From c1fef32b157a7364b9b64cf1a34404da3ddace67 Mon Sep 17 00:00:00 2001 From: Pranita Fulsundar Date: Mon, 2 Jun 2025 09:54:22 +0530 Subject: [PATCH] fix(ui): pagination limit for dashboards (#21466) * fix: pagination limit for dashboards * add e2e test * refactor: address pr comments (cherry picked from commit f4720e0cb7921e1c8b518d748dc84a7440d704d5) --- .../e2e/Features/Dashboards.spec.ts | 82 +++++++++++++++++++ .../entity/service/DashboardServiceClass.ts | 56 ++++++++++++- .../resources/ui/playwright/utils/entity.ts | 12 +++ .../resources/ui/src/rest/dashboardAPI.ts | 2 +- 4 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Dashboards.spec.ts diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Dashboards.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Dashboards.spec.ts new file mode 100644 index 00000000000..81d3c2668ab --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Dashboards.spec.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2025 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 { DashboardServiceClass } from '../../support/entity/service/DashboardServiceClass'; +import { createNewPage, redirectToHomePage } from '../../utils/common'; +import { generateEntityChildren } from '../../utils/entity'; + +// use the admin user to login +test.use({ storageState: 'playwright/.auth/admin.json' }); + +const dashboardEntity = new DashboardServiceClass(); + +test.slow(true); + +test.describe('Dashboards', () => { + test.beforeAll('Setup pre-requests', async ({ browser }) => { + const { apiContext, afterAction } = await createNewPage(browser); + + const dashboardChildren = generateEntityChildren('dashboard', 25); + + await dashboardEntity.create(apiContext, dashboardChildren); + + await afterAction(); + }); + + test.afterAll('Clean up', async ({ browser }) => { + const { afterAction, apiContext } = await createNewPage(browser); + + await dashboardEntity.delete(apiContext); + await afterAction(); + }); + + test.beforeEach('Visit home page', async ({ page }) => { + await redirectToHomePage(page); + }); + + test(`should change the page size`, async ({ page }) => { + await dashboardEntity.visitEntityPage(page); + + await page.getByRole('tab', { name: 'Dashboards' }).click(); + + await page.waitForSelector('.ant-spin', { + state: 'detached', + }); + + await expect(page.getByTestId('pagination')).toBeVisible(); + await expect(page.getByTestId('previous')).toBeDisabled(); + await expect(page.getByTestId('page-indicator')).toContainText( + 'Page 1 of 2 ' + ); + + // Check the page sizing change + const childrenResponse = page.waitForResponse( + (res) => + res.url().includes('/api/v1/dashboards') && + res.url().includes('limit=25') + ); + await page.getByTestId('page-size-selection-dropdown').click(); + await page.getByText('25 / Page').click(); + await childrenResponse; + + await page.waitForSelector('.ant-spin', { + state: 'detached', + }); + + await expect(page.getByTestId('next')).toBeDisabled(); + await expect(page.getByTestId('previous')).toBeDisabled(); + await expect(page.getByTestId('page-indicator')).toContainText( + 'Page 1 of 1' + ); + }); +}); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DashboardServiceClass.ts b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DashboardServiceClass.ts index 01aca3101dd..fc42674c267 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DashboardServiceClass.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/support/entity/service/DashboardServiceClass.ts @@ -12,6 +12,7 @@ */ import { APIRequestContext, Page } from '@playwright/test'; import { Operation } from 'fast-json-patch'; +import { isUndefined } from 'lodash'; import { SERVICE_TYPE } from '../../../constant/service'; import { uuid } from '../../../utils/common'; import { visitServiceDetailsPage } from '../../../utils/service'; @@ -35,8 +36,14 @@ export class DashboardServiceClass extends EntityClass { }, }, }; + childEntity = { + name: `pw-dashboard-${uuid()}`, + displayName: `pw-dashboard-${uuid()}`, + service: this.entity.name, + }; entityResponseData: ResponseDataType = {} as ResponseDataType; + childrenArrayResponseData: ResponseDataType[] = []; constructor(name?: string) { super(EntityTypeEndpoint.DashboardService); @@ -44,7 +51,21 @@ export class DashboardServiceClass extends EntityClass { this.type = 'Dashboard Service'; } - async create(apiContext: APIRequestContext) { + private async createDashboardChild( + apiContext: APIRequestContext, + dashboardData: { name: string; displayName: string; service: string } + ): Promise { + const response = await apiContext.post('/api/v1/dashboards', { + data: dashboardData, + }); + + return await response.json(); + } + + async create( + apiContext: APIRequestContext, + customChildDashboards?: { name: string; displayName: string }[] + ) { const serviceResponse = await apiContext.post( '/api/v1/services/dashboardServices', { @@ -56,7 +77,38 @@ export class DashboardServiceClass extends EntityClass { this.entityResponseData = service; - return service; + const childDashboardResponseData: ResponseDataType[] = []; + + if (!isUndefined(customChildDashboards)) { + for (const child of customChildDashboards) { + const childDashboard = { + ...child, + service: this.entity.name, + }; + + const responseData = await this.createDashboardChild( + apiContext, + childDashboard + ); + childDashboardResponseData.push(responseData); + } + } else { + const childDashboard = { + ...this.childEntity, + }; + const responseData = await this.createDashboardChild( + apiContext, + childDashboard + ); + childDashboardResponseData.push(responseData); + } + + this.childrenArrayResponseData = childDashboardResponseData; + + return { + service, + children: this.childrenArrayResponseData, + }; } async patch(apiContext: APIRequestContext, payload: Operation[]) { diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts index 3fd700b2b72..148f73a0d2e 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts @@ -25,6 +25,7 @@ import { descriptionBox, redirectToHomePage, toastNotification, + uuid, } from './common'; import { customFormatDateTime, @@ -1422,3 +1423,14 @@ export const getFirstRowColumnLink = (page: Page) => { .locator('[data-testid="column-name"] a') .first(); }; + +export const generateEntityChildren = (entityName: string, count = 25) => { + return Array.from({ length: count }, (_, i) => { + const id = uuid(); + + return { + name: `pw-${entityName}-${i + 1}-${id}`, + displayName: `pw-${entityName}-${i + 1}-${id}`, + }; + }); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/rest/dashboardAPI.ts b/openmetadata-ui/src/main/resources/ui/src/rest/dashboardAPI.ts index d1ae7be12a6..df16646dce1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/rest/dashboardAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/rest/dashboardAPI.ts @@ -69,9 +69,9 @@ export const getDashboards = async ( params: { service, fields, + limit, ...paging, include, - limit, }, });