mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-08 06:53:11 +00:00
* glossary import optimization around files under BulkImportPage * fix unit test * fix the special character glossary breaking for import * supported bulk edit in glossary page * added playwright test
This commit is contained in:
parent
6f5a3afac5
commit
96e07e7ce0
@ -16,6 +16,8 @@ import { SERVICE_TYPE } from '../../constant/service';
|
|||||||
import { GlobalSettingOptions } from '../../constant/settings';
|
import { GlobalSettingOptions } from '../../constant/settings';
|
||||||
import { EntityDataClass } from '../../support/entity/EntityDataClass';
|
import { EntityDataClass } from '../../support/entity/EntityDataClass';
|
||||||
import { TableClass } from '../../support/entity/TableClass';
|
import { TableClass } from '../../support/entity/TableClass';
|
||||||
|
import { Glossary } from '../../support/glossary/Glossary';
|
||||||
|
import { GlossaryTerm } from '../../support/glossary/GlossaryTerm';
|
||||||
import {
|
import {
|
||||||
createNewPage,
|
createNewPage,
|
||||||
descriptionBoxReadOnly,
|
descriptionBoxReadOnly,
|
||||||
@ -23,13 +25,16 @@ import {
|
|||||||
redirectToHomePage,
|
redirectToHomePage,
|
||||||
toastNotification,
|
toastNotification,
|
||||||
} from '../../utils/common';
|
} from '../../utils/common';
|
||||||
|
import { selectActiveGlossaryTerm } from '../../utils/glossary';
|
||||||
import {
|
import {
|
||||||
createColumnRowDetails,
|
createColumnRowDetails,
|
||||||
createCustomPropertiesForEntity,
|
createCustomPropertiesForEntity,
|
||||||
createDatabaseRowDetails,
|
createDatabaseRowDetails,
|
||||||
createDatabaseSchemaRowDetails,
|
createDatabaseSchemaRowDetails,
|
||||||
|
createGlossaryTermRowDetails,
|
||||||
createTableRowDetails,
|
createTableRowDetails,
|
||||||
fillDescriptionDetails,
|
fillDescriptionDetails,
|
||||||
|
fillGlossaryRowDetails,
|
||||||
fillGlossaryTermDetails,
|
fillGlossaryTermDetails,
|
||||||
fillRowDetails,
|
fillRowDetails,
|
||||||
fillTagDetails,
|
fillTagDetails,
|
||||||
@ -611,4 +616,116 @@ test.describe('Bulk Edit Entity', () => {
|
|||||||
await tableEntity.delete(apiContext);
|
await tableEntity.delete(apiContext);
|
||||||
await afterAction();
|
await afterAction();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Glossary', async ({ page }) => {
|
||||||
|
test.slow();
|
||||||
|
|
||||||
|
const additionalGlossaryTerm = createGlossaryTermRowDetails();
|
||||||
|
const glossary = new Glossary();
|
||||||
|
const glossaryTerm = new GlossaryTerm(glossary);
|
||||||
|
|
||||||
|
const { apiContext, afterAction } = await getApiContext(page);
|
||||||
|
await glossary.create(apiContext);
|
||||||
|
await glossaryTerm.create(apiContext);
|
||||||
|
|
||||||
|
await test.step('Perform bulk edit action', async () => {
|
||||||
|
await glossary.visitEntityPage(page);
|
||||||
|
|
||||||
|
await page.click('[data-testid="bulk-edit-table"]');
|
||||||
|
|
||||||
|
// Adding manual wait for the file to load
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Adding some assertion to make sure that CSV loaded correctly
|
||||||
|
await expect(
|
||||||
|
page.locator('.InovuaReactDataGrid__header-layout')
|
||||||
|
).toBeVisible();
|
||||||
|
await expect(page.getByRole('button', { name: 'Next' })).toBeVisible();
|
||||||
|
await expect(
|
||||||
|
page.getByRole('button', { name: 'Previous' })
|
||||||
|
).not.toBeVisible();
|
||||||
|
|
||||||
|
// Click on first cell and edit
|
||||||
|
await page.click(
|
||||||
|
'.InovuaReactDataGrid__row--first > .InovuaReactDataGrid__row-cell-wrap > .InovuaReactDataGrid__cell--first'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Click on first cell and edit
|
||||||
|
await fillGlossaryRowDetails(
|
||||||
|
{
|
||||||
|
...additionalGlossaryTerm,
|
||||||
|
name: glossaryTerm.data.name,
|
||||||
|
owners: [EntityDataClass.user1.responseData?.['displayName']],
|
||||||
|
reviewers: [EntityDataClass.user2.responseData?.['displayName']],
|
||||||
|
relatedTerm: {
|
||||||
|
parent: glossary.data.name,
|
||||||
|
name: glossaryTerm.data.name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
page
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Next' }).click();
|
||||||
|
const loader = page.locator(
|
||||||
|
'.inovua-react-toolkit-load-mask__background-layer'
|
||||||
|
);
|
||||||
|
|
||||||
|
await loader.waitFor({ state: 'hidden' });
|
||||||
|
|
||||||
|
await validateImportStatus(page, {
|
||||||
|
passed: '2',
|
||||||
|
processed: '2',
|
||||||
|
failed: '0',
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.waitForSelector('.InovuaReactDataGrid__header-layout', {
|
||||||
|
state: 'visible',
|
||||||
|
});
|
||||||
|
|
||||||
|
const rowStatus = ['Entity updated'];
|
||||||
|
|
||||||
|
await expect(page.locator('[data-props-id="details"]')).toHaveText(
|
||||||
|
rowStatus
|
||||||
|
);
|
||||||
|
|
||||||
|
await page.getByRole('button', { name: 'Update' }).click();
|
||||||
|
await page
|
||||||
|
.locator('.inovua-react-toolkit-load-mask__background-layer')
|
||||||
|
.waitFor({ state: 'detached' });
|
||||||
|
|
||||||
|
await toastNotification(
|
||||||
|
page,
|
||||||
|
`Glossaryterm ${glossary.responseData.fullyQualifiedName} details updated successfully`
|
||||||
|
);
|
||||||
|
|
||||||
|
await selectActiveGlossaryTerm(page, additionalGlossaryTerm.displayName);
|
||||||
|
|
||||||
|
// Verify Description
|
||||||
|
await expect(page.getByText('Playwright GlossaryTerm')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify Synonyms
|
||||||
|
await expect(
|
||||||
|
page.getByTestId('playwright,glossaryTerm,testing')
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// Verify References
|
||||||
|
await expect(page.getByTestId('reference-link-data')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify Tags
|
||||||
|
await expect(page.getByTestId('tag-PII.Sensitive')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify Owners
|
||||||
|
await expect(
|
||||||
|
page.getByTestId(EntityDataClass.user1.responseData?.['displayName'])
|
||||||
|
).toBeVisible();
|
||||||
|
|
||||||
|
// Verify Reviewers
|
||||||
|
await expect(
|
||||||
|
page.getByTestId(EntityDataClass.user2.responseData?.['displayName'])
|
||||||
|
).toBeVisible();
|
||||||
|
});
|
||||||
|
|
||||||
|
await glossary.delete(apiContext);
|
||||||
|
await afterAction();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -301,7 +301,7 @@ export const fillGlossaryRowDetails = async (
|
|||||||
owners: string[];
|
owners: string[];
|
||||||
},
|
},
|
||||||
page: Page,
|
page: Page,
|
||||||
propertyListName: Record<string, string>
|
propertyListName?: Record<string, string>
|
||||||
) => {
|
) => {
|
||||||
await page
|
await page
|
||||||
.locator('.InovuaReactDataGrid__cell--cell-active')
|
.locator('.InovuaReactDataGrid__cell--cell-active')
|
||||||
@ -362,7 +362,9 @@ export const fillGlossaryRowDetails = async (
|
|||||||
.locator('.InovuaReactDataGrid__cell--cell-active')
|
.locator('.InovuaReactDataGrid__cell--cell-active')
|
||||||
.press('ArrowRight', { delay: 100 });
|
.press('ArrowRight', { delay: 100 });
|
||||||
|
|
||||||
|
if (propertyListName) {
|
||||||
await fillCustomPropertyDetails(page, propertyListName);
|
await fillCustomPropertyDetails(page, propertyListName);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateImportStatus = async (
|
export const validateImportStatus = async (
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import React, {
|
|||||||
import { DndProvider } from 'react-dnd';
|
import { DndProvider } from 'react-dnd';
|
||||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link, useHistory } from 'react-router-dom';
|
||||||
import { ReactComponent as IconDrag } from '../../../assets/svg/drag.svg';
|
import { ReactComponent as IconDrag } from '../../../assets/svg/drag.svg';
|
||||||
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
|
import { ReactComponent as EditIcon } from '../../../assets/svg/edit-new.svg';
|
||||||
import { ReactComponent as IconDown } from '../../../assets/svg/ic-arrow-down.svg';
|
import { ReactComponent as IconDown } from '../../../assets/svg/ic-arrow-down.svg';
|
||||||
@ -88,7 +88,11 @@ import {
|
|||||||
patchGlossaryTerm,
|
patchGlossaryTerm,
|
||||||
} from '../../../rest/glossaryAPI';
|
} from '../../../rest/glossaryAPI';
|
||||||
import { Transi18next } from '../../../utils/CommonUtils';
|
import { Transi18next } from '../../../utils/CommonUtils';
|
||||||
import { getEntityName } from '../../../utils/EntityUtils';
|
import { getBulkEditButton } from '../../../utils/EntityBulkEdit/EntityBulkEditUtils';
|
||||||
|
import {
|
||||||
|
getEntityBulkEditPath,
|
||||||
|
getEntityName,
|
||||||
|
} from '../../../utils/EntityUtils';
|
||||||
import Fqn from '../../../utils/Fqn';
|
import Fqn from '../../../utils/Fqn';
|
||||||
import {
|
import {
|
||||||
buildTree,
|
buildTree,
|
||||||
@ -116,6 +120,7 @@ import {
|
|||||||
} from './GlossaryTermTab.interface';
|
} from './GlossaryTermTab.interface';
|
||||||
|
|
||||||
const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => {
|
const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => {
|
||||||
|
const history = useHistory();
|
||||||
const { currentUser } = useApplicationStore();
|
const { currentUser } = useApplicationStore();
|
||||||
const tableContainerRef = useRef<HTMLDivElement>(null);
|
const tableContainerRef = useRef<HTMLDivElement>(null);
|
||||||
const [containerWidth, setContainerWidth] = useState(0);
|
const [containerWidth, setContainerWidth] = useState(0);
|
||||||
@ -638,6 +643,15 @@ const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleEditGlossary = () => {
|
||||||
|
history.push({
|
||||||
|
pathname: getEntityBulkEditPath(
|
||||||
|
EntityType.GLOSSARY_TERM,
|
||||||
|
activeGlossary?.fullyQualifiedName ?? ''
|
||||||
|
),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const extraTableFilters = useMemo(() => {
|
const extraTableFilters = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -658,6 +672,9 @@ const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => {
|
|||||||
</Space>
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
|
{getBulkEditButton(permissions.EditAll, handleEditGlossary)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
className="text-primary remove-button-background-hover"
|
className="text-primary remove-button-background-hover"
|
||||||
data-testid="expand-collapse-all-button"
|
data-testid="expand-collapse-all-button"
|
||||||
|
|||||||
@ -498,7 +498,7 @@ const BulkEntityImportPage = () => {
|
|||||||
activeAsyncImportJob={activeAsyncImportJob}
|
activeAsyncImportJob={activeAsyncImportJob}
|
||||||
activeStep={activeStep}
|
activeStep={activeStep}
|
||||||
breadcrumbList={breadcrumbList}
|
breadcrumbList={breadcrumbList}
|
||||||
columns={columns}
|
columns={filterColumns}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
handleBack={handleBack}
|
handleBack={handleBack}
|
||||||
handleValidate={handleValidate}
|
handleValidate={handleValidate}
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import {
|
|||||||
exportDatabaseDetailsInCSV,
|
exportDatabaseDetailsInCSV,
|
||||||
exportDatabaseSchemaDetailsInCSV,
|
exportDatabaseSchemaDetailsInCSV,
|
||||||
} from '../../rest/databaseAPI';
|
} from '../../rest/databaseAPI';
|
||||||
|
import { exportGlossaryInCSVFormat } from '../../rest/glossaryAPI';
|
||||||
import { exportDatabaseServiceDetailsInCSV } from '../../rest/serviceAPI';
|
import { exportDatabaseServiceDetailsInCSV } from '../../rest/serviceAPI';
|
||||||
import { exportTableDetailsInCSV } from '../../rest/tableAPI';
|
import { exportTableDetailsInCSV } from '../../rest/tableAPI';
|
||||||
import i18n from '../i18next/LocalUtil';
|
import i18n from '../i18next/LocalUtil';
|
||||||
@ -39,6 +40,9 @@ export const getBulkEditCSVExportEntityApi = (entityType: EntityType) => {
|
|||||||
case EntityType.DATABASE_SCHEMA:
|
case EntityType.DATABASE_SCHEMA:
|
||||||
return exportDatabaseSchemaDetailsInCSV;
|
return exportDatabaseSchemaDetailsInCSV;
|
||||||
|
|
||||||
|
case EntityType.GLOSSARY_TERM:
|
||||||
|
return exportGlossaryInCSVFormat;
|
||||||
|
|
||||||
case EntityType.TABLE:
|
case EntityType.TABLE:
|
||||||
return exportTableDetailsInCSV;
|
return exportTableDetailsInCSV;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user