fix(ui): alphabetical sort order support for display name (#21745)

* add sort order support for display name

* fix table sorting field for name

* add tests

* refactor code

* add test for all entities

* minor fix

* fix sorting logic to match with ES behaviour

* fix test

* minor fix

* fix flakyness
This commit is contained in:
Pranita Fulsundar 2025-06-27 20:21:54 +05:30 committed by GitHub
parent d36878409a
commit d1b12650e3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 130 additions and 3 deletions

View File

@ -28,3 +28,22 @@ export const EXPECTED_BUCKETS = [
'searchIndex',
'mlmodel',
];
export const DATA_ASSETS = [
{ name: 'Table', filter: 'table' },
{ name: 'Database', filter: 'database' },
{ name: 'Database Schema', filter: 'databaseSchema' },
{ name: 'Dashboard', filter: 'dashboard' },
{ name: 'Dashboard Data Model', filter: 'dashboardDataModel' },
{ name: 'Pipeline', filter: 'pipeline' },
{ name: 'Topic', filter: 'topic' },
{ name: 'ML Model', filter: 'mlmodel' },
{ name: 'Container', filter: 'container' },
{ name: 'Search Index', filter: 'searchIndex' },
{ name: 'API Endpoint', filter: 'apiEndpoint' },
{ name: 'API Collection', filter: 'apiCollection' },
{ name: 'Stored Procedure', filter: 'storedProcedure' },
{ name: 'Glossary Term', filter: 'glossaryTerm' },
{ name: 'Tags', filter: 'tag' },
{ name: 'Metrics', filter: 'metric' },
];

View File

@ -0,0 +1,68 @@
/*
* 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 } from '@playwright/test';
import { DATA_ASSETS } from '../../constant/explore';
import { SidebarItem } from '../../constant/sidebar';
import { EntityDataClass } from '../../support/entity/EntityDataClass';
import { performAdminLogin } from '../../utils/admin';
import { redirectToHomePage } from '../../utils/common';
import { selectSortOrder, verifyEntitiesAreSorted } from '../../utils/explore';
import { sidebarClick } from '../../utils/sidebar';
test.describe('Explore Sort Order Filter', () => {
test.beforeAll('Setup pre-requests', async ({ browser }) => {
test.slow(true);
const { apiContext, afterAction } = await performAdminLogin(browser);
await EntityDataClass.preRequisitesForTests(apiContext);
await afterAction();
});
test.afterAll('Cleanup', async ({ browser }) => {
test.slow(true);
const { apiContext, afterAction } = await performAdminLogin(browser);
await EntityDataClass.postRequisitesForTests(apiContext);
await afterAction();
});
DATA_ASSETS.forEach(({ name, filter }) => {
test(`${name}`, async ({ browser }) => {
test.slow(true);
const { page, afterAction } = await performAdminLogin(browser);
await redirectToHomePage(page);
await sidebarClick(page, SidebarItem.EXPLORE);
await page.waitForLoadState('networkidle');
await page.getByRole('button', { name: 'Data Assets' }).click();
await page.waitForSelector(
'data-testid="drop-down-menu" data-testid="loader"',
{
state: 'detached',
}
);
await page.getByTestId(`${filter}-checkbox`).check();
await page.getByTestId('update-btn').click();
await selectSortOrder(page, 'Name');
await verifyEntitiesAreSorted(page);
await afterAction();
});
});
});

View File

@ -27,6 +27,7 @@ import { DashboardDataModelClass } from './DashboardDataModelClass';
import { DatabaseClass } from './DatabaseClass';
import { DatabaseSchemaClass } from './DatabaseSchemaClass';
import { EntityDataClassCreationConfig } from './EntityDataClass.interface';
import { MetricClass } from './MetricClass';
import { MlModelClass } from './MlModelClass';
import { PipelineClass } from './PipelineClass';
import { SearchIndexClass } from './SearchIndexClass';
@ -104,6 +105,7 @@ export class EntityDataClass {
static readonly dataProduct1 = new DataProduct(this.domain1);
static readonly dataProduct2 = new DataProduct(this.domain1);
static readonly dataProduct3 = new DataProduct(this.domain2);
static readonly metric1 = new MetricClass();
static async preRequisitesForTests(
apiContext: APIRequestContext,
@ -129,6 +131,7 @@ export class EntityDataClass {
this.certificationTag1.create(apiContext),
this.certificationTag2.create(apiContext),
this.classification1.create(apiContext),
this.metric1.create(apiContext),
]
: [];
@ -249,6 +252,7 @@ export class EntityDataClass {
this.dataProduct1.delete(apiContext),
this.dataProduct2.delete(apiContext),
this.dataProduct3.delete(apiContext),
this.metric1.delete(apiContext),
]
: [];

View File

@ -154,3 +154,39 @@ export const validateBucketsForIndex = async (page: Page, index: string) => {
).toBeGreaterThan(0);
});
};
export const selectSortOrder = async (page: Page, sortOrder: string) => {
await page.waitForSelector('[data-testid="loader"]', { state: 'detached' });
await page.getByTestId('sorting-dropdown-label').click();
await page.waitForSelector(`role=menuitem[name="${sortOrder}"]`, {
state: 'visible',
});
await page.getByRole('menuitem', { name: sortOrder }).click();
await expect(page.getByTestId('sorting-dropdown-label')).toHaveText(
sortOrder
);
await page.getByTestId('sort-order-button').click();
await page.waitForSelector('[data-testid="loader"]', { state: 'detached' });
};
export const verifyEntitiesAreSorted = async (page: Page) => {
const entityNames = await page.$$eval(
'[data-testid="search-results"] .explore-search-card [data-testid="entity-link"]',
(elements) => elements.map((el) => el.textContent?.trim() ?? '')
);
// Normalize for case insensitivity, but retain punctuation
const normalize = (str: string) => str.toLowerCase().trim();
// Sort using ASCII-based string comparison (ES behavior)
const sortedEntityNames = [...entityNames].sort((a, b) => {
const normA = normalize(a);
const normB = normalize(b);
return normA < normB ? -1 : normA > normB ? 1 : 0;
});
expect(entityNames).toEqual(sortedEntityNames);
};

View File

@ -45,7 +45,7 @@ export const tableSortingFields: SortingField[] = [
},
{
name: i18n.t('label.name'),
value: 'name.keyword',
value: 'displayName.keyword',
},
{
name: i18n.t('label.weekly-usage'),
@ -65,7 +65,7 @@ export const entitySortingFields = [
},
{
name: i18n.t('label.name'),
value: 'name.keyword',
value: 'displayName.keyword',
},
{ name: i18n.t('label.relevance'), value: '_score' },
{
@ -77,7 +77,7 @@ export const entitySortingFields = [
export const tagSortingFields = [
{
name: i18n.t('label.name'),
value: 'name.keyword',
value: 'displayName.keyword',
},
{ name: i18n.t('label.relevance'), value: '_score' },
{