feat: Remove SummaryPanel component and tests; replace with SummaryCardV1 in QualityTab

This commit is contained in:
Shailesh Parmar 2025-10-04 11:01:12 +05:30
parent f8df6c38c6
commit f2b8f7786c
4 changed files with 50 additions and 207 deletions

View File

@ -1,122 +0,0 @@
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Col, Row } from 'antd';
import { FC, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { ReactComponent as TestCaseAbortedIcon } from '../../../assets/svg/aborted-status.svg';
import { ReactComponent as TestCaseIcon } from '../../../assets/svg/all-activity-v2.svg';
import { ReactComponent as TestCaseFailedIcon } from '../../../assets/svg/failed-status.svg';
import { ReactComponent as DataAssetsCoverageIcon } from '../../../assets/svg/ic-data-assets-coverage.svg';
import { ReactComponent as HealthCheckIcon } from '../../../assets/svg/ic-green-heart-border.svg';
import { ReactComponent as TestCaseSuccessIcon } from '../../../assets/svg/success-colored.svg';
import { SummaryCard } from '../../../components/common/SummaryCard/SummaryCard.component';
import { PRIMARY_COLOR, YELLOW_2 } from '../../../constants/Color.constants';
import { SummaryPanelProps } from './SummaryPanel.interface';
export const SummaryPanel: FC<SummaryPanelProps> = ({
testSummary: summary,
isLoading = false,
showAdditionalSummary = false,
}: SummaryPanelProps) => {
const { t } = useTranslation();
const spanValue = useMemo(
() => (showAdditionalSummary ? 8 : 6),
[showAdditionalSummary]
);
return (
<Row wrap gutter={[16, 16]}>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-primary"
className="h-full"
isLoading={isLoading}
showProgressBar={false}
title={t('label.total-entity', { entity: t('label.test-plural') })}
titleIcon={
<TestCaseIcon color={PRIMARY_COLOR} height={16} width={16} />
}
total={summary?.total ?? 0}
value={summary?.total ?? 0}
/>
</Col>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-success"
isLoading={isLoading}
title={t('label.success')}
titleIcon={<TestCaseSuccessIcon height={16} width={16} />}
total={summary?.total ?? 0}
type="success"
value={summary?.success ?? 0}
/>
</Col>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-aborted"
isLoading={isLoading}
title={t('label.aborted')}
titleIcon={
<TestCaseAbortedIcon color={YELLOW_2} height={16} width={16} />
}
total={summary?.total ?? 0}
type="aborted"
value={summary?.aborted ?? 0}
/>
</Col>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-failed"
isLoading={isLoading}
title={t('label.failed')}
titleIcon={<TestCaseFailedIcon height={16} width={16} />}
total={summary?.total ?? 0}
type="failed"
value={summary?.failed ?? 0}
/>
</Col>
{showAdditionalSummary && (
<>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-success"
isLoading={isLoading}
title={t('label.healthy-data-asset-plural')}
titleIcon={<HealthCheckIcon height={16} width={16} />}
total={summary?.totalDQEntities ?? 0}
type="success"
value={summary?.healthy ?? 0}
/>
</Col>
<Col span={spanValue}>
<SummaryCard
inverseLabel
cardBackgroundClass="bg-primary"
isLoading={isLoading}
title={t('label.data-asset-plural-coverage')}
titleIcon={<DataAssetsCoverageIcon height={16} width={16} />}
total={summary?.totalEntityCount ?? 0}
type="acknowledged"
value={summary?.totalDQEntities ?? 0}
/>
</Col>
</>
)}
</Row>
);
};

View File

@ -1,81 +0,0 @@
/*
* Copyright 2023 Collate.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { render, screen } from '@testing-library/react';
import { getTestCaseExecutionSummary } from '../../../rest/testAPI';
import { SummaryPanel } from './SummaryPanel.component';
const testCasePermission = {
Create: true,
Delete: true,
ViewAll: true,
EditAll: true,
EditDescription: true,
EditDisplayName: true,
EditCustomFields: true,
};
const mockSummary = {
total: 10,
success: 7,
aborted: 2,
failed: 1,
};
jest.mock('../../common/SummaryCard/SummaryCard.component', () => {
return {
SummaryCard: jest
.fn()
.mockImplementation(() => <div>SummaryCard.component</div>),
};
});
jest.mock('../../../rest/testAPI', () => {
return {
getTestCaseExecutionSummary: jest
.fn()
.mockImplementation(() => Promise.resolve(mockSummary)),
};
});
describe('SummaryPanel component', () => {
it('component should render', async () => {
render(<SummaryPanel testSummary={mockSummary} />);
const summaryCards = await screen.findAllByText('SummaryCard.component');
expect(summaryCards).toHaveLength(4);
});
it('Show additional summary card if showAdditionalSummary is true', async () => {
render(<SummaryPanel showAdditionalSummary testSummary={mockSummary} />);
const summaryCards = await screen.findAllByText('SummaryCard.component');
expect(summaryCards).toHaveLength(6);
});
it('should not call getTestCaseExecutionSummary API, if testSummary data is provided', async () => {
const mockGetTestCaseExecutionSummary =
getTestCaseExecutionSummary as jest.Mock;
render(<SummaryPanel testSummary={mockSummary} />);
expect(mockGetTestCaseExecutionSummary).not.toHaveBeenCalled();
});
it('should not call getTestCaseExecutionSummary API, if there is no permission', async () => {
const mockGetTestCaseExecutionSummary =
getTestCaseExecutionSummary as jest.Mock;
testCasePermission.ViewAll = false;
render(<SummaryPanel testSummary={mockSummary} />);
expect(mockGetTestCaseExecutionSummary).not.toHaveBeenCalled();
});
});

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { DownOutlined } from '@ant-design/icons'; import { DownOutlined } from '@ant-design/icons';
import { Grid } from '@mui/material';
import { import {
Button, Button,
Col, Col,
@ -26,7 +27,11 @@ import { isEmpty } from 'lodash';
import { useEffect, useMemo, useState } from 'react'; import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { ReactComponent as AddItemIcon } from '../../../../../assets/svg/add-item-icon.svg';
import { ReactComponent as SettingIcon } from '../../../../../assets/svg/ic-settings-primery.svg'; import { ReactComponent as SettingIcon } from '../../../../../assets/svg/ic-settings-primery.svg';
import { ReactComponent as RedCircleIcon } from '../../../../../assets/svg/red-circle-with-dash.svg';
import { ReactComponent as SuccessTicketIcon } from '../../../../../assets/svg/success-ticket-with-check.svg';
import { ReactComponent as YellowCalendarIcon } from '../../../../../assets/svg/yellow-calendar.icon.svg';
import { INITIAL_PAGING_VALUE } from '../../../../../constants/constants'; import { INITIAL_PAGING_VALUE } from '../../../../../constants/constants';
import { PAGE_HEADERS } from '../../../../../constants/PageHeaders.constant'; import { PAGE_HEADERS } from '../../../../../constants/PageHeaders.constant';
import { import {
@ -56,9 +61,9 @@ import ErrorPlaceHolder from '../../../../common/ErrorWithPlaceholder/ErrorPlace
import NextPrevious from '../../../../common/NextPrevious/NextPrevious'; import NextPrevious from '../../../../common/NextPrevious/NextPrevious';
import { NextPreviousProps } from '../../../../common/NextPrevious/NextPrevious.interface'; import { NextPreviousProps } from '../../../../common/NextPrevious/NextPrevious.interface';
import Searchbar from '../../../../common/SearchBarComponent/SearchBar.component'; import Searchbar from '../../../../common/SearchBarComponent/SearchBar.component';
import SummaryCardV1 from '../../../../common/SummaryCard/SummaryCardV1';
import TabsLabel from '../../../../common/TabsLabel/TabsLabel.component'; import TabsLabel from '../../../../common/TabsLabel/TabsLabel.component';
import { TestLevel } from '../../../../DataQuality/AddDataQualityTest/components/TestCaseFormV1.interface'; import { TestLevel } from '../../../../DataQuality/AddDataQualityTest/components/TestCaseFormV1.interface';
import { SummaryPanel } from '../../../../DataQuality/SummaryPannel/SummaryPanel.component';
import TestSuitePipelineTab from '../../../../DataQuality/TestSuite/TestSuitePipelineTab/TestSuitePipelineTab.component'; import TestSuitePipelineTab from '../../../../DataQuality/TestSuite/TestSuitePipelineTab/TestSuitePipelineTab.component';
import PageHeader from '../../../../PageHeader/PageHeader.component'; import PageHeader from '../../../../PageHeader/PageHeader.component';
import DataQualityTab from '../../DataQualityTab/DataQualityTab'; import DataQualityTab from '../../DataQualityTab/DataQualityTab';
@ -115,6 +120,37 @@ export const QualityTab = () => {
const [ingestionPipelineCount, setIngestionPipelineCount] = const [ingestionPipelineCount, setIngestionPipelineCount] =
useState<number>(0); useState<number>(0);
const totalTestCaseSummary = useMemo(() => {
const tests = testCaseSummary?.total ?? INITIAL_TEST_SUMMARY;
return [
{
title: t('label.test-plural-type', { type: t('label.total') }),
key: 'total-tests',
value: tests.total,
icon: AddItemIcon,
},
{
title: t('label.test-plural-type', { type: t('label.successful') }),
key: 'successful-tests',
value: tests.success,
icon: SuccessTicketIcon,
},
{
title: t('label.test-plural-type', { type: t('label.failed') }),
key: 'failed-tests',
value: tests.failed,
icon: RedCircleIcon,
},
{
title: t('label.test-plural-type', { type: t('label.aborted') }),
key: 'aborted-tests',
value: tests.aborted,
icon: YellowCalendarIcon,
},
];
}, [testCaseSummary]);
const fetchIngestionPipelineCount = async () => { const fetchIngestionPipelineCount = async () => {
try { try {
const { paging: ingestionPipelinePaging } = await getIngestionPipelines({ const { paging: ingestionPipelinePaging } = await getIngestionPipelines({
@ -393,9 +429,18 @@ export const QualityTab = () => {
</Row> </Row>
</Col> </Col>
<Col span={24}> <Col span={24}>
<SummaryPanel <Grid container spacing={5}>
testSummary={testCaseSummary?.total ?? INITIAL_TEST_SUMMARY} {totalTestCaseSummary?.map((summary) => (
<Grid key={summary.title} size="grow">
<SummaryCardV1
icon={summary.icon}
isLoading={isTestsLoading}
title={summary.title}
value={summary.value}
/> />
</Grid>
))}
</Grid>
</Col> </Col>
<Col span={24}> <Col span={24}>
<Tabs className="tabs-new" items={tabs} onChange={handleTabChange} /> <Tabs className="tabs-new" items={tabs} onChange={handleTabChange} />

View File

@ -1694,6 +1694,7 @@
"test-email": "Test Email", "test-email": "Test Email",
"test-email-connection": "Test Email Connection", "test-email-connection": "Test Email Connection",
"test-entity": "Test {{entity}}", "test-entity": "Test {{entity}}",
"test-plural-type": "{{type}} Tests",
"test-level-lowercase": "test level", "test-level-lowercase": "test level",
"test-plural": "Tests", "test-plural": "Tests",
"test-suite": "Test Suite", "test-suite": "Test Suite",