diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/insights/workflows/dataAssets/DataAssetsWorkflow.java b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/insights/workflows/dataAssets/DataAssetsWorkflow.java index dd9d534bea8..38679aa24f0 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/insights/workflows/dataAssets/DataAssetsWorkflow.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/insights/workflows/dataAssets/DataAssetsWorkflow.java @@ -97,9 +97,9 @@ public class DataAssetsWorkflow { oldestPossibleTimestamp); } } else { - this.endTimestamp = - TimestampUtils.getEndOfDayTimestamp(TimestampUtils.subtractDays(timestamp, 1)); - this.startTimestamp = TimestampUtils.getStartOfDayTimestamp(endTimestamp); + this.endTimestamp = TimestampUtils.getEndOfDayTimestamp(TimestampUtils.addDays(timestamp, 1)); + this.startTimestamp = + TimestampUtils.getStartOfDayTimestamp(TimestampUtils.subtractDays(timestamp, 1)); } this.batchSize = batchSize; diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataInsight.spec.ts b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataInsight.spec.ts deleted file mode 100644 index 2195b076bca..00000000000 --- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/DataInsight.spec.ts +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2023 Collate. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * http://www.apache.org/licenses/LICENSE-2.0 - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - customFormatDateTime, - getCurrentMillis, - getEpochMillisForFutureDays, -} from '../../../src/utils/date-time/DateTimeUtils'; -import { - descriptionBox, - interceptURL, - verifyResponseStatusCode, -} from '../../common/common'; -import { verifyKpiChart } from '../../common/DataInsightUtils'; -import { getToken } from '../../common/Utils/LocalStorage'; -import { - EXPLORE_PAGE_TABS, - SidebarItem, -} from '../../constants/Entity.interface'; -import { GlobalSettingOptions } from '../../constants/settings.constant'; - -const KPI_DATA = [ - { - dataInsightChart: 'Percentage of Entities With Description', - displayName: 'Cypress description with percentage', - metricType: 'completedDescriptionFraction (PERCENTAGE)', - }, - { - dataInsightChart: 'Percentage of Entities With Owner', - displayName: 'Cypress Owner with percentage', - metricType: 'hasOwnerFraction (PERCENTAGE)', - }, -]; - -const deleteKpiRequest = () => { - cy.get('[data-menu-id*="kpi"]').click(); - cy.wait('@getKpi').then(({ response }) => { - const data = response.body.data; - if (data.length > 0) { - cy.getAllLocalStorage().then((storageData) => { - const token = getToken(storageData); - - data.forEach((element) => { - cy.request({ - method: 'DELETE', - url: `/api/v1/kpi/${element.id}?hardDelete=true&recursive=false`, - headers: { Authorization: `Bearer ${token}` }, - }).then((response) => { - expect(response.status).to.eq(200); - }); - }); - }); - cy.reload(); - } - }); -}; - -const addKpi = (data) => { - const startDate = customFormatDateTime(getCurrentMillis(), 'yyyy-MM-dd'); - const endDate = customFormatDateTime( - getEpochMillisForFutureDays(1), - 'yyyy-MM-dd' - ); - interceptURL('POST', '/api/v1/kpi', 'createKpi'); - cy.get('#dataInsightChart').click(); - cy.get(`.ant-select-dropdown [title="${data.dataInsightChart}"]`).click(); - cy.get('[data-testid="displayName"]').type(data.displayName); - cy.get('#metricType').click(); - cy.get(`.ant-select-dropdown [title="${data.metricType}"]`).click(); - cy.get('[data-testid="metric-percentage-input"] [role="spinbutton"]') - .scrollIntoView() - .type('100'); - cy.get('[data-testid="start-date"]').click().type(`${startDate}{enter}`); - cy.get('[data-testid="end-date"]').click().type(`${endDate}{enter}`); - cy.get(descriptionBox).scrollIntoView().type('cypress test'); - cy.get('[data-testid="submit-btn"]').scrollIntoView().click(); - verifyResponseStatusCode('@createKpi', 201); -}; - -// Need to migrate it to playwright -describe.skip('Data Insight feature', { tags: 'Observability' }, () => { - beforeEach(() => { - interceptURL( - 'GET', - '/api/v1/analytics/dataInsights/charts/aggregate?*', - 'dataInsightsChart' - ); - interceptURL('GET', '/api/v1/kpi?fields=*', 'getKpi'); - cy.login(); - }); - - it('Initial setup', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - deleteKpiRequest(); - }); - - it('Create description and owner KPI', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - cy.get('[data-menu-id*="kpi"]').click(); - KPI_DATA.map((data) => { - cy.get('[data-testid="add-kpi-btn"]').click(); - verifyResponseStatusCode('@getKpi', 200); - addKpi(data); - }); - }); - - it('Deploy data insight index', () => { - interceptURL('GET', '/api/v1/apps?limit=*', 'apps'); - interceptURL( - 'GET', - '/api/v1/apps/name/DataInsightsApplication?*', - 'dataInsightsApplication' - ); - interceptURL( - 'POST', - '/api/v1/apps/deploy/DataInsightsApplication', - 'deploy' - ); - interceptURL( - 'POST', - '/api/v1/apps/trigger/DataInsightsApplication', - 'triggerPipeline' - ); - cy.settingClick(GlobalSettingOptions.APPLICATIONS); - verifyResponseStatusCode('@apps', 200); - cy.get( - '[data-testid="data-insights-application-card"] [data-testid="config-btn"]' - ).click(); - verifyResponseStatusCode('@dataInsightsApplication', 200); - cy.get('[data-testid="deploy-button"]').click(); - verifyResponseStatusCode('@deploy', 200); - cy.reload(); - verifyResponseStatusCode('@dataInsightsApplication', 200); - - // Adding a manual wait to allow some time between deploying the pipeline and triggering it - // eslint-disable-next-line cypress/no-unnecessary-waiting - cy.wait(2000); - cy.get('[data-testid="run-now-button"]').click(); - verifyResponseStatusCode('@triggerPipeline', 200); - cy.reload(); - verifyKpiChart(); - }); - - it('Verifying Data assets tab', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - cy.get('[data-testid="date-picker-menu"]').click(); - cy.contains('[role="menuitem"]', 'Last 60 days').click(); - verifyResponseStatusCode('@dataInsightsChart', 200); - cy.get('[data-testid="search-dropdown-Team"]').should('be.visible'); - cy.get('[data-testid="search-dropdown-Tier"]').should('be.visible'); - cy.get('[data-testid="summary-card"]').should('be.visible'); - cy.get('[data-testid="kpi-card"]').should('be.visible'); - cy.get('#entity-summary-chart').scrollIntoView().should('be.visible'); - cy.get('#PercentageOfEntitiesWithDescriptionByType-graph') - .scrollIntoView() - .should('be.visible'); - cy.get('#PercentageOfServicesWithDescription-graph') - .scrollIntoView() - .should('be.visible'); - cy.get('#PercentageOfEntitiesWithOwnerByType-graph') - .scrollIntoView() - .should('be.visible'); - cy.get('#PercentageOfServicesWithOwner-graph') - .scrollIntoView() - .should('be.visible'); - cy.get('#TotalEntitiesByTier-graph').scrollIntoView().should('be.visible'); - }); - - it('Verify No owner and description redirection to explore page', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - interceptURL( - 'GET', - '/api/v1/search/query?*descriptionStatus*INCOMPLETE*', - 'noDescriptionAssets' - ); - cy.get('[data-testid="explore-asset-with-no-description"]') - .scrollIntoView() - .click(); - Object.values(EXPLORE_PAGE_TABS).map((tab) => { - cy.get(`[data-testid="${tab}-tab"]`).scrollIntoView().click(); - verifyResponseStatusCode('@noDescriptionAssets', 200); - cy.get('[data-testid="advance-search-filter-text"]').should( - 'contain', - "descriptionStatus = 'INCOMPLETE'" - ); - }); - - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - interceptURL( - 'GET', - '/api/v1/search/query?*must_not*exists*owner.displayName.keyword*', - 'noOwnerAssets' - ); - cy.get('[data-testid="explore-asset-with-no-owner"]') - .scrollIntoView() - .click(); - - Object.values(EXPLORE_PAGE_TABS).map((tab) => { - cy.get(`[data-testid="${tab}-tab"]`).scrollIntoView().click(); - verifyResponseStatusCode('@noOwnerAssets', 200); - cy.get('[data-testid="advance-search-filter-text"]').should( - 'contain', - 'owner.displayName.keyword IS NULL' - ); - }); - }); - - it('Verifying App analytics tab', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - cy.get('[data-testid="date-picker-menu"]').click(); - cy.contains('[role="menuitem"]', 'Last 60 days').click(); - verifyResponseStatusCode('@getKpi', 200); - cy.get('[data-menu-id*="app-analytics"]').click(); - verifyResponseStatusCode('@dataInsightsChart', 200); - cy.get('[data-testid="summary-card-content"]').should('be.visible'); - cy.get('[data-testid="entity-summary-card-percentage"]') - .contains('Most Viewed Data Assets') - .scrollIntoView() - .should('be.visible'); - cy.get('[data-testid="entity-page-views-card"]') - .scrollIntoView() - .should('be.visible'); - cy.get('[data-testid="entity-active-user-card"]') - .scrollIntoView() - .should('be.visible'); - cy.get('[data-testid="entity-summary-card-percentage"]') - .contains('Most Active Users') - .scrollIntoView() - .should('be.visible'); - }); - - it('Verifying KPI tab', () => { - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - cy.get('[data-testid="date-picker-menu"]').click(); - cy.contains('[role="menuitem"]', 'Last 60 days').click(); - cy.get('[data-menu-id*="kpi"]').click(); - verifyResponseStatusCode('@getKpi', 200); - cy.get('[data-testid="kpi-card"]').should('be.visible'); - cy.get( - '[data-row-key="cypress-description-with-percentage-completed-description-fraction"]' - ) - .scrollIntoView() - .should('be.visible'); - cy.get('[data-row-key="cypress-owner-with-percentage-has-owner-fraction"]') - .scrollIntoView() - .should('be.visible'); - }); - - it('Update KPI', () => { - interceptURL('GET', '/api/v1/kpi/name/*', 'fetchKpiByName'); - interceptURL('PATCH', '/api/v1/kpi/*', 'updateKpi'); - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - cy.get('[data-menu-id*="kpi"]').click(); - verifyResponseStatusCode('@getKpi', 200); - KPI_DATA.map((data) => { - cy.get(`[data-testid="edit-action-${data.displayName}"]`).click(); - verifyResponseStatusCode('@fetchKpiByName', 200); - cy.get('[data-testid="metric-percentage-input"] [role="spinbutton"]') - .scrollIntoView() - .clear() - .type('50'); - cy.get('[data-testid="submit-btn"]').scrollIntoView().click(); - verifyResponseStatusCode('@updateKpi', 200); - }); - }); - - it('Delete Kpi', () => { - interceptURL('GET', '/api/v1/kpi/name/*', 'fetchKpiByName'); - interceptURL( - 'DELETE', - '/api/v1/kpi/*?hardDelete=true&recursive=false', - 'deleteKpi' - ); - cy.sidebarClick(SidebarItem.DATA_INSIGHT); - verifyResponseStatusCode('@dataInsightsChart', 200); - cy.get('[data-menu-id*="kpi"]').click(); - verifyResponseStatusCode('@getKpi', 200); - KPI_DATA.map((data) => { - cy.get(`[data-testid="delete-action-${data.displayName}"]`).click(); - cy.get('[data-testid="confirmation-text-input"]').type('DELETE'); - cy.get('[data-testid="confirm-button"]').click(); - verifyResponseStatusCode('@deleteKpi', 200); - }); - }); -}); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/dataInsight.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/dataInsight.ts new file mode 100644 index 00000000000..8919b5132de --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/dataInsight.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +export const KPI_DATA = [ + { + dataInsightChart: 'Description KPI', + displayName: 'Playwright description with percentage', + metricType: 'Percentage', + }, + { + dataInsightChart: 'Owner KPI', + displayName: 'Playwright Owner with percentage', + metricType: 'Percentage', + }, +]; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataInsight.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataInsight.spec.ts new file mode 100644 index 00000000000..6a080689cb3 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataInsight.spec.ts @@ -0,0 +1,259 @@ +/* + * 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 test, { expect } from '@playwright/test'; +import { KPI_DATA } from '../../constant/dataInsight'; +import { GlobalSettingOptions } from '../../constant/settings'; +import { SidebarItem } from '../../constant/sidebar'; +import { TableClass } from '../../support/entity/TableClass'; +import { + createNewPage, + getApiContext, + redirectToHomePage, +} from '../../utils/common'; +import { addKpi, deleteKpiRequest } from '../../utils/dataInsight'; +import { settingClick, sidebarClick } from '../../utils/sidebar'; + +// use the admin user to login +test.use({ storageState: 'playwright/.auth/admin.json' }); + +test.describe.configure({ mode: 'serial' }); + +test.describe('Data Insight Page', () => { + const table = new TableClass(); + + test.beforeAll(async ({ browser }) => { + const { apiContext } = await createNewPage(browser); + + await table.create(apiContext); + + apiContext.patch(`/api/v1/tables/${table.entityResponseData?.id ?? ''}`, { + data: [ + { + op: 'add', + path: '/tags/0', + value: { + name: 'Tier2', + tagFQN: 'Tier.Tier2', + labelType: 'Manual', + state: 'Confirmed', + }, + }, + ], + headers: { + 'Content-Type': 'application/json-patch+json', + }, + }); + + await deleteKpiRequest(apiContext); + }); + + test.afterAll(async ({ browser }) => { + const { apiContext } = await createNewPage(browser); + + // await table.delete(apiContext); + }); + + test.beforeEach('Visit Data Insight Page', async ({ page }) => { + await redirectToHomePage(page); + await sidebarClick(page, SidebarItem.DATA_INSIGHT); + }); + + test('Create description and owner KPI', async ({ page }) => { + await page.getByRole('menuitem', { name: 'KPIs' }).click(); + + for (const data of KPI_DATA) { + await page.getByTestId('add-kpi-btn').click(); + + await addKpi(page, data); + } + }); + + test('Run DataInsight Application', async ({ page }) => { + await settingClick(page, GlobalSettingOptions.APPLICATIONS); + + const appDetails = page.waitForResponse( + '**/api/v1/apps/name/DataInsightsApplication?*' + ); + await page.click( + '[data-testid="data-insights-application-card"] [data-testid="config-btn"]' + ); + await appDetails; + + const triggerResponse = page.waitForResponse( + '**/api/v1/apps/trigger/DataInsightsApplication' + ); + await page.getByTestId('run-now-button').click(); + await triggerResponse; + + const { apiContext } = await getApiContext(page); + + await expect + .poll( + async () => { + const response = await apiContext + .get( + '/api/v1/apps/name/DataInsightsApplication/status?offset=0&limit=1' + ) + .then((res) => res.json()); + + return response.data[0].status; + }, + { + // Custom expect message for reporting, optional. + message: 'Wait for the pipeline to be successful', + timeout: 60_000, + intervals: [5_000, 10_000], + } + ) + .toBe('success'); + + // Verify KPI + + await sidebarClick(page, SidebarItem.DATA_INSIGHT); + + await page.waitForSelector('[data-testid="search-dropdown-Team"]'); + await page.waitForSelector('[data-testid="search-dropdown-Tier"]'); + await page.waitForSelector('[data-testid="summary-card"]'); + await page.waitForSelector('[data-testid="kpi-card"]'); + }); + + test('Verifying Data assets tab', async ({ page }) => { + await page.waitForResponse( + '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' + ); + await page.getByTestId('date-picker-menu').click(); + await page.getByRole('menuitem', { name: 'Last 60 days' }).click(); + + await expect(page.getByTestId('search-dropdown-Team')).toBeVisible(); + + await expect(page.getByTestId('search-dropdown-Tier')).toBeVisible(); + await expect(page.getByTestId('summary-card')).toBeVisible(); + await expect(page.getByTestId('kpi-card')).toBeVisible(); + await expect(page.getByTestId('total_data_assets-graph')).toBeVisible(); + await expect( + page.getByTestId('percentage_of_data_asset_with_description-graph') + ).toBeVisible(); + await expect( + page.getByTestId('percentage_of_data_asset_with_owner-graph') + ).toBeVisible(); + await expect( + page.getByTestId('percentage_of_service_with_description-graph') + ).toBeVisible(); + await expect( + page.getByTestId('percentage_of_service_with_owner-graph') + ).toBeVisible(); + await expect( + page.getByTestId('total_data_assets_by_tier-graph') + ).toBeVisible(); + }); + + test('Verify No owner and description redirection to explore page', async ({ + page, + }) => { + await page.waitForResponse( + '/api/v1/analytics/dataInsights/system/charts/name/percentage_of_service_with_description/data?**' + ); + await page.getByTestId('explore-asset-with-no-description').click(); + + await page.waitForURL('**/explore?**'); + + await expect(page.getByTestId('advance-search-filter-text')).toContainText( + "descriptionStatus = 'INCOMPLETE'" + ); + + await sidebarClick(page, SidebarItem.DATA_INSIGHT); + await page.waitForResponse( + '/api/v1/analytics/dataInsights/system/charts/name/percentage_of_service_with_description/data?**' + ); + + await page.getByTestId('explore-asset-with-no-owner').click(); + await page.waitForURL('**/explore?**'); + + await expect(page.getByTestId('advance-search-filter-text')).toContainText( + 'owners.displayName.keyword IS NULL' + ); + }); + + test('Verifying App analytics tab', async ({ page }) => { + await page.waitForResponse( + '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' + ); + await page.getByTestId('date-picker-menu').click(); + await page.getByRole('menuitem', { name: 'Last 60 days' }).click(); + + await page.getByRole('menuitem', { name: 'App Analytics' }).click(); + + await expect(page.getByTestId('summary-card-content')).toBeVisible(); + await expect( + page.locator('[data-testid="entity-summary-card-percentage"]', { + hasText: 'Most Viewed Data Assets', + }) + ).toBeVisible(); + await expect(page.getByTestId('entity-page-views-card')).toBeVisible(); + await expect(page.getByTestId('entity-active-user-card')).toBeVisible(); + await expect( + page.locator('[data-testid="entity-summary-card-percentage"]', { + hasText: 'Most Active Users', + }) + ).toBeVisible(); + }); + + test('Verifying KPI tab', async ({ page }) => { + await page.waitForResponse( + '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' + ); + + await page.getByTestId('date-picker-menu').click(); + await page.getByRole('menuitem', { name: 'Last 60 days' }).click(); + await page.getByRole('menuitem', { name: 'KPIs' }).click(); + + await expect(page.getByTestId('kpi-card')).toBeVisible(); + await expect( + page.locator( + '[data-row-key="playwright-description-with-percentage-percentage"]' + ) + ).toBeVisible(); + await expect( + page.locator( + '[data-row-key="playwright-owner-with-percentage-percentage"]' + ) + ).toBeVisible(); + }); + + test('Update KPI', async ({ page }) => { + await page.waitForResponse( + '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' + ); + await page.getByRole('menuitem', { name: 'KPIs' }).click(); + + for (const data of KPI_DATA) { + await page.getByTestId(`edit-action-${data.displayName}`).click(); + + await page.getByRole('spinbutton').fill('50'); + await page.getByTestId('submit-btn').click(); + } + }); + + test('Delete Kpi', async ({ page }) => { + await page.waitForResponse( + '/api/v1/kpi/playwright-owner-with-percentage-percentage/latestKpiResult' + ); + await page.getByRole('menuitem', { name: 'KPIs' }).click(); + + for (const data of KPI_DATA) { + await page.getByTestId(`delete-action-${data.displayName}`).click(); + await page.getByTestId('confirmation-text-input').type('DELETE'); + await page.getByTestId('confirm-button').click(); + } + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/dataInsight.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/dataInsight.ts new file mode 100644 index 00000000000..0771478cf60 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/dataInsight.ts @@ -0,0 +1,74 @@ +/* + * 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 { APIRequestContext, Page } from '@playwright/test'; +import { descriptionBox } from './common'; + +export const deleteKpiRequest = async (apiRequest: APIRequestContext) => { + const kpis = await apiRequest.get('/api/v1/kpi').then((res) => res.json()); + + if (kpis.data.length > 0) { + for (const element of kpis.data) { + await apiRequest.delete( + `/api/v1/kpi/${element.id}?hardDelete=true&recursive=false`, + (route) => { + route.fulfill({ + status: 200, + }); + } + ); + } + } +}; + +export const addKpi = async (page: Page, data) => { + const currentDate = new Date(); + const month = + currentDate.getMonth() + 1 < 10 + ? `0${currentDate.getMonth() + 1}` + : currentDate.getMonth() + 1; + const date = + currentDate.getDate() < 10 + ? `0${currentDate.getDate()}` + : currentDate.getDate(); + + const startDate = `${currentDate.getFullYear()}-${month}-${date}`; + currentDate.setDate(currentDate.getDate() + 1); + const nextMonth = + currentDate.getMonth() + 1 < 10 + ? `0${currentDate.getMonth() + 1}` + : currentDate.getMonth() + 1; + const nextDate = + currentDate.getDate() < 10 + ? `0${currentDate.getDate()}` + : currentDate.getDate(); + const endDate = `${currentDate.getFullYear()}-${nextMonth}-${nextDate}`; + + await page.click('#chartType'); + await page.click(`.ant-select-dropdown [title="${data.dataInsightChart}"]`); + await page.getByTestId('displayName').fill(data.displayName); + await page.getByTestId('metricType').click(); + await page.click(`.ant-select-dropdown [title="${data.metricType}"]`); + await page.locator('.ant-slider-mark-text', { hasText: '100%' }).click(); + + await page.getByTestId('start-date').click(); + await page.getByTestId('start-date').fill(startDate); + await page.getByTestId('start-date').press('Enter'); + await page.getByTestId('end-date').click(); + await page.getByTestId('end-date').fill(endDate); + await page.getByTestId('end-date').press('Enter'); + + await page.locator(descriptionBox).fill('Playwright KPI test description'); + + await page.getByTestId('submit-btn').click(); + await page.waitForURL('**/data-insights/kpi'); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/DataInsightChartCard.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/DataInsightChartCard.tsx index d0b25abcfc4..5cbb52ae927 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/DataInsightChartCard.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataInsight/DataInsightChartCard.tsx @@ -14,6 +14,7 @@ import { Button, Card, Col, Row } from 'antd'; import { AxiosError } from 'axios'; import { first, + get, groupBy, includes, last, @@ -40,7 +41,10 @@ import { GRAPH_HEIGHT, TOTAL_ENTITY_CHART_COLOR, } from '../../constants/DataInsight.constants'; -import { INCOMPLETE_DESCRIPTION_ADVANCE_SEARCH_FILTER } from '../../constants/explore.constants'; +import { + INCOMPLETE_DESCRIPTION_ADVANCE_SEARCH_FILTER, + NO_OWNER_ADVANCE_SEARCH_FILTER, +} from '../../constants/explore.constants'; import { SearchIndex } from '../../enums/search.enum'; import { DataInsightChart } from '../../generated/api/dataInsight/kpi/createKpiRequest'; @@ -157,32 +161,32 @@ export const DataInsightChartCard = ({ }, [kpi.data, type]); const totalValue = useMemo(() => { + let data = { results: [{ count: 0 }] }; switch (type) { case SystemChartType.TotalDataAssets: - return ( - entitiesSummary[SystemChartType.TotalDataAssetsSummaryCard] - ?.results[0].count ?? 0 - ); + data = entitiesSummary[SystemChartType.TotalDataAssetsSummaryCard]; + + break; + case SystemChartType.PercentageOfDataAssetWithDescription: case SystemChartType.PercentageOfServiceWithDescription: - return ( - entitiesSummary[SystemChartType.DataAssetsWithDescriptionSummaryCard] - ?.results[0].count ?? 0 - ); + data = + entitiesSummary[SystemChartType.DataAssetsWithDescriptionSummaryCard]; + + break; case SystemChartType.PercentageOfDataAssetWithOwner: case SystemChartType.PercentageOfServiceWithOwner: - return ( - entitiesSummary[SystemChartType.DataAssetsWithOwnerSummaryCard] - ?.results[0].count ?? 0 - ); + data = entitiesSummary[SystemChartType.DataAssetsWithOwnerSummaryCard]; + + break; case SystemChartType.TotalDataAssetsByTier: - return ( - entitiesSummary[SystemChartType.TotalDataAssetsWithTierSummaryCard] - ?.results[0].count ?? 0 - ); + data = + entitiesSummary[SystemChartType.TotalDataAssetsWithTierSummaryCard]; + + break; } - return 0; + return get(data, 'results.0.count', 0); }, [type, entitiesSummary]); const { t } = useTranslation(); @@ -247,10 +251,7 @@ export const DataInsightChartCard = ({ } return ( - + diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightProvider.tsx index 144bd9de99e..6913e94d15c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightProvider.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DataInsightPage/DataInsightProvider.tsx @@ -69,7 +69,7 @@ const DataInsightProvider = ({ children }: DataInsightProviderProps) => { selectedOptions: [], options: [], }); - const [entitiesChartsSummary, setEntitiesChartSummary] = useState< + const [entitiesChartsSummary, setEntitiesChartsSummary] = useState< Record >({} as Record); @@ -280,7 +280,7 @@ const DataInsightProvider = ({ children }: DataInsightProviderProps) => { }, tierTag: tier, entitiesSummary: entitiesChartsSummary, - updateEntitySummary: setEntitiesChartSummary, + updateEntitySummary: setEntitiesChartsSummary, }), [ handleTeamSearch, @@ -297,7 +297,7 @@ const DataInsightProvider = ({ children }: DataInsightProviderProps) => { teamsOptions, isTeamLoading, entitiesChartsSummary, - setEntitiesChartSummary, + setEntitiesChartsSummary, ] );