mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-12 15:57:44 +00:00
* fix(ui): consider all the tags as tier which are children of Tier classification * add playwright * wip tier cleanup * fix async select list loading issue * address comments * update variable
This commit is contained in:
parent
166d9ef43d
commit
a034a979f1
@ -85,7 +85,11 @@ entities.forEach((EntityClass) => {
|
||||
});
|
||||
|
||||
test('Tier Add, Update and Remove', async ({ page }) => {
|
||||
await entity.tier(page, 'Tier1', 'Tier5');
|
||||
await entity.tier(
|
||||
page,
|
||||
'Tier1',
|
||||
EntityDataClass.tierTag1.data.displayName
|
||||
);
|
||||
});
|
||||
|
||||
test('Update description', async ({ page }) => {
|
||||
|
||||
@ -14,6 +14,7 @@ import { APIRequestContext } from '@playwright/test';
|
||||
import { Domain } from '../domain/Domain';
|
||||
import { Glossary } from '../glossary/Glossary';
|
||||
import { GlossaryTerm } from '../glossary/GlossaryTerm';
|
||||
import { TagClass } from '../tag/TagClass';
|
||||
import { TeamClass } from '../team/TeamClass';
|
||||
import { UserClass } from '../user/UserClass';
|
||||
|
||||
@ -28,6 +29,7 @@ export class EntityDataClass {
|
||||
static readonly user2 = new UserClass();
|
||||
static readonly team1 = new TeamClass();
|
||||
static readonly team2 = new TeamClass();
|
||||
static readonly tierTag1 = new TagClass({ classification: 'Tier' });
|
||||
|
||||
static async preRequisitesForTests(apiContext: APIRequestContext) {
|
||||
// Add pre-requisites for tests
|
||||
@ -41,6 +43,7 @@ export class EntityDataClass {
|
||||
await this.user2.create(apiContext);
|
||||
await this.team1.create(apiContext);
|
||||
await this.team2.create(apiContext);
|
||||
await this.tierTag1.create(apiContext);
|
||||
}
|
||||
|
||||
static async postRequisitesForTests(apiContext: APIRequestContext) {
|
||||
@ -54,5 +57,6 @@ export class EntityDataClass {
|
||||
await this.user2.delete(apiContext);
|
||||
await this.team1.delete(apiContext);
|
||||
await this.team2.delete(apiContext);
|
||||
await this.tierTag1.delete(apiContext);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 { visitClassificationPage } from '../../utils/tag';
|
||||
import { getRandomLastName } from '../../utils/user';
|
||||
|
||||
type ResponseDataType = {
|
||||
style?: {
|
||||
color: string;
|
||||
};
|
||||
description: string;
|
||||
displayName: string;
|
||||
classification: {
|
||||
id: string;
|
||||
type: 'classification';
|
||||
name: string;
|
||||
fullyQualifiedName: string;
|
||||
description: string;
|
||||
displayName: string;
|
||||
deleted: boolean;
|
||||
href: string;
|
||||
};
|
||||
name: string;
|
||||
id: string;
|
||||
fullyQualifiedName: string;
|
||||
};
|
||||
|
||||
export type TagData = {
|
||||
style?: {
|
||||
color: string;
|
||||
};
|
||||
description: string;
|
||||
displayName: string;
|
||||
classification: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export class TagClass {
|
||||
randomName = getRandomLastName();
|
||||
data: TagData = {
|
||||
name: `pw-tier-${this.randomName}`,
|
||||
displayName: `PW Tier ${this.randomName}`,
|
||||
description: 'Tier tag for the Collate platform',
|
||||
style: {
|
||||
color: '#FFD700',
|
||||
},
|
||||
classification: 'Tier',
|
||||
};
|
||||
|
||||
responseData: ResponseDataType;
|
||||
|
||||
constructor(tag: Partial<TagData>) {
|
||||
this.data.classification = tag.classification ?? this.data.classification;
|
||||
}
|
||||
|
||||
async visitPage(page: Page) {
|
||||
await visitClassificationPage(
|
||||
page,
|
||||
this.responseData.classification.displayName
|
||||
);
|
||||
}
|
||||
|
||||
async create(apiContext: APIRequestContext) {
|
||||
const response = await apiContext.post('/api/v1/tags', {
|
||||
data: this.data,
|
||||
});
|
||||
|
||||
this.responseData = await response.json();
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
get() {
|
||||
return this.responseData;
|
||||
}
|
||||
|
||||
async delete(apiContext: APIRequestContext) {
|
||||
const response = await apiContext.delete(
|
||||
`/api/v1/tags/${this.responseData.id}?recursive=true&hardDelete=true`
|
||||
);
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 { Page } from '@playwright/test';
|
||||
import { SidebarItem } from '../constant/sidebar';
|
||||
import { redirectToHomePage } from './common';
|
||||
import { sidebarClick } from './sidebar';
|
||||
|
||||
export const visitClassificationPage = async (
|
||||
page: Page,
|
||||
classificationName: string
|
||||
) => {
|
||||
await redirectToHomePage(page);
|
||||
const classificationResponse = page.waitForResponse(
|
||||
'/api/v1/classifications?**'
|
||||
);
|
||||
await sidebarClick(page, SidebarItem.TAGS);
|
||||
await classificationResponse;
|
||||
await page.getByRole('menuitem', { name: classificationName }).click();
|
||||
};
|
||||
@ -122,7 +122,7 @@ const AsyncSelectList: FC<AsyncSelectListProps & SelectProps> = ({
|
||||
|
||||
const tagOptions = useMemo(() => {
|
||||
const newTags = options
|
||||
.filter((tag) => !tag.label?.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`)) // To filter out Tier tags
|
||||
.filter((tag) => !tag.label?.startsWith(`Tier${FQN_SEPARATOR_CHAR}`)) // To filter out Tier tags
|
||||
.map((tag) => {
|
||||
const displayName = tag.data?.displayName;
|
||||
const parts = Fqn.split(tag.label);
|
||||
|
||||
@ -688,13 +688,13 @@ export const getEntityIdArray = (entities: EntityReference[]): string[] =>
|
||||
|
||||
export const getTagValue = (tag: string | TagLabel): string | TagLabel => {
|
||||
if (isString(tag)) {
|
||||
return tag.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`)
|
||||
return tag.startsWith(`Tier${FQN_SEPARATOR_CHAR}`)
|
||||
? tag.split(FQN_SEPARATOR_CHAR)[1]
|
||||
: tag;
|
||||
} else {
|
||||
return {
|
||||
...tag,
|
||||
tagFQN: tag.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`)
|
||||
tagFQN: tag.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}`)
|
||||
? tag.tagFQN.split(FQN_SEPARATOR_CHAR)[1]
|
||||
: tag.tagFQN,
|
||||
};
|
||||
|
||||
@ -135,7 +135,7 @@ import { stringToHTML } from './StringsUtils';
|
||||
import {
|
||||
getDataTypeString,
|
||||
getTagsWithoutTier,
|
||||
getTierFromTableTags,
|
||||
getTierTags,
|
||||
getUsagePercentile,
|
||||
} from './TableUtils';
|
||||
import { getTableTags } from './TagsUtils';
|
||||
@ -217,7 +217,7 @@ const getTableFieldsFromTableDetails = (tableDetails: Table) => {
|
||||
const databaseDisplayName = getEntityName(database) || databaseName;
|
||||
const schemaDisplayName = getEntityName(databaseSchema) || schemaName;
|
||||
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
return {
|
||||
fullyQualifiedName,
|
||||
@ -301,7 +301,7 @@ const getTableOverview = (tableDetails: Table) => {
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.lineage],
|
||||
},
|
||||
@ -343,7 +343,7 @@ const getTableOverview = (tableDetails: Table) => {
|
||||
|
||||
const getPipelineOverview = (pipelineDetails: Pipeline) => {
|
||||
const { owner, tags, sourceUrl, service, displayName } = pipelineDetails;
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
const serviceDisplayName = getEntityName(service);
|
||||
|
||||
const overview = [
|
||||
@ -381,7 +381,7 @@ const getPipelineOverview = (pipelineDetails: Pipeline) => {
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.lineage],
|
||||
},
|
||||
@ -393,7 +393,7 @@ const getPipelineOverview = (pipelineDetails: Pipeline) => {
|
||||
const getDashboardOverview = (dashboardDetails: Dashboard) => {
|
||||
const { owner, tags, sourceUrl, service, displayName, project } =
|
||||
dashboardDetails;
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
const serviceDisplayName = getEntityName(service);
|
||||
|
||||
const overview = [
|
||||
@ -430,7 +430,7 @@ const getDashboardOverview = (dashboardDetails: Dashboard) => {
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
isExternal: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.lineage],
|
||||
@ -453,7 +453,7 @@ export const getSearchIndexOverview = (
|
||||
searchIndexDetails: SearchIndexEntity
|
||||
) => {
|
||||
const { owner, tags, service } = searchIndexDetails;
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -465,7 +465,7 @@ export const getSearchIndexOverview = (
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
isExternal: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.lineage],
|
||||
@ -591,7 +591,7 @@ const getDataModelOverview = (dataModelDetails: DashboardDataModel) => {
|
||||
dataModelType,
|
||||
fullyQualifiedName,
|
||||
} = dataModelDetails;
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -633,7 +633,7 @@ const getDataModelOverview = (dataModelDetails: DashboardDataModel) => {
|
||||
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
isExternal: false,
|
||||
visible: [
|
||||
@ -667,7 +667,7 @@ const getStoredProcedureOverview = (
|
||||
FQN_SEPARATOR_CHAR
|
||||
).split(FQN_SEPARATOR_CHAR);
|
||||
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -717,7 +717,7 @@ const getStoredProcedureOverview = (
|
||||
},
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [
|
||||
DRAWER_NAVIGATION_OPTIONS.lineage,
|
||||
@ -747,7 +747,7 @@ const getStoredProcedureOverview = (
|
||||
const getDatabaseOverview = (databaseDetails: Database) => {
|
||||
const { owner, service, tags, usageSummary } = databaseDetails;
|
||||
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -760,7 +760,7 @@ const getDatabaseOverview = (databaseDetails: Database) => {
|
||||
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.explore],
|
||||
},
|
||||
@ -790,7 +790,7 @@ const getDatabaseSchemaOverview = (databaseSchemaDetails: DatabaseSchema) => {
|
||||
const { owner, service, tags, usageSummary, database } =
|
||||
databaseSchemaDetails;
|
||||
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -803,7 +803,7 @@ const getDatabaseSchemaOverview = (databaseSchemaDetails: DatabaseSchema) => {
|
||||
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.explore],
|
||||
},
|
||||
@ -841,7 +841,7 @@ const getDatabaseSchemaOverview = (databaseSchemaDetails: DatabaseSchema) => {
|
||||
const getEntityServiceOverview = (serviceDetails: EntityServiceUnion) => {
|
||||
const { owner, tags, serviceType } = serviceDetails;
|
||||
|
||||
const tier = getTierFromTableTags(tags ?? []);
|
||||
const tier = getTierTags(tags ?? []);
|
||||
|
||||
const overview = [
|
||||
{
|
||||
@ -854,7 +854,7 @@ const getEntityServiceOverview = (serviceDetails: EntityServiceUnion) => {
|
||||
|
||||
{
|
||||
name: i18next.t('label.tier'),
|
||||
value: tier ? tier.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
value: tier ? tier.tagFQN.split(FQN_SEPARATOR_CHAR)[1] : NO_DATA,
|
||||
isLink: false,
|
||||
visible: [DRAWER_NAVIGATION_OPTIONS.explore],
|
||||
},
|
||||
|
||||
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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 { TagLabel } from '../generated/entity/data/container';
|
||||
import { getTagsWithoutTier, getTierTags } from '../utils/TableUtils';
|
||||
|
||||
describe('TableUtils', () => {
|
||||
it('getTierTags should return the correct usage percentile', () => {
|
||||
const tags = [
|
||||
{ tagFQN: 'Tier.Tier1' },
|
||||
{ tagFQN: 'RandomTag' },
|
||||
{ tagFQN: 'OtherTag' },
|
||||
] as TagLabel[];
|
||||
const result = getTierTags(tags);
|
||||
|
||||
expect(result).toStrictEqual({ tagFQN: 'Tier.Tier1' });
|
||||
});
|
||||
|
||||
it('getTagsWithoutTier should return the tier tag FQN', () => {
|
||||
const tags = [
|
||||
{ tagFQN: 'Tier.Gold' },
|
||||
{ tagFQN: 'RandomTag' },
|
||||
{ tagFQN: 'OtherTag' },
|
||||
];
|
||||
const result = getTagsWithoutTier(tags);
|
||||
|
||||
expect(result).toStrictEqual([
|
||||
{ tagFQN: 'RandomTag' },
|
||||
{ tagFQN: 'OtherTag' },
|
||||
]);
|
||||
});
|
||||
|
||||
// Add more tests for other functions in TableUtils...
|
||||
});
|
||||
@ -103,23 +103,9 @@ export const getUsagePercentile = (pctRank: number, isLiteral = false) => {
|
||||
return usagePercentile;
|
||||
};
|
||||
|
||||
export const getTierFromTableTags = (
|
||||
tags: Array<EntityTags>
|
||||
): EntityTags['tagFQN'] => {
|
||||
const tierTag = tags.find(
|
||||
(item) =>
|
||||
item.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`) &&
|
||||
!isNaN(parseInt(item.tagFQN.substring(9).trim()))
|
||||
);
|
||||
|
||||
return tierTag?.tagFQN || '';
|
||||
};
|
||||
|
||||
export const getTierTags = (tags: Array<TagLabel>) => {
|
||||
const tierTag = tags.find(
|
||||
(item) =>
|
||||
item.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`) &&
|
||||
!isNaN(parseInt(item.tagFQN.substring(9).trim()))
|
||||
const tierTag = tags.find((item) =>
|
||||
item.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}`)
|
||||
);
|
||||
|
||||
return tierTag;
|
||||
@ -129,9 +115,7 @@ export const getTagsWithoutTier = (
|
||||
tags: Array<EntityTags>
|
||||
): Array<EntityTags> => {
|
||||
return tags.filter(
|
||||
(item) =>
|
||||
!item.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`) ||
|
||||
isNaN(parseInt(item.tagFQN.substring(9).trim()))
|
||||
(item) => !item.tagFQN.startsWith(`Tier${FQN_SEPARATOR_CHAR}`)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user