From cef958ec9d5d25bae1d83b90f75ba7c4b49dd8f2 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Tue, 19 Nov 2024 17:27:46 +0530 Subject: [PATCH 01/15] fix the tree state on edit glossary term --- .../GlossaryTermTab.component.tsx | 2 +- .../Glossary/GlossaryV1.component.tsx | 19 +++++++++++++-- .../resources/ui/src/utils/GlossaryUtils.tsx | 24 +++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx index 43865ecfd7d6..65990d3ee128 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx @@ -123,7 +123,7 @@ const GlossaryTermTab = ({ ); const [statusDropdownSelection, setStatusDropdownSelections] = useState< string[] - >(['Approved', 'Draft']); + >([Status.Approved, Status.Draft, Status.InReview]); const [selectedStatus, setSelectedStatus] = useState([ ...statusDropdownSelection, ]); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx index fcbe01ad3926..070d8f86bb95 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx @@ -41,6 +41,7 @@ import { patchGlossaryTerm, } from '../../rest/glossaryAPI'; import { getEntityDeleteMessage } from '../../utils/CommonUtils'; +import { updateGlossaryTermByFqn } from '../../utils/GlossaryUtils'; import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { showErrorToast } from '../../utils/ToastUtils'; import { useActivityFeedProvider } from '../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; @@ -97,7 +98,8 @@ const GlossaryV1 = ({ const [editMode, setEditMode] = useState(false); - const { activeGlossary, setGlossaryChildTerms } = useGlossaryStore(); + const { activeGlossary, glossaryChildTerms, setGlossaryChildTerms } = + useGlossaryStore(); const { id, fullyQualifiedName } = activeGlossary ?? {}; @@ -206,6 +208,17 @@ const GlossaryV1 = ({ setIsEditModalOpen(true); }; + const updateGlossaryTermInStore = (updatedTerm: GlossaryTerm) => { + const clonedTerms = cloneDeep(glossaryChildTerms); + const updatedGlossaryTerms = updateGlossaryTermByFqn( + clonedTerms, + updatedTerm.fullyQualifiedName ?? '', + updatedTerm as ModifiedGlossary + ); + + setGlossaryChildTerms(updatedGlossaryTerms); + }; + const updateGlossaryTerm = async ( currentData: GlossaryTerm, updatedData: GlossaryTerm @@ -217,8 +230,10 @@ const GlossaryV1 = ({ throw t('server.entity-updating-error', { entity: t('label.glossary-term'), }); + } else { + updateGlossaryTermInStore(response); + setIsEditModalOpen(false); } - onTermModalSuccess(); } catch (error) { if ( (error as AxiosError).response?.status === HTTP_STATUS_CODE.CONFLICT diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx index 177c2ab0a608..c2bfda868435 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.tsx @@ -163,6 +163,30 @@ export const getGlossaryBreadcrumbs = (fqn: string) => { return breadcrumbList; }; +export const updateGlossaryTermByFqn = ( + glossaryTerms: ModifiedGlossary[], + fqn: string, + newValue: ModifiedGlossary +): ModifiedGlossary[] => { + return glossaryTerms.map((term) => { + if (term.fullyQualifiedName === fqn) { + return newValue; + } + if (term.children) { + return { + ...term, + children: updateGlossaryTermByFqn( + term.children as ModifiedGlossary[], + fqn, + newValue + ), + }; + } + + return term; + }) as ModifiedGlossary[]; +}; + // This function finds and gives you the glossary term you're looking for. // You can then use this term or update its information in the Glossary or Term with it's reference created // Reference will only be created if withReference is true From 1416664193e76081bc3d8e6429748e46d713975f Mon Sep 17 00:00:00 2001 From: karanh37 Date: Wed, 20 Nov 2024 13:07:22 +0530 Subject: [PATCH 02/15] add playwright tests --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 243 ++++++++++-------- .../resources/ui/playwright/utils/glossary.ts | 31 +++ 2 files changed, 172 insertions(+), 102 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index f5c5fe15000f..dcdc9371ef45 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -61,6 +61,7 @@ import { selectActiveGlossaryTerm, selectColumns, toggleAllColumnsSelection, + updateGlossaryTermDataFromTree, validateGlossaryTerm, verifyAllColumns, verifyColumnsVisibility, @@ -85,120 +86,108 @@ test.describe('Glossary tests', () => { await afterAction(); }); - test.fixme( - 'Glossary & terms creation for reviewer as user', - async ({ browser }) => { - test.slow(true); - - const { page, afterAction, apiContext } = await performAdminLogin( - browser - ); - const { page: page1, afterAction: afterActionUser1 } = - await performUserLogin(browser, user1); - const glossary1 = new Glossary(); - glossary1.data.owners = [{ name: 'admin', type: 'user' }]; - glossary1.data.mutuallyExclusive = true; - glossary1.data.reviewers = [ - { name: `${user1.data.firstName}${user1.data.lastName}`, type: 'user' }, - ]; - glossary1.data.terms = [new GlossaryTerm(glossary1)]; - - await test.step('Create Glossary', async () => { - await sidebarClick(page, SidebarItem.GLOSSARY); - await createGlossary(page, glossary1.data, false); - await verifyGlossaryDetails(page, glossary1.data); - }); + test('Glossary & terms creation for reviewer as user', async ({ + browser, + }) => { + test.slow(true); - await test.step('Create Glossary Terms', async () => { - await sidebarClick(page, SidebarItem.GLOSSARY); - await createGlossaryTerms(page, glossary1.data); - }); + const { page, afterAction, apiContext } = await performAdminLogin(browser); + const { page: page1, afterAction: afterActionUser1 } = + await performUserLogin(browser, user1); + const glossary1 = new Glossary(); + glossary1.data.owners = [{ name: 'admin', type: 'user' }]; + glossary1.data.mutuallyExclusive = true; + glossary1.data.reviewers = [ + { name: `${user1.data.firstName}${user1.data.lastName}`, type: 'user' }, + ]; + glossary1.data.terms = [new GlossaryTerm(glossary1)]; - await test.step( - 'Approve Glossary Term from Glossary Listing for reviewer user', - async () => { - await redirectToHomePage(page1); - // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds - await page1.waitForTimeout(15000); - await sidebarClick(page1, SidebarItem.GLOSSARY); - await selectActiveGlossary(page1, glossary1.data.name); - - await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); - await redirectToHomePage(page1); - await sidebarClick(page1, SidebarItem.GLOSSARY); - await selectActiveGlossary(page1, glossary1.data.name); - await validateGlossaryTerm( - page1, - glossary1.data.terms[0].data, - 'Approved' - ); + await test.step('Create Glossary', async () => { + await sidebarClick(page, SidebarItem.GLOSSARY); + await createGlossary(page, glossary1.data, false); + await verifyGlossaryDetails(page, glossary1.data); + }); - await afterActionUser1(); - } - ); + await test.step('Create Glossary Terms', async () => { + await sidebarClick(page, SidebarItem.GLOSSARY); + await createGlossaryTerms(page, glossary1.data); + }); + + await test.step( + 'Approve Glossary Term from Glossary Listing for reviewer user', + async () => { + await redirectToHomePage(page1); + await sidebarClick(page1, SidebarItem.GLOSSARY); + await selectActiveGlossary(page1, glossary1.data.name); + + await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); + await redirectToHomePage(page1); + await sidebarClick(page1, SidebarItem.GLOSSARY); + await selectActiveGlossary(page1, glossary1.data.name); + await validateGlossaryTerm( + page1, + glossary1.data.terms[0].data, + 'Approved' + ); - await glossary1.delete(apiContext); - await afterAction(); - } - ); + await afterActionUser1(); + } + ); - test.fixme( - 'Glossary & terms creation for reviewer as team', - async ({ browser }) => { - test.slow(true); + await glossary1.delete(apiContext); + await afterAction(); + }); - const { page, afterAction, apiContext } = await performAdminLogin( - browser - ); - const { page: page1, afterAction: afterActionUser1 } = - await performUserLogin(browser, user2); + test('Glossary & terms creation for reviewer as team', async ({ + browser, + }) => { + test.slow(true); - const glossary2 = new Glossary(); - glossary2.data.owners = [{ name: 'admin', type: 'user' }]; - glossary2.data.reviewers = [ - { name: team.data.displayName, type: 'team' }, - ]; - glossary2.data.terms = [new GlossaryTerm(glossary2)]; + const { page, afterAction, apiContext } = await performAdminLogin(browser); + const { page: page1, afterAction: afterActionUser1 } = + await performUserLogin(browser, user2); - await test.step('Create Glossary', async () => { - await sidebarClick(page, SidebarItem.GLOSSARY); - await createGlossary(page, glossary2.data, false); - await verifyGlossaryDetails(page, glossary2.data); - }); + const glossary2 = new Glossary(); + glossary2.data.owners = [{ name: 'admin', type: 'user' }]; + glossary2.data.reviewers = [{ name: team.data.displayName, type: 'team' }]; + glossary2.data.terms = [new GlossaryTerm(glossary2)]; - await test.step('Create Glossary Terms', async () => { - await redirectToHomePage(page); - await sidebarClick(page, SidebarItem.GLOSSARY); - await createGlossaryTerms(page, glossary2.data); - }); + await test.step('Create Glossary', async () => { + await sidebarClick(page, SidebarItem.GLOSSARY); + await createGlossary(page, glossary2.data, false); + await verifyGlossaryDetails(page, glossary2.data); + }); - await test.step( - 'Approve Glossary Term from Glossary Listing for reviewer team', - async () => { - await redirectToHomePage(page1); - // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds - await page1.waitForTimeout(15000); - await sidebarClick(page1, SidebarItem.GLOSSARY); - await selectActiveGlossary(page1, glossary2.data.name); - await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); - - await redirectToHomePage(page1); - await sidebarClick(page1, SidebarItem.GLOSSARY); - await selectActiveGlossary(page1, glossary2.data.name); - await validateGlossaryTerm( - page1, - glossary2.data.terms[0].data, - 'Approved' - ); + await test.step('Create Glossary Terms', async () => { + await redirectToHomePage(page); + await sidebarClick(page, SidebarItem.GLOSSARY); + await createGlossaryTerms(page, glossary2.data); + }); + + await test.step( + 'Approve Glossary Term from Glossary Listing for reviewer team', + async () => { + await redirectToHomePage(page1); + await sidebarClick(page1, SidebarItem.GLOSSARY); + await selectActiveGlossary(page1, glossary2.data.name); + await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); + + await redirectToHomePage(page1); + await sidebarClick(page1, SidebarItem.GLOSSARY); + await selectActiveGlossary(page1, glossary2.data.name); + await validateGlossaryTerm( + page1, + glossary2.data.terms[0].data, + 'Approved' + ); - await afterActionUser1(); - } - ); + await afterActionUser1(); + } + ); - await glossary2.delete(apiContext); - await afterAction(); - } - ); + await glossary2.delete(apiContext); + await afterAction(); + }); test('Update Glossary and Glossary Term', async ({ browser }) => { test.slow(true); @@ -870,6 +859,7 @@ test.describe('Glossary tests', () => { } finally { await glossary1.delete(apiContext); await afterAction(); + await afterActionUser1(); } }); @@ -1063,6 +1053,55 @@ test.describe('Glossary tests', () => { } }); + test('Glossary Term Update in Glossary Page should persist tree', async ({ + browser, + }) => { + const { page, afterAction, apiContext } = await performAdminLogin(browser); + const glossary1 = new Glossary(); + const glossaryTerm1 = new GlossaryTerm(glossary1); + await glossary1.create(apiContext); + await glossaryTerm1.create(apiContext); + const glossaryTerm2 = new GlossaryTerm( + glossary1, + glossaryTerm1.responseData.fullyQualifiedName + ); + await glossaryTerm2.create(apiContext); + const glossaryTerm3 = new GlossaryTerm( + glossary1, + glossaryTerm2.responseData.fullyQualifiedName + ); + await glossaryTerm3.create(apiContext); + + try { + await sidebarClick(page, SidebarItem.GLOSSARY); + await selectActiveGlossary(page, glossary1.data.displayName); + await page.getByTestId('expand-collapse-all-button').click(); + + await expect( + page.getByRole('cell', { name: glossaryTerm1.data.displayName }) + ).toBeVisible(); + + await expect( + page.getByRole('cell', { name: glossaryTerm2.data.displayName }) + ).toBeVisible(); + + await expect( + page.getByRole('cell', { name: glossaryTerm3.data.displayName }) + ).toBeVisible(); + + await updateGlossaryTermDataFromTree( + page, + glossaryTerm2.responseData.fullyQualifiedName + ); + } finally { + await glossaryTerm3.delete(apiContext); + await glossaryTerm2.delete(apiContext); + await glossaryTerm1.delete(apiContext); + await glossary1.delete(apiContext); + await afterAction(); + } + }); + test.afterAll(async ({ browser }) => { const { afterAction, apiContext } = await performAdminLogin(browser); await user1.delete(apiContext); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index 22cba32b692d..d6dcff3db223 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -504,6 +504,37 @@ export const approveGlossaryTermTask = async ( await toastNotification(page, /Task resolved successfully/); }; +// Show the glossary term edit modal from glossary page tree. +// Update the description and verify the changes. +export const updateGlossaryTermDataFromTree = async ( + page: Page, + termFqn: string +) => { + // eslint-disable-next-line no-useless-escape + const escapedFqn = termFqn.replace(/\"/g, '\\"'); + const termRow = page.locator(`[data-row-key="${escapedFqn}"]`); + await termRow.getByTestId('edit-button').click(); + + await page.waitForSelector('[role="dialog"].edit-glossary-modal'); + + await expect( + page.locator('[role="dialog"].edit-glossary-modal') + ).toBeVisible(); + await expect(page.locator('.ant-modal-title')).toContainText( + 'Edit Glossary Term' + ); + + await page.locator(descriptionBox).fill('Updated description'); + + const glossaryTermResponse = page.waitForResponse('/api/v1/glossaryTerms/*'); + await page.getByTestId('save-glossary-term').click(); + await glossaryTermResponse; + + await expect( + termRow.getByRole('cell', { name: 'Updated description' }) + ).toBeVisible(); +}; + export const validateGlossaryTerm = async ( page: Page, term: GlossaryTermData, From 666689876694eb3cb7416ca6316ddbff0b9f8e77 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Wed, 20 Nov 2024 16:02:00 +0530 Subject: [PATCH 03/15] fix permission loading --- .../GlossaryDetails.component.tsx | 2 +- .../GlossaryTermTab.component.tsx | 32 +++++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryDetails/GlossaryDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryDetails/GlossaryDetails.component.tsx index 013b9e62d22a..470709b66484 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryDetails/GlossaryDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryDetails/GlossaryDetails.component.tsx @@ -270,7 +270,7 @@ const GlossaryDetails = ({ {getWidgetFromKeyInternal(widget)} )); - }, [tagsWidget, layout]); + }, [tagsWidget, layout, permissions, termsLoading]); const detailsContent = useMemo(() => { return ( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx index 65990d3ee128..090eb7e8c740 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx @@ -33,7 +33,7 @@ import { AxiosError } from 'axios'; import classNames from 'classnames'; import { compare } from 'fast-json-patch'; import { cloneDeep, isEmpty, isUndefined } from 'lodash'; -import React, { useCallback, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { useTranslation } from 'react-i18next'; @@ -114,6 +114,10 @@ const GlossaryTermTab = ({ const [isTableLoading, setIsTableLoading] = useState(false); const [isTableHovered, setIsTableHovered] = useState(false); const [expandedRowKeys, setExpandedRowKeys] = useState([]); + const listOfVisibleColumns = useMemo(() => { + return ['name', 'description', 'owners', 'status', 'new-term']; + }, []); + const [isStatusDropdownVisible, setIsStatusDropdownVisible] = useState(false); const statusOptions = useMemo( @@ -298,10 +302,6 @@ const GlossaryTermTab = ({ return data; }, [glossaryTerms, permissions]); - const listOfVisibleColumns = useMemo(() => { - return ['name', 'description', 'owners', 'status', 'new-term']; - }, []); - const defaultCheckedList = useMemo( () => columns.reduce( @@ -323,13 +323,7 @@ const GlossaryTermTab = ({ const [isDropdownVisible, setIsDropdownVisible] = useState(false); const [options, setOptions] = useState<{ value: string; label: string }[]>( - columns.reduce<{ value: string; label: string }[]>( - (acc, { key, title }) => - key !== 'name' - ? [...acc, { label: title as string, value: key as string }] - : acc, - [] - ) + [] ); const newColumns = useMemo(() => { @@ -353,7 +347,7 @@ const GlossaryTermTab = ({ return aIndex - bIndex; }), - [newColumns] + [options, newColumns] ); const handleColumnSelectionDropdownSave = useCallback(() => { @@ -785,6 +779,18 @@ const GlossaryTermTab = ({ return expandedRowKeys.length === expandableKeys.length; }, [expandedRowKeys, expandableKeys]); + useEffect(() => { + setOptions( + columns.reduce<{ value: string; label: string }[]>( + (acc, { key, title }) => + key !== 'name' + ? [...acc, { label: title as string, value: key as string }] + : acc, + [] + ) + ); + }, [columns]); + if (termsLoading) { return ; } From 2baa990943fb519bf48a61add2f31a8696fdf393 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Wed, 20 Nov 2024 18:45:31 +0530 Subject: [PATCH 04/15] fix tests --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 4 +++ .../GlossaryTermTab.component.tsx | 24 +++++--------- .../Glossary/GlossaryV1.component.tsx | 33 +++++++++++++------ 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index dcdc9371ef45..bbc0db2ecc4c 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -117,6 +117,8 @@ test.describe('Glossary tests', () => { 'Approve Glossary Term from Glossary Listing for reviewer user', async () => { await redirectToHomePage(page1); + // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds + await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); await selectActiveGlossary(page1, glossary1.data.name); @@ -168,6 +170,8 @@ test.describe('Glossary tests', () => { 'Approve Glossary Term from Glossary Listing for reviewer team', async () => { await redirectToHomePage(page1); + // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds + await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); await selectActiveGlossary(page1, glossary2.data.name); await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx index 090eb7e8c740..63954c347c6e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.component.tsx @@ -33,7 +33,7 @@ import { AxiosError } from 'axios'; import classNames from 'classnames'; import { compare } from 'fast-json-patch'; import { cloneDeep, isEmpty, isUndefined } from 'lodash'; -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { useTranslation } from 'react-i18next'; @@ -300,7 +300,7 @@ const GlossaryTermTab = ({ } return data; - }, [glossaryTerms, permissions]); + }, [permissions]); const defaultCheckedList = useMemo( () => @@ -323,7 +323,13 @@ const GlossaryTermTab = ({ const [isDropdownVisible, setIsDropdownVisible] = useState(false); const [options, setOptions] = useState<{ value: string; label: string }[]>( - [] + columns.reduce<{ value: string; label: string }[]>( + (acc, { key, title }) => + key !== 'name' + ? [...acc, { label: title as string, value: key as string }] + : acc, + [] + ) ); const newColumns = useMemo(() => { @@ -779,18 +785,6 @@ const GlossaryTermTab = ({ return expandedRowKeys.length === expandableKeys.length; }, [expandedRowKeys, expandableKeys]); - useEffect(() => { - setOptions( - columns.reduce<{ value: string; label: string }[]>( - (acc, { key, title }) => - key !== 'name' - ? [...acc, { label: title as string, value: key as string }] - : acc, - [] - ) - ); - }, [columns]); - if (termsLoading) { return ; } diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx index 070d8f86bb95..87ac05380160 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx @@ -85,6 +85,7 @@ const GlossaryV1 = ({ const { getEntityPermission } = usePermissionProvider(); const [isLoading, setIsLoading] = useState(true); const [isTermsLoading, setIsTermsLoading] = useState(false); + const [isPermissionLoading, setIsPermissionLoading] = useState(false); const [isDelete, setIsDelete] = useState(false); @@ -351,18 +352,29 @@ const GlossaryV1 = ({ shouldRefreshTerms && loadGlossaryTerms(true); }; - useEffect(() => { - if (id && !action) { - loadGlossaryTerms(); - if (isGlossaryActive) { - isVersionsView + const initPermissions = async () => { + setIsPermissionLoading(true); + const permissionFetch = isGlossaryActive + ? fetchGlossaryPermission + : fetchGlossaryTermPermission; + + try { + if (isVersionsView) { + isGlossaryActive ? setGlossaryPermission(VERSION_VIEW_GLOSSARY_PERMISSION) - : fetchGlossaryPermission(); + : setGlossaryTermPermission(VERSION_VIEW_GLOSSARY_PERMISSION); } else { - isVersionsView - ? setGlossaryTermPermission(VERSION_VIEW_GLOSSARY_PERMISSION) - : fetchGlossaryTermPermission(); + await permissionFetch(); } + } finally { + setIsPermissionLoading(false); + } + }; + + useEffect(() => { + if (id && !action) { + loadGlossaryTerms(); + initPermissions(); } }, [id, isGlossaryActive, isVersionsView, action]); @@ -370,8 +382,9 @@ const GlossaryV1 = ({ ) : ( <> - {isLoading && } + {(isLoading || isPermissionLoading) && } {!isLoading && + !isPermissionLoading && !isEmpty(selectedData) && (isGlossaryActive ? ( Date: Wed, 20 Nov 2024 20:37:53 +0530 Subject: [PATCH 05/15] adding timeout for in review state --- .../src/main/resources/ui/playwright/utils/glossary.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index d6dcff3db223..e0e4702491f5 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -549,8 +549,8 @@ export const validateGlossaryTerm = async ( await expect(page.locator(statusSelector)).toContainText(status); if (status === 'Draft') { - // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds - await page.waitForTimeout(15000); + // wait for 25 seconds as the flowable which creates task is triggered every 10 seconds + await page.waitForTimeout(25000); await validateGlossaryTermTask(page, term); await page.click('[data-testid="terms"]'); } From 3566a052db3b20e423a81f13e70a8c7c92153841 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Wed, 20 Nov 2024 20:44:39 +0530 Subject: [PATCH 06/15] adding timeout for in review state --- .../src/main/resources/ui/playwright/utils/glossary.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index e0e4702491f5..a49871a7cb23 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -470,7 +470,10 @@ export const fillGlossaryTermDetails = async ( }; const validateGlossaryTermTask = async (page: Page, term: GlossaryTermData) => { + const taskCountRes = page.waitForResponse('/api/v1/feed/count?*'); await page.click('[data-testid="activity_feed"]'); + await taskCountRes; + const taskFeeds = page.waitForResponse(TASK_OPEN_FETCH_LINK); await page .getByTestId('global-setting-left-panel') @@ -549,8 +552,8 @@ export const validateGlossaryTerm = async ( await expect(page.locator(statusSelector)).toContainText(status); if (status === 'Draft') { - // wait for 25 seconds as the flowable which creates task is triggered every 10 seconds - await page.waitForTimeout(25000); + // wait for 10 seconds as the flowable which creates task is triggered every 10 seconds + await page.waitForTimeout(10000); await validateGlossaryTermTask(page, term); await page.click('[data-testid="terms"]'); } From 817cce30bb874b55041a688b2ae1a03c4acbe30d Mon Sep 17 00:00:00 2001 From: karanh37 Date: Wed, 20 Nov 2024 22:21:22 +0530 Subject: [PATCH 07/15] increasing timeout --- .../src/main/resources/ui/playwright/utils/glossary.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index a49871a7cb23..a3e7fe9a75e9 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -552,8 +552,8 @@ export const validateGlossaryTerm = async ( await expect(page.locator(statusSelector)).toContainText(status); if (status === 'Draft') { - // wait for 10 seconds as the flowable which creates task is triggered every 10 seconds - await page.waitForTimeout(10000); + // wait for 20 seconds as the flowable which creates task is triggered every 10 seconds + await page.waitForTimeout(20000); await validateGlossaryTermTask(page, term); await page.click('[data-testid="terms"]'); } From 01af501493b210fe48f6b723653d46f0c48da581 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Thu, 21 Nov 2024 11:51:05 +0530 Subject: [PATCH 08/15] fix tests --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 10 +++++++++- .../main/resources/ui/playwright/utils/glossary.ts | 12 ++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index bbc0db2ecc4c..fe2fa0cc6192 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -63,6 +63,7 @@ import { toggleAllColumnsSelection, updateGlossaryTermDataFromTree, validateGlossaryTerm, + validateGlossaryTermTask, verifyAllColumns, verifyColumnsVisibility, verifyGlossaryDetails, @@ -120,8 +121,11 @@ test.describe('Glossary tests', () => { // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); - await selectActiveGlossary(page1, glossary1.data.name); + await validateGlossaryTermTask(page, glossary1.data.terms[0].data); + await page.click('[data-testid="terms"]'); + + await selectActiveGlossary(page1, glossary1.data.name); await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); await redirectToHomePage(page1); await sidebarClick(page1, SidebarItem.GLOSSARY); @@ -173,6 +177,10 @@ test.describe('Glossary tests', () => { // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); + + await validateGlossaryTermTask(page, glossary2.data.terms[0].data); + await page.click('[data-testid="terms"]'); + await selectActiveGlossary(page1, glossary2.data.name); await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index a3e7fe9a75e9..049e44c9c41a 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -469,7 +469,10 @@ export const fillGlossaryTermDetails = async ( } }; -const validateGlossaryTermTask = async (page: Page, term: GlossaryTermData) => { +export const validateGlossaryTermTask = async ( + page: Page, + term: GlossaryTermData +) => { const taskCountRes = page.waitForResponse('/api/v1/feed/count?*'); await page.click('[data-testid="activity_feed"]'); await taskCountRes; @@ -550,13 +553,6 @@ export const validateGlossaryTerm = async ( await expect(page.locator(termSelector)).toContainText(term.name); await expect(page.locator(statusSelector)).toContainText(status); - - if (status === 'Draft') { - // wait for 20 seconds as the flowable which creates task is triggered every 10 seconds - await page.waitForTimeout(20000); - await validateGlossaryTermTask(page, term); - await page.click('[data-testid="terms"]'); - } }; export const createGlossaryTerm = async ( From 109d95d37a3d822a1b55af3b39e6801047f70bbb Mon Sep 17 00:00:00 2001 From: karanh37 Date: Thu, 21 Nov 2024 13:27:49 +0530 Subject: [PATCH 09/15] update tests --- .../main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index fe2fa0cc6192..05fc6451579e 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -121,10 +121,6 @@ test.describe('Glossary tests', () => { // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); - - await validateGlossaryTermTask(page, glossary1.data.terms[0].data); - await page.click('[data-testid="terms"]'); - await selectActiveGlossary(page1, glossary1.data.name); await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); await redirectToHomePage(page1); From 7e7c6981c35753afaac4ebe515d47b6bfd0d63c5 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Fri, 22 Nov 2024 11:38:31 +0530 Subject: [PATCH 10/15] add a poll for checking tasks created --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 21 ++++++---- .../resources/ui/playwright/utils/glossary.ts | 39 +++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index 05fc6451579e..9113f3f09ffc 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -63,11 +63,11 @@ import { toggleAllColumnsSelection, updateGlossaryTermDataFromTree, validateGlossaryTerm, - validateGlossaryTermTask, verifyAllColumns, verifyColumnsVisibility, verifyGlossaryDetails, verifyGlossaryTermAssets, + verifyTaskCreated, } from '../../utils/glossary'; import { sidebarClick } from '../../utils/sidebar'; import { TaskDetails } from '../../utils/task'; @@ -118,10 +118,14 @@ test.describe('Glossary tests', () => { 'Approve Glossary Term from Glossary Listing for reviewer user', async () => { await redirectToHomePage(page1); - // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds - await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); await selectActiveGlossary(page1, glossary1.data.name); + await verifyTaskCreated( + page1, + glossary1.data.fullyQualifiedName, + glossary1.data.terms[0].data.name + ); + await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); await redirectToHomePage(page1); await sidebarClick(page1, SidebarItem.GLOSSARY); @@ -170,14 +174,15 @@ test.describe('Glossary tests', () => { 'Approve Glossary Term from Glossary Listing for reviewer team', async () => { await redirectToHomePage(page1); - // wait for 15 seconds as the flowable which creates task is triggered every 10 seconds - await page1.waitForTimeout(15000); await sidebarClick(page1, SidebarItem.GLOSSARY); + await selectActiveGlossary(page1, glossary2.data.name); - await validateGlossaryTermTask(page, glossary2.data.terms[0].data); - await page.click('[data-testid="terms"]'); + await verifyTaskCreated( + page1, + glossary2.data.fullyQualifiedName, + glossary2.data.terms[0].data.name + ); - await selectActiveGlossary(page1, glossary2.data.name); await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); await redirectToHomePage(page1); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index 049e44c9c41a..713f92af7976 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -37,6 +37,12 @@ import { addMultiOwner } from './entity'; import { sidebarClick } from './sidebar'; import { TaskDetails, TASK_OPEN_FETCH_LINK } from './task'; +type TaskEntity = { + entityRef: { + name: string; + }; +}; + const GLOSSARY_NAME_VALIDATION_ERROR = 'Name size must be between 1 and 128'; export const descriptionBox = @@ -469,6 +475,39 @@ export const fillGlossaryTermDetails = async ( } }; +export const verifyTaskCreated = async ( + page: Page, + glossaryFqn: string, + glossaryTermName: string +) => { + const { apiContext } = await getApiContext(page); + const entityLink = encodeURIComponent(`<#E::glossary::${glossaryFqn}>`); + + await expect + .poll( + async () => { + const response = await apiContext + .get( + `/api/v1/feed?entityLink=${entityLink}&type=Task&taskStatus=Open` + ) + .then((res) => res.json()); + + const arr = response.data.map( + (item: TaskEntity) => item.entityRef.name + ); + + return arr; + }, + { + // Custom expect message for reporting, optional. + message: 'To get the last run execution status as success', + timeout: 200_000, + intervals: [30_000], + } + ) + .toContain(glossaryTermName); +}; + export const validateGlossaryTermTask = async ( page: Page, term: GlossaryTermData From d0eaa52b5f9c5bd1b3818f83a3b9064119454c64 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Fri, 22 Nov 2024 16:34:03 +0530 Subject: [PATCH 11/15] testing response --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 4 +-- .../resources/ui/playwright/utils/glossary.ts | 33 +++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index 9113f3f09ffc..315879fc5cfa 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -123,7 +123,7 @@ test.describe('Glossary tests', () => { await verifyTaskCreated( page1, glossary1.data.fullyQualifiedName, - glossary1.data.terms[0].data.name + glossary1.data.terms[0].data ); await approveGlossaryTermTask(page1, glossary1.data.terms[0].data); @@ -180,7 +180,7 @@ test.describe('Glossary tests', () => { await verifyTaskCreated( page1, glossary2.data.fullyQualifiedName, - glossary2.data.terms[0].data.name + glossary2.data.terms[0].data ); await approveGlossaryTermTask(page1, glossary2.data.terms[0].data); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index 713f92af7976..5dcfe662aa94 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -478,9 +478,10 @@ export const fillGlossaryTermDetails = async ( export const verifyTaskCreated = async ( page: Page, glossaryFqn: string, - glossaryTermName: string + glossaryTermData: GlossaryTermData ) => { const { apiContext } = await getApiContext(page); + const decodedEntityLink = `<#E::glossaryTerm::${glossaryTermData.fullyQualifiedName}>`; const entityLink = encodeURIComponent(`<#E::glossary::${glossaryFqn}>`); await expect @@ -496,6 +497,34 @@ export const verifyTaskCreated = async ( (item: TaskEntity) => item.entityRef.name ); + // Testing the response + const endTs = new Date().getTime(); + const startTs = endTs - 10 * 60 * 1000; + + const workflowInstances = await apiContext + .get( + `/api/v1/governance/workflowInstances?startTs=${startTs}&endTs=${endTs}` + ) + .then((res) => res.json()); + + // eslint-disable-next-line no-console + console.log('workflowInstances', workflowInstances); + + const workflowInstanceId = (workflowInstances.data ?? []).find( + (item) => item.variables.relatedEntity === decodedEntityLink + )?.id; + + if (workflowInstanceId) { + const workflowInstanceDetails = await apiContext + .get( + `/api/v1/governance/workflowInstanceStates/GlossaryTermApprovalWorkflow/${workflowInstanceId}?startTs=${startTs}&endTs=${endTs}` + ) + .then((res) => res.json()); + + // eslint-disable-next-line no-console + console.log('workflowInstanceDetails', workflowInstanceDetails); + } + return arr; }, { @@ -505,7 +534,7 @@ export const verifyTaskCreated = async ( intervals: [30_000], } ) - .toContain(glossaryTermName); + .toContain(glossaryTermData.name); }; export const validateGlossaryTermTask = async ( From 4f461fd974951a6fef1ab4d48649565d9fe4d42d Mon Sep 17 00:00:00 2001 From: karanh37 Date: Fri, 22 Nov 2024 21:48:33 +0530 Subject: [PATCH 12/15] adding limit --- .../src/main/resources/ui/playwright/utils/glossary.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index 5dcfe662aa94..dc5b56d51d4b 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -503,7 +503,7 @@ export const verifyTaskCreated = async ( const workflowInstances = await apiContext .get( - `/api/v1/governance/workflowInstances?startTs=${startTs}&endTs=${endTs}` + `/api/v1/governance/workflowInstances?startTs=${startTs}&endTs=${endTs}&limit=25` ) .then((res) => res.json()); @@ -517,7 +517,7 @@ export const verifyTaskCreated = async ( if (workflowInstanceId) { const workflowInstanceDetails = await apiContext .get( - `/api/v1/governance/workflowInstanceStates/GlossaryTermApprovalWorkflow/${workflowInstanceId}?startTs=${startTs}&endTs=${endTs}` + `/api/v1/governance/workflowInstanceStates/GlossaryTermApprovalWorkflow/${workflowInstanceId}?startTs=${startTs}&endTs=${endTs}&limit=25` ) .then((res) => res.json()); From 107b852816e7ba64057566febfdabf0ce4879827 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Mon, 25 Nov 2024 13:14:59 +0530 Subject: [PATCH 13/15] fix tests --- .../ui/playwright/e2e/Pages/Glossary.spec.ts | 6 ++-- .../resources/ui/playwright/utils/glossary.ts | 29 ------------------- 2 files changed, 2 insertions(+), 33 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index 315879fc5cfa..13d143d03a79 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -791,9 +791,8 @@ test.describe('Glossary tests', () => { '[data-testid="viewer-container"]' ); - await expect(viewerContainerText).toContain('Updated description'); + expect(viewerContainerText).toContain('Updated description'); } finally { - await user1.delete(apiContext); await glossary1.delete(apiContext); await afterAction(); } @@ -838,9 +837,8 @@ test.describe('Glossary tests', () => { '[data-testid="viewer-container"]' ); - await expect(viewerContainerText).toContain('Updated description'); + expect(viewerContainerText).toContain('Updated description'); } finally { - await user1.delete(apiContext); await glossaryTerm1.delete(apiContext); await glossary1.delete(apiContext); await afterAction(); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts index dc5b56d51d4b..5505efe77efa 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/glossary.ts @@ -481,7 +481,6 @@ export const verifyTaskCreated = async ( glossaryTermData: GlossaryTermData ) => { const { apiContext } = await getApiContext(page); - const decodedEntityLink = `<#E::glossaryTerm::${glossaryTermData.fullyQualifiedName}>`; const entityLink = encodeURIComponent(`<#E::glossary::${glossaryFqn}>`); await expect @@ -497,34 +496,6 @@ export const verifyTaskCreated = async ( (item: TaskEntity) => item.entityRef.name ); - // Testing the response - const endTs = new Date().getTime(); - const startTs = endTs - 10 * 60 * 1000; - - const workflowInstances = await apiContext - .get( - `/api/v1/governance/workflowInstances?startTs=${startTs}&endTs=${endTs}&limit=25` - ) - .then((res) => res.json()); - - // eslint-disable-next-line no-console - console.log('workflowInstances', workflowInstances); - - const workflowInstanceId = (workflowInstances.data ?? []).find( - (item) => item.variables.relatedEntity === decodedEntityLink - )?.id; - - if (workflowInstanceId) { - const workflowInstanceDetails = await apiContext - .get( - `/api/v1/governance/workflowInstanceStates/GlossaryTermApprovalWorkflow/${workflowInstanceId}?startTs=${startTs}&endTs=${endTs}&limit=25` - ) - .then((res) => res.json()); - - // eslint-disable-next-line no-console - console.log('workflowInstanceDetails', workflowInstanceDetails); - } - return arr; }, { From 15c0acefd2943ba7dcfb9bdcb99702650df0cc03 Mon Sep 17 00:00:00 2001 From: karanh37 Date: Mon, 25 Nov 2024 17:20:27 +0530 Subject: [PATCH 14/15] change user for testing --- .../resources/ui/playwright/e2e/Pages/Glossary.spec.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts index 13d143d03a79..09ba8d8caac0 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/Glossary.spec.ts @@ -76,12 +76,14 @@ import { performUserLogin } from '../../utils/user'; const user1 = new UserClass(); const user2 = new UserClass(); const team = new TeamClass(); +const user3 = new UserClass(); test.describe('Glossary tests', () => { test.beforeAll(async ({ browser }) => { const { afterAction, apiContext } = await performAdminLogin(browser); await user2.create(apiContext); await user1.create(apiContext); + await user3.create(apiContext); team.data.users = [user2.responseData.id]; await team.create(apiContext); await afterAction(); @@ -94,12 +96,12 @@ test.describe('Glossary tests', () => { const { page, afterAction, apiContext } = await performAdminLogin(browser); const { page: page1, afterAction: afterActionUser1 } = - await performUserLogin(browser, user1); + await performUserLogin(browser, user3); const glossary1 = new Glossary(); glossary1.data.owners = [{ name: 'admin', type: 'user' }]; glossary1.data.mutuallyExclusive = true; glossary1.data.reviewers = [ - { name: `${user1.data.firstName}${user1.data.lastName}`, type: 'user' }, + { name: `${user3.data.firstName}${user3.data.lastName}`, type: 'user' }, ]; glossary1.data.terms = [new GlossaryTerm(glossary1)]; @@ -1117,6 +1119,7 @@ test.describe('Glossary tests', () => { const { afterAction, apiContext } = await performAdminLogin(browser); await user1.delete(apiContext); await user2.delete(apiContext); + await user3.create(apiContext); await team.delete(apiContext); await afterAction(); }); From 37c2530829e991de8e655a12ef311cb13166b5d8 Mon Sep 17 00:00:00 2001 From: Pablo Takara Date: Wed, 27 Nov 2024 19:20:02 +0100 Subject: [PATCH 15/15] Catch Exceptions on the Consumer to avoid losing records --- .../workflows/WorkflowEventConsumer.java | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowEventConsumer.java b/openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowEventConsumer.java index 8277275d7014..7cbc974a4d25 100644 --- a/openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowEventConsumer.java +++ b/openmetadata-service/src/main/java/org/openmetadata/service/governance/workflows/WorkflowEventConsumer.java @@ -1,9 +1,12 @@ package org.openmetadata.service.governance.workflows; +import static org.openmetadata.schema.entity.events.SubscriptionDestination.SubscriptionType.GOVERNANCE_WORKFLOW_CHANGE_EVENT; + import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Pair; import org.openmetadata.schema.entity.events.EventSubscription; import org.openmetadata.schema.entity.events.SubscriptionDestination; import org.openmetadata.schema.type.ChangeEvent; @@ -13,6 +16,7 @@ import org.openmetadata.service.Entity; import org.openmetadata.service.apps.bundles.changeEvent.Destination; import org.openmetadata.service.events.errors.EventPublisherException; +import org.openmetadata.service.exception.CatalogExceptionMessage; import org.openmetadata.service.resources.feeds.MessageParser; @Slf4j @@ -46,22 +50,33 @@ public WorkflowEventConsumer( @Override public void sendMessage(ChangeEvent event) throws EventPublisherException { // NOTE: We are only consuming ENTITY related events. - EventType eventType = event.getEventType(); - - if (validEventTypes.contains(eventType)) { - String signal = String.format("%s-%s", event.getEntityType(), eventType.toString()); - - EntityReference entityReference = - Entity.getEntityReferenceById(event.getEntityType(), event.getEntityId(), Include.ALL); - MessageParser.EntityLink entityLink = - new MessageParser.EntityLink( - event.getEntityType(), entityReference.getFullyQualifiedName()); - - Map variables = new HashMap<>(); - - variables.put("relatedEntity", entityLink.getLinkString()); - - WorkflowHandler.getInstance().triggerWithSignal(signal, variables); + try { + EventType eventType = event.getEventType(); + + if (validEventTypes.contains(eventType)) { + String signal = String.format("%s-%s", event.getEntityType(), eventType.toString()); + + EntityReference entityReference = + Entity.getEntityReferenceById(event.getEntityType(), event.getEntityId(), Include.ALL); + MessageParser.EntityLink entityLink = + new MessageParser.EntityLink( + event.getEntityType(), entityReference.getFullyQualifiedName()); + + Map variables = new HashMap<>(); + + variables.put("relatedEntity", entityLink.getLinkString()); + + WorkflowHandler.getInstance().triggerWithSignal(signal, variables); + } + } catch (Exception exc) { + String message = + CatalogExceptionMessage.eventPublisherFailedToPublish( + GOVERNANCE_WORKFLOW_CHANGE_EVENT, event, exc.getMessage()); + LOG.error(message); + throw new EventPublisherException( + CatalogExceptionMessage.eventPublisherFailedToPublish( + GOVERNANCE_WORKFLOW_CHANGE_EVENT, exc.getMessage()), + Pair.of(subscriptionDestination.getId(), event)); } }