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();