diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/PieChartSummaryPanel.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/PieChartSummaryPanel.component.tsx index 4bf05875579..1290979e267 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/PieChartSummaryPanel.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/PieChartSummaryPanel.component.tsx @@ -1,245 +1,255 @@ -import { Card, Col, Row, Typography } from 'antd'; +/* + * Copyright 2024 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 { + CheckCircleOutlined, + FilterOutlined, + SnippetsOutlined, +} from '@ant-design/icons'; +import { Card, Col, Row, Space, Typography } from 'antd'; import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import { Cell, Pie, PieChart } from 'recharts'; -import { PRIMARY_COLOR, WHITE_SMOKE } from '../../../constants/Color.constants'; -import PageHeader from '../../PageHeader/PageHeader.component'; +import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from 'recharts'; +import { + BLUE_2, + GREEN_3, + RED_3, + YELLOW_2, +} from '../../../constants/Color.constants'; +import { formatNumberWithComma } from '../../../utils/CommonUtils'; +import './pie-chart-summary-panel.style.less'; import { SummaryPanelProps } from './SummaryPanel.interface'; -const renderCenterText = (value: number) => ( - - {value.toLocaleString()} - -); - const PieChartSummaryPanel = ({ testSummary, isLoading = false, + showAdditionalSummary = true, }: SummaryPanelProps) => { const { t } = useTranslation(); + const { + total: totalTests = 0, + success: successTests = 0, + failed: failedTests = 0, + aborted: abortedTests = 0, + healthy: healthyDataAssets = 0, + totalDQEntities = 0, + totalEntityCount = 0, + } = testSummary || {}; - const healthyDataAssets = useMemo(() => { - return [ - { - name: 'healthy', - value: testSummary?.healthy, - color: '#12B76A', - }, - { - name: 'total', - value: - (testSummary?.totalDQEntities ?? 0) - (testSummary?.healthy ?? 0), - color: WHITE_SMOKE, - }, - ]; - }, [testSummary?.healthy, testSummary?.totalDQEntities]); + const totalDataAssets = totalDQEntities; + const dataAssetsCoverage = totalDQEntities; - const dataAssetsCoverage = useMemo(() => { + const testData = useMemo(() => { return [ - { - name: 'dataAssetsCoverage', - value: testSummary?.totalDQEntities, - color: PRIMARY_COLOR, - }, - { - name: 'total', - value: - (testSummary?.totalEntityCount ?? 0) - - (testSummary?.totalDQEntities ?? 0), - color: WHITE_SMOKE, - }, + { name: 'Success', value: successTests, color: GREEN_3 }, + { name: 'Aborted', value: abortedTests, color: YELLOW_2 }, + { name: 'Failed', value: failedTests, color: RED_3 }, ]; - }, [testSummary?.totalEntityCount, testSummary?.totalDQEntities]); + }, [successTests, abortedTests, failedTests]); + + const healthyPercentage = useMemo(() => { + if (totalDataAssets === 0) { + return 0; + } + + return Math.round((healthyDataAssets / totalDataAssets) * 100); + }, [healthyDataAssets, totalDataAssets]); + + const coveragePercentage = useMemo(() => { + if (totalEntityCount === 0) { + return 0; + } + + return Math.round((dataAssetsCoverage / totalEntityCount) * 100); + }, [dataAssetsCoverage, totalEntityCount]); + + const healthyData = useMemo(() => { + const unhealthy = totalDataAssets - healthyDataAssets; - const testCaseSummary = useMemo(() => { return [ - { - name: 'success', - data: [ - { - name: 'success', - value: testSummary?.success, - color: '#12B76A', - }, - { - name: 'total', - value: (testSummary?.total ?? 0) - (testSummary?.success ?? 0), - color: WHITE_SMOKE, - }, - ], - innerRadius: 90, - outerRadius: 100, - }, - { - name: 'failed', - data: [ - { - name: 'failed', - value: testSummary?.failed, - color: '#EF4444', - }, - { - name: 'total', - value: (testSummary?.total ?? 0) - (testSummary?.failed ?? 0), - color: WHITE_SMOKE, - }, - ], - innerRadius: 70, - outerRadius: 80, - }, - { - name: 'aborted', - data: [ - { - name: 'aborted', - value: testSummary?.aborted, - color: '#F59E0B', - }, - { - name: 'total', - value: (testSummary?.total ?? 0) - (testSummary?.aborted ?? 0), - color: WHITE_SMOKE, - }, - ], - innerRadius: 50, - outerRadius: 60, - }, + { name: 'Healthy', value: healthyDataAssets, color: GREEN_3 }, + { name: 'Unhealthy', value: unhealthy, color: '#E5E7EB' }, ]; - }, [testSummary]); + }, [healthyDataAssets, totalDataAssets]); + + const coverageData = useMemo(() => { + const uncovered = totalEntityCount - dataAssetsCoverage; + + return [ + { name: 'Covered', value: dataAssetsCoverage, color: BLUE_2 }, + { name: 'Uncovered', value: uncovered, color: '#E5E7EB' }, + ]; + }, [dataAssetsCoverage, totalEntityCount]); return ( - - - - {/* Total Tests */} - - - - {t('label.total-entity', { - entity: t('label.test-case-plural'), - })} - -
- - {testCaseSummary.map((item) => { - return ( - - {item.data?.map((entry) => ( - - ))} - - ); - })} - {renderCenterText(testSummary?.total || 0)} - + + + +
+
+ +
+ + {t('label.total-entity', { + entity: t('label.test-plural'), + })} + + + + {formatNumberWithComma(totalTests)} + +
-
- {testCaseSummary?.map((item) => ( -
- - - {t(item.name)} - - - {item.data[0].value} - + +
+ + {testData.map((item) => ( + +
+ + {item.name} {formatNumberWithComma(item.value)} + + + ))} + + + + + {testData.map((entry, index) => ( + + ))} + + + + 100% + + + +
+
+ + + + {showAdditionalSummary && ( + <> + + +
+
+ +
+ + {t('label.healthy-data-asset-plural')} + + + + {formatNumberWithComma(healthyDataAssets)} + +
- ))} -
-
- - {/* Healthy Data Assets */} - - - - {t('label.healthy-data-asset-plural')} - -
- - - {healthyDataAssets?.map((entry, idx) => ( - - ))} - - {renderCenterText(testSummary?.healthy || 0)} - -
-
- - {/* Data Assets Coverage */} - - - - {t('label.data-asset-plural-coverage')} - -
- - - {dataAssetsCoverage?.map((entry, idx) => ( - - ))} - - {renderCenterText(testSummary?.totalDQEntities || 0)} - -
-
- - - +
+ + + + {healthyData.map((entry, index) => ( + + ))} + + + + {`${healthyPercentage}%`} + + + +
+
+ + + + + +
+
+ +
+ + {t('label.data-asset-plural-coverage')} + + + + {formatNumberWithComma(dataAssetsCoverage)} + +
+
+
+ + + + {coverageData.map((entry, index) => ( + + ))} + + + + {`${coveragePercentage}%`} + + + +
+
+
+ + + )} + ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/pie-chart-summary-panel.style.less b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/pie-chart-summary-panel.style.less new file mode 100644 index 00000000000..81fad4a0054 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/SummaryPannel/pie-chart-summary-panel.style.less @@ -0,0 +1,96 @@ +/* + * Copyright 2024 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 (reference) '../../../styles/variables.less'; + +.pie-chart-summary-panel { + .summary-icon { + font-size: 28px; + + &.total-tests-icon { + color: #3b82f6; + background: #eff6ff; + padding: 8px; + border-radius: 6px; + } + + &.healthy-icon { + color: @green-3; + background: #f0fdf4; + padding: 8px; + border-radius: 6px; + } + + &.coverage-icon { + color: @blue-2; + background: #e0f2fe; + padding: 8px; + border-radius: 6px; + } + } + + .summary-title { + font-size: 16px; + color: @text-color; + font-weight: 600; + margin-bottom: 0; + } + + .summary-value { + font-size: 30px; + font-weight: 600; + color: @text-color; + line-height: 1.2; + margin-top: 8px; + } + + .percentage-change { + font-size: 12px; + font-weight: 500; + + &.positive { + color: @green-3; + } + + &.negative { + color: @red-3; + } + } + + .chart-container { + position: relative; + } + + .title-value-section { + flex-shrink: 0; + margin-right: auto; + } + + .chart-center-text { + font-size: 16px; + font-weight: 600; + fill: @text-color; + } + + .legend-dot { + width: 10px; + height: 10px; + border-radius: 50%; + flex-shrink: 0; + } + + .legend-text { + font-size: 12px; + color: @text-grey-muted; + } +}