Fix #19078 Align the testSuite details page ui with rest of entity details page (#19564)

* Fix #19078 Align the testSuite details page ui with rest of entity details page

* updated testSuite image

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
Shailesh Parmar 2025-01-29 14:04:06 +05:30 committed by GitHub
parent d142edceb7
commit 18d7f4f822
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 140 additions and 65 deletions

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor"><path stroke="currentColor" stroke-width=".35" d="M13.922 3.612 10.977.58A.254.254 0 0 0 10.79.5H3.745C2.78.5 2 1.302 2 2.297v11.406c0 .995.78 1.797 1.745 1.797h8.51c.966 0 1.745-.802 1.745-1.797V3.805a.27.27 0 0 0-.078-.193Zm-2.867-2.15 2.01 2.07H11.6a.55.55 0 0 1-.545-.561V1.463Zm1.2 13.476h-8.51c-.654 0-1.2-.545-1.2-1.235V2.281c0-.674.53-1.236 1.2-1.236h6.764v1.91c0 .625.499 1.123 1.091 1.123h1.854v9.625c0 .69-.545 1.236-1.2 1.236Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 5.152H7.937c-.12 0-.218.111-.218.25 0 .14.097.25.218.25h3.064c.121 0 .218-.11.218-.25 0-.139-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="M5.21 3.083h3.944c.155 0 .28-.128.28-.289a.284.284 0 0 0-.28-.289H5.21a.284.284 0 0 0-.28.29c0 .16.124.288.28.288ZM5.935 4.663l-.9.928-.48-.494a.2.2 0 0 0-.293 0 .215.215 0 0 0 0 .301l.62.639a.2.2 0 0 0 .293 0l1.041-1.072a.215.215 0 0 0 0-.302c-.082-.084-.21-.084-.28 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 7.575H7.937c-.12 0-.218.11-.218.25 0 .139.097.25.218.25h3.064c.121 0 .218-.111.218-.25 0-.14-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="m5.946 7.055-.907.933-.483-.497a.202.202 0 0 0-.294 0 .217.217 0 0 0 0 .303l.624.642a.202.202 0 0 0 .294 0l1.048-1.078a.217.217 0 0 0 0-.303c-.082-.073-.212-.073-.282 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 9.997H7.937c-.12 0-.218.111-.218.25 0 .14.097.25.218.25h3.064c.121 0 .218-.11.218-.25 0-.139-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="m5.935 9.563-.9.928-.48-.494a.2.2 0 0 0-.293 0 .215.215 0 0 0 0 .301l.62.639a.2.2 0 0 0 .293 0l1.041-1.073a.215.215 0 0 0 0-.3c-.07-.085-.199-.085-.28 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 12.42H7.937c-.12 0-.218.111-.218.25s.097.25.218.25h3.064c.121 0 .218-.111.218-.25s-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="M5.624 12.007 4.493 13.14a.2.2 0 0 0 .282.283l1.132-1.132a.2.2 0 0 0-.283-.283Z"/><path stroke="currentColor" stroke-width=".25" d="m5.907 13.139-1.132-1.132a.2.2 0 0 0-.283.283l1.132 1.131a.2.2 0 0 0 .283-.282Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor"><path stroke="currentColor" stroke-width=".35" d="M13.922 3.612 10.977.58A.254.254 0 0 0 10.79.5H3.745C2.78.5 2 1.302 2 2.297v11.406c0 .995.78 1.797 1.745 1.797h8.51c.966 0 1.745-.802 1.745-1.797V3.805a.27.27 0 0 0-.078-.193Zm-2.867-2.15 2.01 2.07H11.6a.55.55 0 0 1-.545-.561V1.463Zm1.2 13.476h-8.51c-.654 0-1.2-.545-1.2-1.235V2.281c0-.674.53-1.236 1.2-1.236h6.764v1.91c0 .625.499 1.123 1.091 1.123h1.854v9.625c0 .69-.545 1.236-1.2 1.236Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 5.152H7.937c-.12 0-.218.111-.218.25 0 .14.097.25.218.25h3.064c.121 0 .218-.11.218-.25 0-.139-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="M5.21 3.083h3.944c.155 0 .28-.128.28-.289a.284.284 0 0 0-.28-.289H5.21a.284.284 0 0 0-.28.29c0 .16.124.288.28.288ZM5.935 4.663l-.9.928-.48-.494a.2.2 0 0 0-.293 0 .215.215 0 0 0 0 .301l.62.639a.2.2 0 0 0 .293 0l1.041-1.072a.215.215 0 0 0 0-.302c-.082-.084-.21-.084-.28 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 7.575H7.937c-.12 0-.218.11-.218.25 0 .139.097.25.218.25h3.064c.121 0 .218-.111.218-.25 0-.14-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="m5.946 7.055-.907.933-.483-.497a.202.202 0 0 0-.294 0 .217.217 0 0 0 0 .303l.624.642a.202.202 0 0 0 .294 0l1.048-1.078a.217.217 0 0 0 0-.303c-.082-.073-.212-.073-.282 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 9.997H7.937c-.12 0-.218.111-.218.25 0 .14.097.25.218.25h3.064c.121 0 .218-.11.218-.25 0-.139-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="m5.935 9.563-.9.928-.48-.494a.2.2 0 0 0-.293 0 .215.215 0 0 0 0 .301l.62.639a.2.2 0 0 0 .293 0l1.041-1.073a.215.215 0 0 0 0-.3c-.07-.085-.199-.085-.28 0Z"/><path stroke="currentColor" stroke-width=".4" d="M11.001 12.42H7.937c-.12 0-.218.111-.218.25s.097.25.218.25h3.064c.121 0 .218-.111.218-.25s-.097-.25-.218-.25Z"/><path stroke="currentColor" stroke-width=".25" d="M5.624 12.007 4.493 13.14a.2.2 0 0 0 .282.283l1.132-1.132a.2.2 0 0 0-.283-.283Z"/><path stroke="currentColor" stroke-width=".25" d="m5.907 13.139-1.132-1.132a.2.2 0 0 0-.283.283l1.132 1.131a.2.2 0 0 0 .283-.282Z"/></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -11,12 +11,14 @@
* limitations under the License.
*/
import { Button, Col, Modal, Row, Space, Tabs } from 'antd';
import { Button, Col, Divider, Modal, Row, Space, Tabs } from 'antd';
import { AxiosError } from 'axios';
import { compare } from 'fast-json-patch';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { ReactComponent as TestSuiteIcon } from '../../assets/svg/icon-test-suite.svg';
import { DomainLabel } from '../../components/common/DomainLabel/DomainLabel.component';
import DescriptionV1 from '../../components/common/EntityDescription/DescriptionV1';
import ManageButton from '../../components/common/EntityPageInfos/ManageButton/ManageButton';
import ErrorPlaceHolder from '../../components/common/ErrorWithPlaceholder/ErrorPlaceHolder';
@ -31,6 +33,8 @@ import { TitleBreadcrumbProps } from '../../components/common/TitleBreadcrumb/Ti
import DataQualityTab from '../../components/Database/Profiler/DataQualityTab/DataQualityTab';
import { AddTestCaseList } from '../../components/DataQuality/AddTestCaseList/AddTestCaseList.component';
import TestSuitePipelineTab from '../../components/DataQuality/TestSuite/TestSuitePipelineTab/TestSuitePipelineTab.component';
import EntityHeaderTitle from '../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component';
import { EntityName } from '../../components/Modals/EntityNameModal/EntityNameModal.interface';
import PageLayoutV1 from '../../components/PageLayoutV1/PageLayoutV1';
import { INITIAL_PAGING_VALUE } from '../../constants/constants';
import { DEFAULT_SORT_ORDER } from '../../constants/profiler.constant';
@ -39,14 +43,14 @@ import {
OperationPermission,
ResourceEntity,
} from '../../context/PermissionProvider/PermissionProvider.interface';
import { ACTION_TYPE, ERROR_PLACEHOLDER_TYPE } from '../../enums/common.enum';
import { ERROR_PLACEHOLDER_TYPE } from '../../enums/common.enum';
import {
EntityTabs,
EntityType,
TabSpecificField,
} from '../../enums/entity.enum';
import { TestCase } from '../../generated/tests/testCase';
import { TestSuite } from '../../generated/tests/testSuite';
import { EntityReference, TestSuite } from '../../generated/tests/testSuite';
import { Include } from '../../generated/type/include';
import { useAuth } from '../../hooks/authHooks';
import { usePaging } from '../../hooks/paging/usePaging';
@ -229,38 +233,35 @@ const TestSuiteDetailsPage = () => {
}
};
const updateTestSuiteData = (updatedTestSuite: TestSuite, type: string) => {
saveAndUpdateTestSuiteData(updatedTestSuite)
.then((res) => {
if (res) {
setTestSuite(res);
} else {
showErrorToast(t('server.unexpected-response'));
}
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t(
`server.entity-${
type === ACTION_TYPE.UPDATE ? 'updating' : 'removing'
}-error`,
{
entity: t('label.owner'),
}
)
);
});
const updateTestSuiteData = async (updatedTestSuite: TestSuite) => {
try {
const res = await saveAndUpdateTestSuiteData(updatedTestSuite);
setTestSuite(res);
} catch (error) {
showErrorToast(error as AxiosError);
}
};
const onUpdateOwner = useCallback(
(updatedOwners: TestSuite['owners']) => {
async (updatedOwners: TestSuite['owners']) => {
const updatedTestSuite = {
...testSuite,
owners: updatedOwners,
} as TestSuite;
updateTestSuiteData(updatedTestSuite, ACTION_TYPE.UPDATE);
await updateTestSuiteData(updatedTestSuite);
},
[testOwners, testSuite]
);
const handleDomainUpdate = useCallback(
async (updateDomain?: EntityReference | EntityReference[]) => {
const updatedTestSuite: TestSuite = {
...testSuite,
domain: updateDomain,
} as TestSuite;
await updateTestSuiteData(updatedTestSuite);
},
[testOwners, testSuite]
);
@ -287,6 +288,28 @@ const TestSuiteDetailsPage = () => {
}
};
const handleDisplayNameChange = async (entityName?: EntityName) => {
try {
if (testSuite) {
const updatedTestSuite = {
...testSuite,
...entityName,
};
const jsonPatch = compare(testSuite, updatedTestSuite);
if (jsonPatch.length && testSuite.id) {
const response = await saveAndUpdateTestSuiteData(
updatedTestSuite as TestSuite
);
setTestSuite(response);
}
}
} catch (error) {
showErrorToast(error as AxiosError);
}
};
const handleTestCasePaging = ({ currentPage }: PagingHandlerParams) => {
if (currentPage) {
handlePageChange(currentPage);
@ -389,47 +412,78 @@ const TestSuiteDetailsPage = () => {
pageTitle={t('label.entity-detail-plural', {
entity: getEntityName(testSuite),
})}>
<Row className="page-container" gutter={[0, 32]}>
<Row className="page-container" gutter={[0, 24]}>
<Col span={24}>
<Space align="center" className="justify-between w-full">
<TitleBreadcrumb
data-testid="test-suite-breadcrumb"
titleLinks={slashedBreadCrumb}
/>
<Space>
{(testSuitePermissions.EditAll ||
testSuitePermissions.EditTests) && (
<Button
data-testid="add-test-case-btn"
type="primary"
onClick={() => setIsTestCaseModalOpen(true)}>
{t('label.add-entity', {
entity: t('label.test-case-plural'),
})}
</Button>
)}
<ManageButton
isRecursiveDelete
afterDeleteAction={afterDeleteAction}
allowSoftDelete={false}
canDelete={isAdminUser}
deleted={testSuite?.deleted}
displayName={getEntityName(testSuite)}
entityId={testSuite?.id}
entityName={testSuite?.fullyQualifiedName as string}
entityType={EntityType.TEST_SUITE}
<TitleBreadcrumb
data-testid="test-suite-breadcrumb"
titleLinks={slashedBreadCrumb}
/>
</Col>
<Col span={24}>
<Row gutter={[16, 16]}>
<Col span={18}>
<EntityHeaderTitle
className="w-max-full-45"
displayName={testSuite?.displayName}
icon={<TestSuiteIcon className="h-9" />}
name={testSuite?.name ?? ''}
serviceName="testSuite"
/>
</Space>
</Space>
</Col>
<Col className="d-flex justify-end" span={6}>
<Space>
{(testSuitePermissions.EditAll ||
testSuitePermissions.EditTests) && (
<Button
data-testid="add-test-case-btn"
type="primary"
onClick={() => setIsTestCaseModalOpen(true)}>
{t('label.add-entity', {
entity: t('label.test-case-plural'),
})}
</Button>
)}
<ManageButton
isRecursiveDelete
afterDeleteAction={afterDeleteAction}
allowSoftDelete={false}
canDelete={isAdminUser}
deleted={testSuite?.deleted}
displayName={getEntityName(testSuite)}
editDisplayNamePermission={
testSuitePermissions.EditAll ||
testSuitePermissions.EditDisplayName
}
entityId={testSuite?.id}
entityName={testSuite?.fullyQualifiedName as string}
entityType={EntityType.TEST_SUITE}
onEditDisplayName={handleDisplayNameChange}
/>
</Space>
</Col>
<div className="w-full m-t-xxs m-b-xs">
<OwnerLabel
hasPermission={isAdminUser}
owners={testOwners}
onUpdate={onUpdateOwner}
/>
</div>
<Col span={24}>
<div className="d-flex flex-wrap gap-2">
<DomainLabel
domain={testSuite?.domain}
entityFqn={testSuite?.fullyQualifiedName ?? ''}
entityId={testSuite?.id ?? ''}
entityType={EntityType.TEST_SUITE}
hasPermission={testSuitePermissions.EditAll}
onUpdate={handleDomainUpdate}
/>
<Divider className="self-center" type="vertical" />
<OwnerLabel
hasPermission={isAdminUser}
owners={testOwners}
onUpdate={onUpdateOwner}
/>
</div>
</Col>
</Row>
</Col>
<Col span={24}>
<DescriptionV1
className="test-suite-description"
description={testSuiteDescription}

View File

@ -102,6 +102,21 @@ jest.mock('../../context/PermissionProvider/PermissionProvider', () => ({
.mockImplementation(() => Promise.resolve(mockEntityPermissions)),
})),
}));
jest.mock(
'../../components/Entity/EntityHeaderTitle/EntityHeaderTitle.component',
() => {
return jest
.fn()
.mockImplementation(() => <div>EntityHeaderTitle.component</div>);
}
);
jest.mock('../../components/common/DomainLabel/DomainLabel.component', () => {
return {
DomainLabel: jest
.fn()
.mockImplementation(() => <div>DomainLabel.component</div>),
};
});
describe('TestSuiteDetailsPage component', () => {
it('component should render', async () => {
@ -110,6 +125,12 @@ describe('TestSuiteDetailsPage component', () => {
expect(
await screen.findByText('TitleBreadcrumb.component')
).toBeInTheDocument();
expect(
await screen.findByText('EntityHeaderTitle.component')
).toBeInTheDocument();
expect(
await screen.findByText('DomainLabel.component')
).toBeInTheDocument();
expect(
await screen.findByText('ManageButton.component')
).toBeInTheDocument();