From 7d24cb51646ba08f3033335788c1cb951e80ce3b Mon Sep 17 00:00:00 2001 From: Ashish Gupta Date: Wed, 20 Mar 2024 19:42:07 +0530 Subject: [PATCH] #15466: supported entity stats table in searchindex application history logs (#15620) * supported entity stats table in searchindex application history logs * localization keys * changes due to total records * added test around appLogsViewer and fix sonar issue --- .../AppLogsViewer/AppLogsViewer.component.tsx | 123 +++++- .../AppLogsViewer/AppLogsViewer.interface.ts | 45 +- .../AppLogsViewer/AppLogsViewer.test.tsx | 110 ++++- .../AppLogsViewer/app-logs-viewer.less | 44 ++ .../AppRunsHistory.component.tsx | 2 +- .../resources/ui/src/enums/entity.enum.ts | 3 + .../ui/src/locale/languages/de-de.json | 2 + .../ui/src/locale/languages/en-us.json | 2 + .../ui/src/locale/languages/es-es.json | 2 + .../ui/src/locale/languages/fr-fr.json | 2 + .../ui/src/locale/languages/he-he.json | 2 + .../ui/src/locale/languages/ja-jp.json | 2 + .../ui/src/locale/languages/nl-nl.json | 2 + .../ui/src/locale/languages/pt-br.json | 2 + .../ui/src/locale/languages/ru-ru.json | 2 + .../ui/src/locale/languages/zh-cn.json | 2 + .../ui/src/styles/components/table.less | 4 + .../ui/src/utils/ApplicaionUtils.test.ts | 26 ++ .../ui/src/utils/ApplicationUtils.tsx | 12 + .../src/utils/mocks/ApplicationUtils.mock.ts | 404 ++++++++++++++++++ 20 files changed, 783 insertions(+), 10 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/app-logs-viewer.less create mode 100644 openmetadata-ui/src/main/resources/ui/src/utils/ApplicaionUtils.test.ts create mode 100644 openmetadata-ui/src/main/resources/ui/src/utils/mocks/ApplicationUtils.mock.ts diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.component.tsx index 7878a7b8090..436a6581f9b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.component.tsx @@ -11,16 +11,33 @@ * limitations under the License. */ -import { Badge, Button, Card, Col, Divider, Row, Space } from 'antd'; +import { + Badge, + Button, + Card, + Col, + Divider, + Row, + Space, + Table, + Typography, +} from 'antd'; import { isNil } from 'lodash'; -import React, { useCallback } from 'react'; +import React, { useCallback, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { LazyLog } from 'react-lazylog'; import { ReactComponent as IconSuccessBadge } from '../../../../assets/svg/success-badge.svg'; +import { getEntityStatsData } from '../../../../utils/ApplicationUtils'; import { formatDateTimeWithTimezone } from '../../../../utils/date-time/DateTimeUtils'; import { formatJsonString } from '../../../../utils/StringsUtils'; +import AppBadge from '../../../common/Badge/Badge.component'; import CopyToClipboardButton from '../../../common/CopyToClipboardButton/CopyToClipboardButton'; -import { AppLogsViewerProps, JobStats } from './AppLogsViewer.interface'; +import './app-logs-viewer.less'; +import { + AppLogsViewerProps, + EntityStats, + JobStats, +} from './AppLogsViewer.interface'; const AppLogsViewer = ({ data }: AppLogsViewerProps) => { const { t } = useTranslation(); @@ -96,6 +113,7 @@ const AppLogsViewer = ({ data }: AppLogsViewerProps) => { { /> { [timestamp, formatDateTimeWithTimezone] ); + const tableColumn = useMemo(() => { + const entityTotalJobStatsData = + successContext?.stats.jobStats || failureContext?.stats.jobStats; + + return [ + { + title: t('label.name'), + dataIndex: 'name', + key: 'name', + }, + { + title: ( +
+ + {t('label.entity-record-plural', { + entity: t('label.total'), + })}{' '} + + +
+ ), + dataIndex: 'totalRecords', + key: 'totalRecords', + render: (text: string) => ( + {text} + ), + }, + { + title: ( +
+ + {t('label.entity-record-plural', { + entity: t('label.success'), + })}{' '} + + +
+ ), + dataIndex: 'successRecords', + key: 'successRecords', + render: (text: string) => ( + {text} + ), + }, + { + title: ( +
+ + {t('label.entity-record-plural', { + entity: t('label.failed'), + })}{' '} + + +
+ ), + dataIndex: 'failedRecords', + key: 'failedRecords', + render: (text: string) => ( + {text} + ), + }, + ]; + }, [successContext, failureContext]); + + const entityStatsRenderer = useCallback( + (entityStats: EntityStats) => { + return ( + + ); + }, + [tableColumn] + ); + return ( <> {successContext?.stats && statsRender(successContext?.stats.jobStats)} {failureContext?.stats && statsRender(failureContext?.stats.jobStats)} + + {successContext?.stats?.entityStats && + entityStatsRenderer(successContext.stats.entityStats)} + {failureContext?.stats?.entityStats && + entityStatsRenderer(failureContext.stats.entityStats)} + {logsRender( formatJsonString( JSON.stringify( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.interface.ts index 715262b6a0f..132933f1cdc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.interface.ts @@ -11,15 +11,52 @@ * limitations under the License. */ +import { EntityType } from '../../../../enums/entity.enum'; import { AppRunRecord } from '../../../../generated/entity/applications/appRunRecord'; export interface AppLogsViewerProps { data: AppRunRecord; } -export interface JobStats { - totalRecords: string; - successRecords: string; - failedRecords: string; +export interface TotalRecords { + totalRecords: number; + successRecords: number; + failedRecords: number; +} +export interface JobStats extends TotalRecords { processedRecords: string; } + +export type EntityTypeSearchIndex = Exclude< + EntityType, + | EntityType.BOT + | EntityType.ALERT + | EntityType.knowledgePanels + | EntityType.WEBHOOK + | EntityType.USER + | EntityType.ROLE + | EntityType.TEAM + | EntityType.SUBSCRIPTION + | EntityType.POLICY + | EntityType.DATA_INSIGHT_CHART + | EntityType.KPI + | EntityType.TYPE + | EntityType.APP_MARKET_PLACE_DEFINITION + | EntityType.APPLICATION + | EntityType.PERSONA + | EntityType.DOC_STORE + | EntityType.PAGE + | EntityType.SAMPLE_DATA + | EntityType.GOVERN + | EntityType.CUSTOM_METRIC + | EntityType.ALL +>; + +export type EntityStats = Record; + +export interface EntityStatsData { + name: string; + totalRecords: number; + successRecords: number; + failedRecords: number; +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.test.tsx index ede24d1c15f..d6bca1d8d2b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/AppLogsViewer.test.tsx @@ -39,6 +39,23 @@ jest.mock('antd', () => ({ Badge: jest.fn().mockReturnValue(
Badge
), })); +jest.mock('../../../../utils/ApplicationUtils', () => ({ + getEntityStatsData: jest.fn().mockReturnValue([ + { + name: 'chart', + totalRecords: 100, + failedRecords: 10, + successRecords: 90, + }, + ]), +})); + +jest.mock('../../../common/Badge/Badge.component', () => + jest.fn().mockImplementation(({ label }) => { + return
{`${label}-AppBadge`}
; + }) +); + const mockProps1 = { data: { appId: '6e4d3dcf-238d-4874-b4e4-dd863ede6544', @@ -54,7 +71,6 @@ const mockProps1 = { failedRecords: 0, successRecords: 274, }, - entityStats: {}, }, }, scheduleInfo: { @@ -77,7 +93,51 @@ const mockProps2 = { failedRecords: 0, successRecords: 274, }, - entityStats: {}, + }, + }, + }, +}; + +const mockProps3 = { + data: { + ...mockProps1.data, + successContext: { + stats: { + jobStats: { + totalRecords: 274, + failedRecords: 4, + successRecords: 270, + }, + entityStats: { + chart: { + totalRecords: 100, + failedRecords: 10, + successRecords: 90, + }, + }, + }, + }, + }, +}; + +const mockProps4 = { + data: { + ...mockProps1.data, + successContext: undefined, + failureContext: { + stats: { + jobStats: { + totalRecords: 274, + failedRecords: 4, + successRecords: 270, + }, + entityStats: { + chart: { + totalRecords: 100, + failedRecords: 10, + successRecords: 90, + }, + }, }, }, }, @@ -105,4 +165,50 @@ describe('AppLogsViewer component', () => { expect(screen.getByText('--')).toBeInTheDocument(); // Note: not asserting other elements as for failure also same elements will render }); + + it("should not render entity stats table based if successContext doesn't have data", () => { + render(); + + expect( + screen.queryByTestId('app-entity-stats-history-table') + ).not.toBeInTheDocument(); + }); + + it('should render entity stats table based if SuccessContext has data', () => { + render(); + + expect( + screen.getByTestId('app-entity-stats-history-table') + ).toBeInTheDocument(); + + expect(screen.getByText('label.name')).toBeInTheDocument(); + + expect(screen.getAllByTestId('app-badge')).toHaveLength(3); + expect(screen.getByText('274-AppBadge')).toBeInTheDocument(); + expect(screen.getByText('270-AppBadge')).toBeInTheDocument(); + expect(screen.getByText('4-AppBadge')).toBeInTheDocument(); + }); + + it("should not render entity stats table based if failedContext doesn't have data", () => { + render(); + + expect( + screen.queryByTestId('app-entity-stats-history-table') + ).not.toBeInTheDocument(); + }); + + it('should render entity stats table based if failedContext has data', () => { + render(); + + expect( + screen.getByTestId('app-entity-stats-history-table') + ).toBeInTheDocument(); + + expect(screen.getByText('label.name')).toBeInTheDocument(); + + expect(screen.getAllByTestId('app-badge')).toHaveLength(3); + expect(screen.getByText('274-AppBadge')).toBeInTheDocument(); + expect(screen.getByText('270-AppBadge')).toBeInTheDocument(); + expect(screen.getByText('4-AppBadge')).toBeInTheDocument(); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/app-logs-viewer.less b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/app-logs-viewer.less new file mode 100644 index 00000000000..70137ec19a9 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppLogsViewer/app-logs-viewer.less @@ -0,0 +1,44 @@ +/* + * 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'); + +.entity-stats { + width: max-content; + + .ant-typography { + font-weight: 500; + } + + &.total { + background-color: @primary-color-hover; + border: 1px solid @primary-color; + .ant-typography { + color: @primary-color; + } + } + &.success { + background-color: @green-2; + border: 1px solid @success-color; + .ant-typography { + color: @success-color; + } + } + &.failure { + background-color: @error-light-color; + border: 1px solid @failed-color; + .ant-typography { + color: @failed-color; + } + } +} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppRunsHistory/AppRunsHistory.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppRunsHistory/AppRunsHistory.component.tsx index 0b9a07bad5a..a1bdd3bcb2f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppRunsHistory/AppRunsHistory.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Applications/AppRunsHistory/AppRunsHistory.component.tsx @@ -152,7 +152,7 @@ const AppRunsHistory = forwardRef( return NO_DATA_PLACEHOLDER; } }, - [showLogAction, appData, isExternalApp] + [showLogAction, appData, isExternalApp, handleRowExpandable] ); const tableColumn: ColumnsType = useMemo( diff --git a/openmetadata-ui/src/main/resources/ui/src/enums/entity.enum.ts b/openmetadata-ui/src/main/resources/ui/src/enums/entity.enum.ts index b75f7afd677..53f85a5f284 100644 --- a/openmetadata-ui/src/main/resources/ui/src/enums/entity.enum.ts +++ b/openmetadata-ui/src/main/resources/ui/src/enums/entity.enum.ts @@ -63,6 +63,9 @@ export enum EntityType { CUSTOM_METRIC = 'customMetric', INGESTION_PIPELINE = 'ingestionPipeline', QUERY = 'query', + ENTITY_REPORT_DATA = 'entityReportData', + WEB_ANALYTIC_ENTITY_VIEW_REPORT_DATA = 'webAnalyticEntityViewReportData', + WEB_ANALYTIC_USER_ACTIVITY_REPORT_DATA = 'webAnalyticUserActivityReportData', } export enum AssetsType { 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 fbc4b60d7c8..ae94ba5fa60 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}}-Name", "entity-plural": "Entitäten", "entity-proportion": "{{entity}}-Anteil", + "entity-record-plural": "{{entity}} Records", "entity-service": "{{entity}}-Dienst", "entity-type-plural": "{{entity}}-Typen", "entity-version-detail-plural": "Details zu {{entity}}-Versionen", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "themen", "topic-name": "Themenname", "topic-plural": "Themen", + "total": "Total", "total-entity": "Gesamte {{entity}}", "total-index-sent": "Gesamtindex gesendet", "tour": "Tour", 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 e901d247d3b..05b931280ec 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}} Name", "entity-plural": "Entities", "entity-proportion": "{{entity}} Proportion", + "entity-record-plural": "{{entity}} Records", "entity-service": "{{entity}} Service", "entity-type-plural": "{{entity}} Type", "entity-version-detail-plural": "{{entity}} Version Details", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "topics", "topic-name": "Topic Name", "topic-plural": "Topics", + "total": "Total", "total-entity": "Total {{entity}}", "total-index-sent": " Total index sent", "tour": "Tour", 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 7cad44b185f..34a3da4a376 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 @@ -412,6 +412,7 @@ "entity-name": "Nombre de {{entity}}", "entity-plural": "Entidades", "entity-proportion": "Proporción de {{entity}}", + "entity-record-plural": "{{entity}} Records", "entity-service": "Servicio de {{entity}}", "entity-type-plural": "Tipo de {{entity}}", "entity-version-detail-plural": "Detalles de versión de {{entity}}", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "topics", "topic-name": "Nombre del Topic", "topic-plural": "Topics", + "total": "Total", "total-entity": "Total de {{entity}}", "total-index-sent": "Total de índices enviados", "tour": "Recorrido", 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 618768e47f8..de27a661db9 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 @@ -412,6 +412,7 @@ "entity-name": "Nom de {{entity}}", "entity-plural": "Entités", "entity-proportion": "Proportion de {{entity}}", + "entity-record-plural": "{{entity}} Records", "entity-service": "Service de {{entity}}", "entity-type-plural": "{{entity}} Types", "entity-version-detail-plural": "Détails des Versions de {{entity}}", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "sujets", "topic-name": "Nom du Sujet", "topic-plural": "Sujets", + "total": "Total", "total-entity": "Total {{entity}}", "total-index-sent": "Total d'Index Envoyés", "tour": "Visite", 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 1bc9073bc7a..654690c7465 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 @@ -412,6 +412,7 @@ "entity-name": "שם {{entity}}", "entity-plural": "ישויות", "entity-proportion": "יחס {{entity}}", + "entity-record-plural": "{{entity}} Records", "entity-service": "שירות {{entity}}", "entity-type-plural": "סוגי {{entity}}", "entity-version-detail-plural": "גרסאות פרטי {{entity}}", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "שירותי סטרים", "topic-name": "שם הסטרים", "topic-plural": "שירותי סטרים", + "total": "Total", "total-entity": "סך הכל {{entity}}", "total-index-sent": "סך הכל שלח אינדקס", "tour": "סיור", 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 f2d219dffc4..8ec3bb2e8ed 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}} 名", "entity-plural": "エンティティ", "entity-proportion": "{{entity}} Proportion", + "entity-record-plural": "{{entity}} Records", "entity-service": "{{entity}}サービス", "entity-type-plural": "{{entity}} Type", "entity-version-detail-plural": "{{entity}} Version Details", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "topics", "topic-name": "トピック名", "topic-plural": "トピック", + "total": "Total", "total-entity": "合計 {{entity}}", "total-index-sent": " Total index sent", "tour": "ツアー", 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 9ef076102d9..b9a662e870b 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}}-naam", "entity-plural": "Entiteiten", "entity-proportion": "{{entity}}-verhouding", + "entity-record-plural": "{{entity}} Records", "entity-service": "{{entity}}-service", "entity-type-plural": "{{entity}}-type", "entity-version-detail-plural": "{{entity}}-versie-details", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "onderwerpen", "topic-name": "Onderwerpnaam", "topic-plural": "Onderwerpen", + "total": "Total", "total-entity": "{{entity}} totaal", "total-index-sent": "Index verzonden totaal", "tour": "Rondleiding", 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 3f1ad74700b..f7e93852c3b 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 @@ -412,6 +412,7 @@ "entity-name": "Nome de {{entity}}", "entity-plural": "Entidades", "entity-proportion": "Proporção de {{entity}}", + "entity-record-plural": "{{entity}} Records", "entity-service": "Serviço de {{entity}}", "entity-type-plural": "Tipo de {{entity}}", "entity-version-detail-plural": "Detalhes da Versão de {{entity}}", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "tópicos", "topic-name": "Nome do Tópico", "topic-plural": "Tópicos", + "total": "Total", "total-entity": "Total de {{entity}}", "total-index-sent": " Total de índice enviado", "tour": "Tour", 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 a2eac0114b6..b6e9b5a683c 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}} Имя", "entity-plural": "Сущности", "entity-proportion": "Доля \"{{entity}}\"", + "entity-record-plural": "{{entity}} Records", "entity-service": "Сервис {{entity}}", "entity-type-plural": "Тип {{entity}}", "entity-version-detail-plural": "{{entity}} Version Details", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "топики", "topic-name": "Наименование темы", "topic-plural": "Топики", + "total": "Total", "total-entity": "Все {{entity}}", "total-index-sent": "Все индексы отправлены", "tour": "Руководство пользователя", 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 0223edb183f..59ef7f40fbe 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 @@ -412,6 +412,7 @@ "entity-name": "{{entity}}名称", "entity-plural": "实体", "entity-proportion": "{{entity}}比例", + "entity-record-plural": "{{entity}} Records", "entity-service": "{{entity}}服务", "entity-type-plural": "{{entity}}类型", "entity-version-detail-plural": "{{entity}}版本详情", @@ -1148,6 +1149,7 @@ "topic-lowercase-plural": "消息主题", "topic-name": "消息主题名称", "topic-plural": "消息主题", + "total": "Total", "total-entity": "所有{{entity}}", "total-index-sent": "已发送的索引", "tour": "导览", diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/components/table.less b/openmetadata-ui/src/main/resources/ui/src/styles/components/table.less index 35c3cd5a121..f5c1561e018 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/components/table.less +++ b/openmetadata-ui/src/main/resources/ui/src/styles/components/table.less @@ -68,6 +68,10 @@ &:last-child td { border-bottom: none; + + td { + border-bottom: 1px solid @border-color; + } } } thead > tr { diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ApplicaionUtils.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/ApplicaionUtils.test.ts new file mode 100644 index 00000000000..e481b95e59b --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/utils/ApplicaionUtils.test.ts @@ -0,0 +1,26 @@ +/* + * 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 { getEntityStatsData } from './ApplicationUtils'; +import { + MOCK_APPLICATION_ENTITY_STATS, + MOCK_APPLICATION_ENTITY_STATS_DATA, +} from './mocks/ApplicationUtils.mock'; + +describe('ApplicationUtils tests', () => { + it('getEntityStatsData should return stats data in array', () => { + const resultData = getEntityStatsData(MOCK_APPLICATION_ENTITY_STATS); + + expect(resultData).toEqual(MOCK_APPLICATION_ENTITY_STATS_DATA); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/ApplicationUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/ApplicationUtils.tsx index fa9ad893160..677c21616b7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/ApplicationUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/ApplicationUtils.tsx @@ -11,6 +11,11 @@ * limitations under the License. */ import { StatusType } from '../components/common/StatusBadge/StatusBadge.interface'; +import { + EntityStats, + EntityStatsData, + EntityTypeSearchIndex, +} from '../components/Settings/Applications/AppLogsViewer/AppLogsViewer.interface'; import { Status } from '../generated/entity/applications/appRunRecord'; import { PipelineState } from '../generated/entity/services/ingestionPipelines/ingestionPipeline'; @@ -46,3 +51,10 @@ export const getStatusFromPipelineState = (status: PipelineState) => { return Status.Failed; }; + +export const getEntityStatsData = (data: EntityStats): EntityStatsData[] => { + return Object.keys(data).map((key) => ({ + name: key, + ...data[key as EntityTypeSearchIndex], + })); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/mocks/ApplicationUtils.mock.ts b/openmetadata-ui/src/main/resources/ui/src/utils/mocks/ApplicationUtils.mock.ts new file mode 100644 index 00000000000..e6762cc6c25 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/utils/mocks/ApplicationUtils.mock.ts @@ -0,0 +1,404 @@ +/* + * 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 { EntityType } from '../../enums/entity.enum'; + +export const MOCK_APPLICATION_ENTITY_STATS = { + [EntityType.TAG]: { + totalRecords: 10, + failedRecords: 0, + successRecords: 10, + }, + [EntityType.TEAM]: { + totalRecords: 17, + failedRecords: 0, + successRecords: 17, + }, + [EntityType.USER]: { + totalRecords: 105, + failedRecords: 0, + successRecords: 105, + }, + [EntityType.CHART]: { + totalRecords: 16, + failedRecords: 0, + successRecords: 16, + }, + [EntityType.QUERY]: { + totalRecords: 8, + failedRecords: 0, + successRecords: 8, + }, + [EntityType.TABLE]: { + totalRecords: 180, + failedRecords: 0, + successRecords: 180, + }, + [EntityType.TOPIC]: { + totalRecords: 10, + failedRecords: 0, + successRecords: 10, + }, + [EntityType.DOMAIN]: { + totalRecords: 0, + failedRecords: 0, + successRecords: 0, + }, + [EntityType.MLMODEL]: { + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + [EntityType.DATABASE]: { + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + [EntityType.GLOSSARY]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.PIPELINE]: { + totalRecords: 8, + failedRecords: 0, + successRecords: 8, + }, + [EntityType.TEST_CASE]: { + totalRecords: 7, + failedRecords: 0, + successRecords: 7, + }, + [EntityType.CONTAINER]: { + totalRecords: 17, + failedRecords: 0, + successRecords: 17, + }, + [EntityType.DASHBOARD]: { + totalRecords: 14, + failedRecords: 0, + successRecords: 14, + }, + [EntityType.TEST_SUITE]: { + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + [EntityType.DATA_PRODUCT]: { + totalRecords: 0, + failedRecords: 0, + successRecords: 0, + }, + [EntityType.SEARCH_INDEX]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.GLOSSARY_TERM]: { + totalRecords: 0, + failedRecords: 0, + successRecords: 0, + }, + [EntityType.SEARCH_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.CLASSIFICATION]: { + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + [EntityType.DATABASE_SCHEMA]: { + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + [EntityType.MLMODEL_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.STORAGE_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.DATABASE_SERVICE]: { + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + [EntityType.METADATA_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.PIPELINE_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.STORED_PROCEDURE]: { + totalRecords: 12, + failedRecords: 0, + successRecords: 12, + }, + [EntityType.DASHBOARD_SERVICE]: { + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + [EntityType.ENTITY_REPORT_DATA]: { + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + [EntityType.MESSAGING_SERVICE]: { + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + [EntityType.INGESTION_PIPELINE]: { + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + [EntityType.DASHBOARD_DATA_MODEL]: { + totalRecords: 6, + failedRecords: 0, + successRecords: 6, + }, + [EntityType.WEB_ANALYTIC_ENTITY_VIEW_REPORT_DATA]: { + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + [EntityType.WEB_ANALYTIC_USER_ACTIVITY_REPORT_DATA]: { + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, +}; + +export const MOCK_APPLICATION_ENTITY_STATS_DATA = [ + { + name: EntityType.TAG, + totalRecords: 10, + successRecords: 10, + failedRecords: 0, + }, + { + name: EntityType.TEAM, + totalRecords: 17, + successRecords: 17, + failedRecords: 0, + }, + { + name: EntityType.USER, + totalRecords: 105, + successRecords: 105, + failedRecords: 0, + }, + { + name: EntityType.CHART, + totalRecords: 16, + successRecords: 16, + failedRecords: 0, + }, + { + name: EntityType.QUERY, + totalRecords: 8, + successRecords: 8, + failedRecords: 0, + }, + { + name: EntityType.TABLE, + totalRecords: 180, + successRecords: 180, + failedRecords: 0, + }, + { + name: EntityType.TOPIC, + totalRecords: 10, + successRecords: 10, + failedRecords: 0, + }, + { + name: EntityType.DOMAIN, + totalRecords: 0, + successRecords: 0, + failedRecords: 0, + }, + { + name: EntityType.MLMODEL, + totalRecords: 2, + successRecords: 2, + failedRecords: 0, + }, + { + name: EntityType.DATABASE, + totalRecords: 2, + successRecords: 2, + failedRecords: 0, + }, + { + name: EntityType.GLOSSARY, + totalRecords: 1, + successRecords: 1, + failedRecords: 0, + }, + { + name: EntityType.PIPELINE, + totalRecords: 8, + successRecords: 8, + failedRecords: 0, + }, + { + name: EntityType.TEST_CASE, + totalRecords: 7, + failedRecords: 0, + successRecords: 7, + }, + { + name: EntityType.CONTAINER, + totalRecords: 17, + failedRecords: 0, + successRecords: 17, + }, + { + name: EntityType.DASHBOARD, + totalRecords: 14, + failedRecords: 0, + successRecords: 14, + }, + { + name: EntityType.TEST_SUITE, + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + { + name: EntityType.DATA_PRODUCT, + totalRecords: 0, + successRecords: 0, + failedRecords: 0, + }, + { + name: EntityType.SEARCH_INDEX, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.GLOSSARY_TERM, + totalRecords: 0, + successRecords: 0, + failedRecords: 0, + }, + { + name: EntityType.SEARCH_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.CLASSIFICATION, + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + { + name: EntityType.DATABASE_SCHEMA, + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + { + name: EntityType.MLMODEL_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.STORAGE_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.DATABASE_SERVICE, + totalRecords: 3, + failedRecords: 0, + successRecords: 3, + }, + { + name: EntityType.METADATA_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.PIPELINE_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.STORED_PROCEDURE, + totalRecords: 12, + failedRecords: 0, + successRecords: 12, + }, + { + name: EntityType.DASHBOARD_SERVICE, + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + { + name: EntityType.ENTITY_REPORT_DATA, + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + { + name: EntityType.MESSAGING_SERVICE, + totalRecords: 1, + failedRecords: 0, + successRecords: 1, + }, + { + name: EntityType.INGESTION_PIPELINE, + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, + { + name: EntityType.DASHBOARD_DATA_MODEL, + totalRecords: 6, + failedRecords: 0, + successRecords: 6, + }, + { + name: EntityType.WEB_ANALYTIC_ENTITY_VIEW_REPORT_DATA, + totalRecords: 2, + failedRecords: 0, + successRecords: 2, + }, + { + name: EntityType.WEB_ANALYTIC_USER_ACTIVITY_REPORT_DATA, + totalRecords: 4, + failedRecords: 0, + successRecords: 4, + }, +];