Fixed: Fixed service and services page issue and other miner fixes (#5669)

* Fixed service and services page issue and other miner fixes

* fixed failing unit test
This commit is contained in:
Shailesh Parmar 2022-06-27 22:32:24 +05:30 committed by GitHub
parent 3a1dfbdbcb
commit 9b588c998a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 116 additions and 74 deletions

View File

@ -1280,60 +1280,56 @@ const Entitylineage: FunctionComponent<EntityLineageProp> = ({
} }
}, [entityLineage]); }, [entityLineage]);
if (isLoading) { if (isLoading || (nodes.length === 0 && !deleted)) {
return <Loader />; return <Loader />;
} }
return deleted ? ( return deleted ? (
getDeletedLineagePlaceholder() getDeletedLineagePlaceholder()
) : ( ) : (
<Fragment> <div
<div className={classNames('tw-relative tw-h-full tw--ml-4 tw--mr-7 tw--mt-4')}
className={classNames( data-testid="lineage-container">
'tw-relative tw-h-full tw--ml-4 tw--mr-7 tw--mt-4' <div className="tw-w-full tw-h-full" ref={reactFlowWrapper}>
)} <ReactFlowProvider>
data-testid="lineage-container"> <ReactFlow
<div className="tw-w-full tw-h-full" ref={reactFlowWrapper}> data-testid="react-flow-component"
<ReactFlowProvider> edgeTypes={{ buttonedge: CustomEdge }}
<ReactFlow edges={edges}
data-testid="react-flow-component" maxZoom={2}
edgeTypes={{ buttonedge: CustomEdge }} minZoom={0.5}
edges={edges} nodeTypes={nodeTypes}
maxZoom={2} nodes={nodes}
minZoom={0.5} nodesConnectable={isEditMode}
nodeTypes={nodeTypes} selectNodesOnDrag={false}
nodes={nodes} zoomOnDoubleClick={false}
nodesConnectable={isEditMode} zoomOnScroll={false}
selectNodesOnDrag={false} onConnect={onConnect}
zoomOnDoubleClick={false} onDragOver={onDragOver}
zoomOnScroll={false} onDrop={onDrop}
onConnect={onConnect} onEdgesChange={onEdgesChange}
onDragOver={onDragOver} onInit={(reactFlowInstance: ReactFlowInstance) => {
onDrop={onDrop} onLoad(reactFlowInstance, nodes.length);
onEdgesChange={onEdgesChange} setReactFlowInstance(reactFlowInstance);
onInit={(reactFlowInstance: ReactFlowInstance) => { }}
onLoad(reactFlowInstance, nodes.length); onNodeClick={(_e, node) => onNodeClick(node)}
setReactFlowInstance(reactFlowInstance); onNodeContextMenu={onNodeContextMenu}
}} onNodeDrag={dragHandle}
onNodeClick={(_e, node) => onNodeClick(node)} onNodeDragStart={dragHandle}
onNodeContextMenu={onNodeContextMenu} onNodeDragStop={dragHandle}
onNodeDrag={dragHandle} onNodeMouseEnter={onNodeMouseEnter}
onNodeDragStart={dragHandle} onNodeMouseLeave={onNodeMouseLeave}
onNodeDragStop={dragHandle} onNodeMouseMove={onNodeMouseMove}
onNodeMouseEnter={onNodeMouseEnter} onNodesChange={onNodesChange}>
onNodeMouseLeave={onNodeMouseLeave} {getCustomControlElements()}
onNodeMouseMove={onNodeMouseMove} {getGraphBackGround()}
onNodesChange={onNodesChange}> </ReactFlow>
{getCustomControlElements()} </ReactFlowProvider>
{getGraphBackGround()}
</ReactFlow>
</ReactFlowProvider>
</div>
{getEntityDrawer()}
<EntityLineageSidebar newAddedNode={newAddedNode} show={isEditMode} />
{getConfirmationModal()}
</div> </div>
</Fragment> {getEntityDrawer()}
<EntityLineageSidebar newAddedNode={newAddedNode} show={isEditMode} />
{getConfirmationModal()}
</div>
); );
}; };

View File

@ -127,6 +127,29 @@ const mockEntityLineageProp = {
entityLineageHandler: jest.fn(), entityLineageHandler: jest.fn(),
}; };
const mockFlowData = {
node: [
{
id: 'a4b21449-b03b-4527-b482-148f52f92ff2',
sourcePosition: 'right',
targetPosition: 'left',
type: 'default',
className: 'leaf-node core',
data: {
label: 'dim_address etl',
isEditMode: false,
columns: {},
isExpanded: false,
},
position: {
x: 0,
y: 0,
},
},
],
edge: [],
};
jest.mock('../../utils/EntityLineageUtils', () => ({ jest.mock('../../utils/EntityLineageUtils', () => ({
dragHandle: jest.fn(), dragHandle: jest.fn(),
getDataLabel: jest getDataLabel: jest
@ -138,8 +161,8 @@ jest.mock('../../utils/EntityLineageUtils', () => ({
<p>Lineage data is not available for deleted entities.</p> <p>Lineage data is not available for deleted entities.</p>
), ),
getHeaderLabel: jest.fn().mockReturnValue(<p>Header label</p>), getHeaderLabel: jest.fn().mockReturnValue(<p>Header label</p>),
getLayoutedElementsV1: jest.fn().mockReturnValue([]), getLayoutedElementsV1: jest.fn().mockImplementation(() => mockFlowData),
getLineageDataV1: jest.fn().mockReturnValue([]), getLineageDataV1: jest.fn().mockImplementation(() => mockFlowData),
getModalBodyText: jest.fn(), getModalBodyText: jest.fn(),
onLoad: jest.fn(), onLoad: jest.fn(),
onNodeContextMenu: jest.fn(), onNodeContextMenu: jest.fn(),

View File

@ -66,6 +66,10 @@ const ServiceConfig = ({
}); });
}; };
const onCancel = () => {
history.goBack();
};
const getDynamicFields = () => { const getDynamicFields = () => {
return ( return (
<ConnectionConfigForm <ConnectionConfigForm
@ -79,6 +83,7 @@ const ServiceConfig = ({
serviceCategory={serviceCategory} serviceCategory={serviceCategory}
serviceType={serviceType} serviceType={serviceType}
status={status} status={status}
onCancel={onCancel}
onSave={handleOnSaveClick} onSave={handleOnSaveClick}
/> />
); );

View File

@ -606,9 +606,7 @@ const TeamDetails = ({
blurWithBodyBG blurWithBodyBG
description={currentTeam?.description || ''} description={currentTeam?.description || ''}
entityName={currentTeam?.displayName ?? currentTeam?.name} entityName={currentTeam?.displayName ?? currentTeam?.name}
hasEditAccess={isActionAllowed( hasEditAccess={isOwner()}
userPermissions[Operation.UpdateDescription]
)}
isEdit={isDescriptionEditable} isEdit={isDescriptionEditable}
onCancel={() => descriptionHandler(false)} onCancel={() => descriptionHandler(false)}
onDescriptionEdit={() => descriptionHandler(true)} onDescriptionEdit={() => descriptionHandler(true)}

View File

@ -17,6 +17,7 @@ import { EntityFieldThreads } from 'Models';
import React, { FC, Fragment } from 'react'; import React, { FC, Fragment } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { useAuthContext } from '../../../authentication/auth-provider/AuthProvider'; import { useAuthContext } from '../../../authentication/auth-provider/AuthProvider';
import { TITLE_FOR_UPDATE_DESCRIPTION } from '../../../constants/constants';
import { EntityType } from '../../../enums/entity.enum'; import { EntityType } from '../../../enums/entity.enum';
import { Operation } from '../../../generated/entity/policies/accessControl/rule'; import { Operation } from '../../../generated/entity/policies/accessControl/rule';
import { useAuth } from '../../../hooks/authHooks'; import { useAuth } from '../../../hooks/authHooks';
@ -28,6 +29,7 @@ import {
TASK_ENTITIES, TASK_ENTITIES,
} from '../../../utils/TasksUtils'; } from '../../../utils/TasksUtils';
import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
import NonAdminAction from '../non-admin-action/NonAdminAction';
import PopOver from '../popover/PopOver'; import PopOver from '../popover/PopOver';
import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer';
import { DescriptionProps } from './Description.interface'; import { DescriptionProps } from './Description.interface';
@ -68,16 +70,22 @@ const Description: FC<DescriptionProps> = ({
); );
}; };
const checkPermission = () => {
if (!isAuthDisabled && !isAdminUser) {
if (!isUndefined(hasEditAccess)) {
return Boolean(hasEditAccess);
} else {
return userPermissions[Operation.UpdateDescription];
}
}
return true;
};
const handleUpdate = () => { const handleUpdate = () => {
const check = if (checkPermission()) {
isAdminUser ||
hasEditAccess ||
isAuthDisabled ||
userPermissions[Operation.UpdateDescription] ||
!TASK_ENTITIES.includes(entityType as EntityType);
if (check) {
onDescriptionEdit && onDescriptionEdit(); onDescriptionEdit && onDescriptionEdit();
} else { } else if (TASK_ENTITIES.includes(entityType as EntityType)) {
handleUpdateDescription(); handleUpdateDescription();
} }
}; };
@ -151,12 +159,19 @@ const Description: FC<DescriptionProps> = ({
'tw-w-5 tw-min-w-max tw-flex', 'tw-w-5 tw-min-w-max tw-flex',
description?.trim() ? 'tw-pl-1' : '' description?.trim() ? 'tw-pl-1' : ''
)}> )}>
<button <NonAdminAction
className="focus:tw-outline-none tw-self-baseline" isOwner={
data-testid="edit-description" checkPermission() ||
onClick={handleUpdate}> TASK_ENTITIES.includes(entityType as EntityType)
<SVGIcons alt="edit" icon="icon-edit" title="Edit" width="16px" /> }
</button> title={TITLE_FOR_UPDATE_DESCRIPTION}>
<button
className="focus:tw-outline-none tw-self-baseline"
data-testid="edit-description"
onClick={handleUpdate}>
<SVGIcons alt="edit" icon="icon-edit" title="Edit" width="16px" />
</button>
</NonAdminAction>
<RequestDescriptionEl descriptionThread={thread} /> <RequestDescriptionEl descriptionThread={thread} />
<DescriptionThreadEl descriptionThread={thread} /> <DescriptionThreadEl descriptionThread={thread} />

View File

@ -83,7 +83,7 @@ const TitleBreadcrumb: FunctionComponent<TitleBreadcrumbProps> = ({
className={classes} className={classes}
style={{ style={{
maxWidth, maxWidth,
fontSize: '14px', fontSize: '16px',
}} }}
to={link.url}> to={link.url}>
{link.name} {link.name}

View File

@ -433,6 +433,9 @@ export const TITLE_FOR_NON_ADMIN_ACTION =
export const TITLE_FOR_UPDATE_OWNER = export const TITLE_FOR_UPDATE_OWNER =
'You do not have permissions to update the owner.'; 'You do not have permissions to update the owner.';
export const TITLE_FOR_UPDATE_DESCRIPTION =
'You do not have permissions to update the description.';
export const configOptions = { export const configOptions = {
headers: { 'Content-type': 'application/json-patch+json' }, headers: { 'Content-type': 'application/json-patch+json' },
}; };

View File

@ -175,6 +175,7 @@ const ServicePage: FunctionComponent = () => {
}, },
isProtected: !isAdminUser && !isAuthDisabled, isProtected: !isAdminUser && !isAuthDisabled,
isHidden: !isAdminUser && !isAuthDisabled,
position: 3, position: 3,
}, },
{ {
@ -925,6 +926,7 @@ const ServicePage: FunctionComponent = () => {
entityFqn={serviceFQN} entityFqn={serviceFQN}
entityName={serviceFQN} entityName={serviceFQN}
entityType={serviceCategory.slice(0, -1)} entityType={serviceCategory.slice(0, -1)}
hasEditAccess={isAdminUser || isAuthDisabled}
isEdit={isEdit} isEdit={isEdit}
onCancel={onCancel} onCancel={onCancel}
onDescriptionEdit={onDescriptionEdit} onDescriptionEdit={onDescriptionEdit}
@ -1033,7 +1035,7 @@ const ServicePage: FunctionComponent = () => {
</Button> </Button>
</div> </div>
<ServiceConnectionDetails <ServiceConnectionDetails
connectionDetails={connectionDetails as ConfigData} connectionDetails={connectionDetails || {}}
serviceCategory={serviceCategory} serviceCategory={serviceCategory}
serviceFQN={serviceDetails?.serviceType || ''} serviceFQN={serviceDetails?.serviceType || ''}
/> />

View File

@ -307,7 +307,7 @@ const ServicesPage = () => {
<span <span
className=" tw-ml-1 tw-font-normal tw-text-grey-body" className=" tw-ml-1 tw-font-normal tw-text-grey-body"
data-testid="dashboard-url"> data-testid="dashboard-url">
{getDashboardURL(dashboardService.connection.config)} {getDashboardURL(dashboardService.connection?.config)}
</span> </span>
</div> </div>
</> </>
@ -323,7 +323,7 @@ const ServicesPage = () => {
<span <span
className=" tw-ml-1 tw-font-normal tw-text-grey-body" className=" tw-ml-1 tw-font-normal tw-text-grey-body"
data-testid="pipeline-url"> data-testid="pipeline-url">
{pipelineService.connection.config?.hostPort} {pipelineService.connection?.config?.hostPort || '--'}
</span> </span>
</div> </div>
</> </>
@ -340,7 +340,7 @@ const ServicesPage = () => {
<span <span
className=" tw-ml-1 tw-font-normal tw-text-grey-body" className=" tw-ml-1 tw-font-normal tw-text-grey-body"
data-testid="pipeline-url"> data-testid="pipeline-url">
{mlmodel.connection.config?.registryUri} {mlmodel.connection?.config?.registryUri || '--'}
</span> </span>
</div> </div>
<div className="tw-mb-1 tw-truncate" data-testid="additional-field"> <div className="tw-mb-1 tw-truncate" data-testid="additional-field">
@ -348,7 +348,7 @@ const ServicesPage = () => {
<span <span
className=" tw-ml-1 tw-font-normal tw-text-grey-body" className=" tw-ml-1 tw-font-normal tw-text-grey-body"
data-testid="pipeline-url"> data-testid="pipeline-url">
{mlmodel.connection.config?.trackingUri} {mlmodel.connection?.config?.trackingUri || '--'}
</span> </span>
</div> </div>
</> </>
@ -508,7 +508,7 @@ const ServicesPage = () => {
<p className="tw-text-lg tw-text-center"> <p className="tw-text-lg tw-text-center">
{noServicesText(searchText)} {noServicesText(searchText)}
</p> </p>
<p className="tw-text-lg tw-text-center"> <div className="tw-text-lg tw-text-center">
<NonAdminAction <NonAdminAction
position="bottom" position="bottom"
title={TITLE_FOR_NON_ADMIN_ACTION}> title={TITLE_FOR_NON_ADMIN_ACTION}>
@ -522,7 +522,7 @@ const ServicesPage = () => {
</Button> </Button>
</NonAdminAction>{' '} </NonAdminAction>{' '}
to add new {servicesDisplayName[serviceName]} to add new {servicesDisplayName[serviceName]}
</p> </div>
</div> </div>
</div> </div>
); );