diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-alert-red.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-alert-red.svg new file mode 100644 index 00000000000..df076706b0f --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/ic-alert-red.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx index 8ebf9c75d90..3ae32173851 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetsHeader/DataAssetsHeader.component.tsx @@ -157,6 +157,7 @@ export const DataAssetsHeader = ({ onUpdateRetentionPeriod, extraDropdownContent, onMetricUpdate, + badge, }: DataAssetsHeaderProps) => { const { currentUser } = useApplicationStore(); const USER_ID = currentUser?.id ?? ''; @@ -368,6 +369,7 @@ export const DataAssetsHeader = ({ void; afterDeleteAction?: (isSoftDelete?: boolean, version?: number) => void; onTierUpdate: (tier?: Tag) => Promise; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.component.tsx new file mode 100644 index 00000000000..4462254b184 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.component.tsx @@ -0,0 +1,55 @@ +/* + * 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 { Card, Typography } from 'antd'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { DataStatisticWidgetProps } from '../../DataQuality.interface'; +import './data-statistic-widget.less'; + +const DataStatisticWidget = ({ + name, + title, + icon, + dataLabel, + countValue, + redirectPath, + linkLabel, + isLoading, +}: DataStatisticWidgetProps) => { + const Icon = icon; + + return ( + + + {title} + + +
+ + + {`${countValue} ${dataLabel}`} + +
+ + {linkLabel} + +
+ ); +}; + +export default DataStatisticWidget; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.test.tsx new file mode 100644 index 00000000000..33c98681c9d --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/DataStatisticWidget.test.tsx @@ -0,0 +1,59 @@ +/* + * 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 '@testing-library/jest-dom/extend-expect'; +import { render, screen } from '@testing-library/react'; +import React from 'react'; +import { MemoryRouter } from 'react-router-dom'; +import { DataStatisticWidgetProps } from '../../DataQuality.interface'; +import DataStatisticWidget from './DataStatisticWidget.component'; + +const mockProps: DataStatisticWidgetProps = { + name: 'test-widget', + title: 'Test Title', + icon: () => , + dataLabel: 'items', + countValue: 10, + redirectPath: '/test-path', + linkLabel: 'View Details', + isLoading: false, +}; + +describe('DataStatisticWidget component', () => { + it('should render the widget with provided props', () => { + render( + + + + ); + + expect( + screen.getByTestId('test-widget-data-statistic-widget') + ).toBeInTheDocument(); + expect(screen.getByText('Test Title')).toBeInTheDocument(); + expect(screen.getByTestId('test-icon')).toBeInTheDocument(); + expect(screen.getByText('10 items')).toBeInTheDocument(); + expect(screen.getByText('View Details')).toBeInTheDocument(); + }); + + it('should show loading state when isLoading is true', () => { + render( + + + + ); + + expect(screen.getByTestId('test-widget-data-statistic-widget')).toHaveClass( + 'ant-card-loading' + ); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/data-statistic-widget.less b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/data-statistic-widget.less new file mode 100644 index 00000000000..3a8ddf4d3c8 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/DataStatisticWidget/data-statistic-widget.less @@ -0,0 +1,19 @@ +/* + * 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) url('../../../../styles/variables.less'); + +.data-statistic-widget-title { + div&.ant-typography { + margin-bottom: @margin-xlg; + } +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/IncidentTimeChartWidget/IncidentTimeChartWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/IncidentTimeChartWidget/IncidentTimeChartWidget.component.tsx index 9a8e5b4a2ed..6c5e0b1d034 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/IncidentTimeChartWidget/IncidentTimeChartWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/IncidentTimeChartWidget/IncidentTimeChartWidget.component.tsx @@ -24,6 +24,7 @@ const IncidentTimeChartWidget = ({ name, title, chartFilter, + height, }: IncidentTimeChartWidgetProps) => { const [chartData, setChartData] = useState([]); const [isChartLoading, setIsChartLoading] = useState(true); @@ -86,6 +87,7 @@ const IncidentTimeChartWidget = ({ diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/TestCaseStatusAreaChartWidget/TestCaseStatusAreaChartWidget.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/TestCaseStatusAreaChartWidget/TestCaseStatusAreaChartWidget.component.tsx index 9cfe827a42c..d867bcfd8c2 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/TestCaseStatusAreaChartWidget/TestCaseStatusAreaChartWidget.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/ChartWidgets/TestCaseStatusAreaChartWidget/TestCaseStatusAreaChartWidget.component.tsx @@ -26,6 +26,7 @@ const TestCaseStatusAreaChartWidget = ({ title, chartColorScheme, chartFilter, + height, }: TestCaseStatusAreaChartWidgetProps) => { const [chartData, setChartData] = useState([]); const [isChartLoading, setIsChartLoading] = useState(true); @@ -82,6 +83,7 @@ const TestCaseStatusAreaChartWidget = ({ diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/DataQuality.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/DataQuality.interface.ts index 245efa20aa5..48cc16cae37 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/DataQuality.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataQuality/DataQuality.interface.ts @@ -55,6 +55,7 @@ export interface IncidentTimeChartWidgetProps { incidentMetricType: IncidentTimeMetricsType; name: string; chartFilter?: DataQualityDashboardChartFilters; + height?: number; } export interface TestCaseStatusAreaChartWidgetProps { title: string; @@ -62,8 +63,20 @@ export interface TestCaseStatusAreaChartWidgetProps { name: string; chartColorScheme?: AreaChartColorScheme; chartFilter?: DataQualityDashboardChartFilters; + height?: number; } export interface PieChartWidgetCommonProps { chartFilter?: DataQualityDashboardChartFilters; } + +export interface DataStatisticWidgetProps { + name: string; + title: string; + icon: SvgComponent; + dataLabel: string; + countValue: number; + redirectPath: string; + linkLabel: string; + isLoading?: boolean; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json index bb17d03cb05..37e3deae0cd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/de-de.json @@ -150,6 +150,7 @@ "chart-entity": "{{entity}} Diagramm", "chart-plural": "Diagramme", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Status überprüfen", "children": "Kinder", "children-lowercase": "kinder", @@ -619,6 +620,7 @@ "invalid-condition": "Ungültige Bedingung", "invalid-name": "Ungültiger Name", "is-ready-for-preview": "ist bereit zur Vorschau", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items selected", "january": "Januar", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json index 291173c9f0f..f896a0bcfa9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/en-us.json @@ -150,6 +150,7 @@ "chart-entity": "Chart {{entity}}", "chart-plural": "Charts", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Check status", "children": "Children", "children-lowercase": "children", @@ -619,6 +620,7 @@ "invalid-condition": "Invalid condition", "invalid-name": "Invalid Name", "is-ready-for-preview": "is ready for preview", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items selected", "january": "January", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json index a2289b7d94f..d99cd06d7b4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/es-es.json @@ -150,6 +150,7 @@ "chart-entity": "Gráfico {{entity}}", "chart-plural": "Gráficos", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Verificar estado", "children": "Hijos", "children-lowercase": "hijos", @@ -619,6 +620,7 @@ "invalid-condition": "Condición inválida", "invalid-name": "Nombre inválido", "is-ready-for-preview": "está listo para previsualización", + "issue": "Issue", "issue-plural": "Problemas", "items-selected-lowercase": "elementos seleccionados", "january": "Enero", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json index 8e49dd06067..569a975482e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/fr-fr.json @@ -150,6 +150,7 @@ "chart-entity": "Graphique {{entity}}", "chart-plural": "Graphiques", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Vérifier le Statut", "children": "Enfants", "children-lowercase": "enfants", @@ -619,6 +620,7 @@ "invalid-condition": "Condition Invalide", "invalid-name": "Nom Invalide", "is-ready-for-preview": "est prêt à être prévisualisé", + "issue": "Issue", "issue-plural": "Problèmes", "items-selected-lowercase": "items selected", "january": "Janvier", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json index 2bde5e02338..591a91794f6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/gl-es.json @@ -150,6 +150,7 @@ "chart-entity": "Gráfico {{entity}}", "chart-plural": "Gráficos", "chart-type": "Tipo de gráfico", + "check-data-quality-failure": "Check data quality failure", "check-status": "Verificar estado", "children": "Fillos", "children-lowercase": "fillos", @@ -619,6 +620,7 @@ "invalid-condition": "Condición non válida", "invalid-name": "Nome non válido", "is-ready-for-preview": "está listo para previsualización", + "issue": "Issue", "issue-plural": "Problemas", "items-selected-lowercase": "elementos seleccionados", "january": "Xaneiro", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json index d4c3071c32f..fb8b83293de 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/he-he.json @@ -150,6 +150,7 @@ "chart-entity": "תרשים {{entity}}", "chart-plural": "תרשימים", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "בדוק סטטוס", "children": "ילדים", "children-lowercase": "ילדים", @@ -619,6 +620,7 @@ "invalid-condition": "תנאי לא תקין", "invalid-name": "שם לא תקין", "is-ready-for-preview": "מוכן לתצוגה מקדימה", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items selected", "january": "ינואר", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json index fbffd1f0966..da1057694d4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ja-jp.json @@ -150,6 +150,7 @@ "chart-entity": "{{entity}}のチャート", "chart-plural": "チャート", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "ステータスチェック", "children": "Children", "children-lowercase": "children", @@ -619,6 +620,7 @@ "invalid-condition": "不正な条件", "invalid-name": "不正な名称", "is-ready-for-preview": "はプレビューの準備ができました", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items selected", "january": "1月", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json index efa55ded706..fbe238876ad 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/nl-nl.json @@ -150,6 +150,7 @@ "chart-entity": "Chart {{entity}}", "chart-plural": "Charts", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Status controleren", "children": "Kinderen", "children-lowercase": "kinderen", @@ -619,6 +620,7 @@ "invalid-condition": "Ongeldige voorwaarde", "invalid-name": "Ongeldige naam", "is-ready-for-preview": "is gereed voor voorbeeldweergave", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items geselecteerd", "january": "januari", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json index 99903c39676..9ac45a19018 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pr-pr.json @@ -150,6 +150,7 @@ "chart-entity": "نمودار {{entity}}", "chart-plural": "نمودارها", "chart-type": "نوع نمودار", + "check-data-quality-failure": "Check data quality failure", "check-status": "بررسی وضعیت", "children": "فرزندان", "children-lowercase": "فرزندان", @@ -619,6 +620,7 @@ "invalid-condition": "شرط نامعتبر", "invalid-name": "نام نامعتبر", "is-ready-for-preview": "آماده پیش‌نمایش است", + "issue": "Issue", "issue-plural": "مشکلات", "items-selected-lowercase": "موارد انتخاب شده", "january": "ژانویه", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json index 742d3aaf8e4..1582216f33c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/pt-br.json @@ -150,6 +150,7 @@ "chart-entity": "Gráfico {{entity}}", "chart-plural": "Gráficos", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Verificar status", "children": "Filhos", "children-lowercase": "filhos", @@ -619,6 +620,7 @@ "invalid-condition": "Condição Inválida", "invalid-name": "Nome Inválido", "is-ready-for-preview": "está pronto para visualização", + "issue": "Issue", "issue-plural": "Problemas", "items-selected-lowercase": "Itens Selecionados", "january": "Janeiro", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json index 93c54c0ec05..c1def2b6915 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/ru-ru.json @@ -150,6 +150,7 @@ "chart-entity": "Диаграмма {{entity}}", "chart-plural": "Диаграммы", "chart-type": "Chart type", + "check-data-quality-failure": "Check data quality failure", "check-status": "Проверить статус", "children": "Наследники", "children-lowercase": "наследники", @@ -619,6 +620,7 @@ "invalid-condition": "Недопустимое условие", "invalid-name": "Неверное имя", "is-ready-for-preview": "готов к предварительному просмотру", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "items selected", "january": "Январь", diff --git a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json index 8f1842270af..ca68cd51823 100644 --- a/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json +++ b/openmetadata-ui/src/main/resources/ui/src/locale/languages/zh-cn.json @@ -150,6 +150,7 @@ "chart-entity": "图表{{entity}}", "chart-plural": "图表", "chart-type": "图表类型", + "check-data-quality-failure": "Check data quality failure", "check-status": "检查状态", "children": "子级", "children-lowercase": "子级", @@ -619,6 +620,7 @@ "invalid-condition": "无效条件", "invalid-name": "无效名称", "is-ready-for-preview": "可预览", + "issue": "Issue", "issue-plural": "Issues", "items-selected-lowercase": "已选项", "january": "一月", diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DataQuality/DataQualityPage.interface.ts b/openmetadata-ui/src/main/resources/ui/src/pages/DataQuality/DataQualityPage.interface.ts index df12b62883c..9f8201b3320 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DataQuality/DataQualityPage.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DataQuality/DataQualityPage.interface.ts @@ -31,4 +31,5 @@ export type DataQualityDashboardChartFilters = { tier?: string[]; startTs?: number; endTs?: number; + entityFQN?: string; }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx index b3bc17bc109..08dd0ce7025 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx @@ -12,7 +12,7 @@ * limitations under the License. */ -import { Col, Row, Space, Tabs } from 'antd'; +import { Col, Row, Space, Tabs, Tooltip } from 'antd'; import { AxiosError } from 'axios'; import classNames from 'classnames'; import { compare } from 'fast-json-patch'; @@ -20,7 +20,8 @@ import { isEmpty, isEqual, isUndefined } from 'lodash'; import { EntityTags } from 'Models'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useHistory, useParams } from 'react-router-dom'; +import { Link, useHistory, useParams } from 'react-router-dom'; +import { ReactComponent as RedAlertIcon } from '../../assets/svg/ic-alert-red.svg'; import { useActivityFeedProvider } from '../../components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; import ActivityThreadPanel from '../../components/ActivityFeed/ActivityThreadPanel/ActivityThreadPanel'; import { withActivityFeed } from '../../components/AppRouter/withActivityFeed'; @@ -75,6 +76,7 @@ import { useFqn } from '../../hooks/useFqn'; import { useSub } from '../../hooks/usePubSub'; import { FeedCounts } from '../../interface/feed.interface'; import { postThread } from '../../rest/feedsAPI'; +import { getDataQualityLineage } from '../../rest/lineageAPI'; import { getQueriesList } from '../../rest/queryAPI'; import { addFollower, @@ -131,6 +133,7 @@ const TableDetailsPageV1: React.FC = () => { DEFAULT_ENTITY_PERMISSION ); const [testCaseSummary, setTestCaseSummary] = useState(); + const [dqFailureCount, setDqFailureCount] = useState(0); const tableFqn = useMemo( () => @@ -142,6 +145,21 @@ const TableDetailsPageV1: React.FC = () => { [datasetFQN] ); + const alertBadge = useMemo(() => { + return tableClassBase.getAlertEnableStatus() && dqFailureCount > 0 ? ( + + + + + + ) : undefined; + }, [dqFailureCount, tableFqn]); + const extraDropdownContent = useMemo( () => entityUtilClassBase.getManageExtraOptions( @@ -198,16 +216,50 @@ const TableDetailsPageV1: React.FC = () => { } }, [tableFqn, viewUsagePermission]); - const fetchTestCaseSummary = async () => { - if (isUndefined(tableDetails?.testSuite?.id)) { - return; + const fetchDQFailureCount = async () => { + if (!tableClassBase.getAlertEnableStatus()) { + setDqFailureCount(0); } + // Todo: Remove this once we have support for count in API try { + const data = await getDataQualityLineage(tableFqn, { + upstreamDepth: 3, + }); + const updatedNodes = + data.nodes?.filter((node) => node.fullyQualifiedName !== tableFqn) ?? + []; + setDqFailureCount(updatedNodes.length); + } catch (error) { + setDqFailureCount(0); + } + }; + + const fetchTestCaseSummary = async () => { + try { + if (isUndefined(tableDetails?.testSuite?.id)) { + await fetchDQFailureCount(); + + return; + } + const response = await getTestCaseExecutionSummary( tableDetails?.testSuite?.id ); setTestCaseSummary(response); + + const failureCount = + response.columnTestSummary?.reduce((acc, curr) => { + return acc + (curr.failed ?? 0); + }, response.failed ?? 0) ?? + response.failed ?? + 0; + + if (failureCount === 0) { + await fetchDQFailureCount(); + } else { + setDqFailureCount(failureCount); + } } catch (error) { setTestCaseSummary(undefined); } @@ -958,6 +1010,7 @@ const TableDetailsPageV1: React.FC = () => { isRecursiveDelete afterDeleteAction={afterDeleteAction} afterDomainUpdateAction={updateTableDetailsState} + badge={alertBadge} dataAsset={tableDetails} entityType={EntityType.TABLE} extraDropdownContent={extraDropdownContent} diff --git a/openmetadata-ui/src/main/resources/ui/src/rest/dataQualityDashboardAPI.ts b/openmetadata-ui/src/main/resources/ui/src/rest/dataQualityDashboardAPI.ts index 03bd40260de..c6cc1a5888e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/rest/dataQualityDashboardAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/rest/dataQualityDashboardAPI.ts @@ -122,6 +122,14 @@ export const fetchTestCaseSummary = ( ); } + if (filters?.entityFQN) { + mustFilter.push({ + term: { + entityFQN: filters.entityFQN, + }, + }); + } + return getDataQualityReport({ q: JSON.stringify({ query: { @@ -275,6 +283,13 @@ export const fetchTestCaseStatusMetricsByDays = ( ) ); } + if (filters?.entityFQN) { + mustFilter.push({ + term: { + 'testCase.entityFQN': filters.entityFQN, + }, + }); + } return getDataQualityReport({ q: JSON.stringify({ diff --git a/openmetadata-ui/src/main/resources/ui/src/rest/lineageAPI.ts b/openmetadata-ui/src/main/resources/ui/src/rest/lineageAPI.ts index 3bfe282bafe..fea85600b01 100644 --- a/openmetadata-ui/src/main/resources/ui/src/rest/lineageAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/rest/lineageAPI.ts @@ -46,6 +46,25 @@ export const getLineageDataByFQN = async ( return response.data; }; +export const getDataQualityLineage = async ( + fqn: string, + config?: Partial +) => { + const { upstreamDepth = 1 } = config ?? {}; + const response = await APIClient.get( + `lineage/getDataQualityLineage`, + { + params: { + fqn, + upstreamDepth, + includeDeleted: false, + }, + } + ); + + return response.data; +}; + export const exportLineage = async ( fqn: string, entityType: string, diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts index af7632fb2f8..64e9b0e9d2f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts @@ -47,6 +47,10 @@ class TableClassBase { ): TabProps[] { return getTableDetailPageBaseTabs(tableDetailsPageProps); } + + public getAlertEnableStatus() { + return false; + } } const tableClassBase = new TableClassBase();