Skip to content

Commit bffaaa7

Browse files
Merge branch 'main' into copilot/add-hyperlink-support
2 parents a80d98e + 15542b9 commit bffaaa7

File tree

13 files changed

+1066
-73
lines changed

13 files changed

+1066
-73
lines changed

openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/EntitySummaryPanel.spec.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,13 @@
1313
import { expect, Page, test } from '@playwright/test';
1414
import { ENTITY_TYPES } from '../../constant/entity';
1515
import { SidebarItem } from '../../constant/sidebar';
16+
import { TableClass } from '../../support/entity/TableClass';
1617
import { EntityType } from '../../support/entity/EntityDataClass.interface';
17-
import { redirectToHomePage } from '../../utils/common';
18+
import { createNewPage, redirectToHomePage, uuid } from '../../utils/common';
19+
import {
20+
editDisplayNameFromPanel,
21+
navigateToExploreAndSelectTable,
22+
} from '../../utils/entityPanel';
1823
import { selectDataAssetFilter } from '../../utils/explore';
1924
import { sidebarClick } from '../../utils/sidebar';
2025

@@ -176,3 +181,46 @@ test.describe('Entity Summary Panel', () => {
176181
}
177182
});
178183
});
184+
185+
test.describe('Entity Title Section - Edit Display Name', () => {
186+
const table = new TableClass();
187+
188+
test.beforeAll('Setup', async ({ browser }) => {
189+
const { apiContext, afterAction } = await createNewPage(browser);
190+
await table.create(apiContext);
191+
await afterAction();
192+
});
193+
194+
test('should edit display name from entity summary panel', async ({
195+
page,
196+
}) => {
197+
const newDisplayName = `Updated Table ${uuid()}`;
198+
199+
await navigateToExploreAndSelectTable(page, table.entityResponseData.name);
200+
201+
const summaryPanel = page.locator('.entity-summary-panel-container');
202+
await expect(summaryPanel).toBeVisible();
203+
204+
await editDisplayNameFromPanel(page, newDisplayName);
205+
206+
const entityLink = summaryPanel.getByTestId('entity-link').first();
207+
await expect(entityLink).toContainText(newDisplayName);
208+
});
209+
210+
test('should cancel edit display name modal', async ({ page }) => {
211+
await navigateToExploreAndSelectTable(page, table.entityResponseData.name);
212+
213+
const summaryPanel = page.locator('.entity-summary-panel-container');
214+
await expect(summaryPanel).toBeVisible();
215+
216+
const editButton = summaryPanel.getByTestId('edit-displayName-button');
217+
await editButton.click();
218+
219+
const modal = page.locator('.ant-modal');
220+
await expect(modal).toBeVisible();
221+
222+
await modal.getByRole('button', { name: 'Cancel' }).click();
223+
224+
await expect(modal).not.toBeVisible();
225+
});
226+
});

openmetadata-ui/src/main/resources/ui/playwright/utils/entityPanel.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,3 +518,28 @@ export const removeTierFromPanel = async (page: Page) => {
518518
await clearButton.click();
519519
await patchPromise;
520520
};
521+
522+
export const editDisplayNameFromPanel = async (
523+
page: Page,
524+
newDisplayName: string
525+
) => {
526+
const summaryPanel = page.locator('.entity-summary-panel-container');
527+
const editButton = summaryPanel.getByTestId('edit-displayName-button');
528+
529+
await editButton.waitFor({ state: 'visible' });
530+
await editButton.click();
531+
532+
const modal = page.locator('.ant-modal');
533+
await modal.waitFor({ state: 'visible' });
534+
535+
const displayNameInput = modal.locator('#displayName');
536+
await displayNameInput.waitFor({ state: 'visible' });
537+
await displayNameInput.clear();
538+
await displayNameInput.fill(newDisplayName);
539+
540+
const patchPromise = waitForPatchResponse(page);
541+
await modal.getByTestId('save-button').click();
542+
await patchPromise;
543+
544+
await modal.waitFor({ state: 'hidden' });
545+
};

openmetadata-ui/src/main/resources/ui/src/components/Database/ColumnDetailPanel/ColumnDetailPanel.component.tsx

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@ import {
1717
ChevronUp,
1818
XClose,
1919
} from '@untitledui/icons';
20-
import { Card, Drawer, Space, Tooltip, Typography } from 'antd';
20+
import { Button, Card, Drawer, Space, Tooltip, Typography } from 'antd';
2121
import { AxiosError } from 'axios';
22+
import { isString } from 'lodash';
2223
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2324
import { useTranslation } from 'react-i18next';
25+
import { ReactComponent as IconEdit } from '../../../assets/svg/edit-new.svg';
2426
import { ReactComponent as ColumnIcon } from '../../../assets/svg/ic-column-new.svg';
2527
import { ReactComponent as KeyIcon } from '../../../assets/svg/icon-key.svg';
26-
import { ENTITY_PATH, PAGE_SIZE_LARGE } from '../../../constants/constants';
28+
import {
29+
DE_ACTIVE_COLOR,
30+
ENTITY_PATH,
31+
ICON_DIMENSION,
32+
PAGE_SIZE_LARGE,
33+
} from '../../../constants/constants';
2734
import { EntityType } from '../../../enums/entity.enum';
2835
import { Column, TableConstraint } from '../../../generated/entity/data/table';
2936
import { Type } from '../../../generated/entity/type';
@@ -60,6 +67,8 @@ import CustomPropertiesSection from '../../Explore/EntitySummaryPanel/CustomProp
6067
import DataQualityTab from '../../Explore/EntitySummaryPanel/DataQualityTab/DataQualityTab';
6168
import { LineageTabContent } from '../../Explore/EntitySummaryPanel/LineageTab';
6269
import { LineageData } from '../../Lineage/Lineage.interface';
70+
import EntityNameModal from '../../Modals/EntityNameModal/EntityNameModal.component';
71+
import { EntityName } from '../../Modals/EntityNameModal/EntityNameModal.interface';
6372
import {
6473
ColumnDetailPanelProps,
6574
ColumnFieldUpdate,
@@ -92,6 +101,7 @@ export const ColumnDetailPanel = <T extends ColumnOrTask = Column>({
92101
const { permissions } = useGenericContext();
93102
const [isDescriptionLoading, setIsDescriptionLoading] = useState(false);
94103
const [isTestCaseLoading, setIsTestCaseLoading] = useState(false);
104+
const [isDisplayNameEditing, setIsDisplayNameEditing] = useState(false);
95105

96106
const hasEditPermission = useMemo(
97107
() => ({
@@ -103,6 +113,8 @@ export const ColumnDetailPanel = <T extends ColumnOrTask = Column>({
103113
viewAllPermission: permissions.ViewAll,
104114
customProperties:
105115
(permissions.EditCustomFields || permissions.EditAll) && !deleted,
116+
displayName:
117+
(permissions.EditDisplayName || permissions.EditAll) && !deleted,
106118
}),
107119
[permissions, deleted]
108120
);
@@ -433,6 +445,36 @@ export const ColumnDetailPanel = <T extends ColumnOrTask = Column>({
433445
[performColumnFieldUpdate, t]
434446
);
435447

448+
const handleDisplayNameUpdate = useCallback(
449+
async (data: EntityName) => {
450+
try {
451+
const response = await performColumnFieldUpdate(
452+
{ displayName: data.displayName },
453+
'label.display-name'
454+
);
455+
if (response) {
456+
setActiveColumn(
457+
(prev) =>
458+
({
459+
...prev,
460+
displayName: response.displayName,
461+
} as T)
462+
);
463+
}
464+
} catch (error) {
465+
showErrorToast(
466+
error as AxiosError,
467+
t('server.entity-updating-error', {
468+
entity: t('label.display-name'),
469+
})
470+
);
471+
} finally {
472+
setIsDisplayNameEditing(false);
473+
}
474+
},
475+
[performColumnFieldUpdate, t]
476+
);
477+
436478
const previousFqnRef = useRef<string | undefined>();
437479

438480
useEffect(() => {
@@ -675,16 +717,56 @@ export const ColumnDetailPanel = <T extends ColumnOrTask = Column>({
675717
title={getEntityName(activeColumn)}
676718
trigger="hover">
677719
<div className="d-flex items-center justify-between w-full">
678-
<div className="d-flex items-center">
679-
<span className="entity-icon">
720+
<div className="d-flex items-center w-full">
721+
<span className="entity-icon margin-right-xs">
680722
<ColumnIcon />
681723
</span>
682-
<Typography.Text
683-
className="entity-title-link"
684-
data-testid="entity-link"
685-
ellipsis={{ tooltip: true }}>
686-
{stringToHTML(getEntityName(activeColumn))}
687-
</Typography.Text>
724+
<div className="d-flex flex-column w-full overflow-hidden">
725+
<div className="d-flex items-center gap-2 w-full">
726+
<Typography.Text
727+
className="entity-title-link"
728+
data-testid="entity-link"
729+
ellipsis={{ tooltip: true }}>
730+
{stringToHTML(
731+
(activeColumn as any).displayName || activeColumn.name
732+
)}
733+
</Typography.Text>
734+
{hasEditPermission.displayName &&
735+
(entityType === EntityType.TABLE ||
736+
entityType === EntityType.DASHBOARD_DATA_MODEL) && (
737+
<Tooltip placement="top" title={t('label.edit')}>
738+
<Button
739+
ghost
740+
className="hover-cell-icon flex-center"
741+
data-testid="edit-displayName-button"
742+
icon={
743+
<IconEdit
744+
color={DE_ACTIVE_COLOR}
745+
{...ICON_DIMENSION}
746+
/>
747+
}
748+
style={{
749+
width: '24px',
750+
height: '24px',
751+
}}
752+
type="text"
753+
onClick={() => setIsDisplayNameEditing(true)}
754+
/>
755+
</Tooltip>
756+
)}
757+
</div>
758+
{(activeColumn as any).displayName &&
759+
(activeColumn as any).displayName !== activeColumn.name &&
760+
(entityType === EntityType.TABLE ||
761+
entityType === EntityType.DASHBOARD_DATA_MODEL) && (
762+
<Typography.Text
763+
className="text-grey-muted text-xs"
764+
data-testid="entity-name"
765+
ellipsis={{ tooltip: true }}>
766+
{stringToHTML(activeColumn.name || '')}
767+
</Typography.Text>
768+
)}
769+
</div>
688770
</div>
689771
<div>
690772
<IconButton data-testid="close-button" onClick={onClose}>
@@ -835,6 +917,22 @@ export const ColumnDetailPanel = <T extends ColumnOrTask = Column>({
835917
</div>
836918
</div>
837919
</div>
920+
{isDisplayNameEditing && activeColumn && (
921+
<EntityNameModal
922+
entity={{
923+
name: isString(activeColumn.name) ? activeColumn.name : '',
924+
displayName: isString((activeColumn as any).displayName)
925+
? (activeColumn as any).displayName
926+
: undefined,
927+
}}
928+
title={t('label.edit-entity', {
929+
entity: t('label.display-name'),
930+
})}
931+
visible={isDisplayNameEditing}
932+
onCancel={() => setIsDisplayNameEditing(false)}
933+
onSave={handleDisplayNameUpdate}
934+
/>
935+
)}
838936
</Drawer>
839937
);
840938
};

openmetadata-ui/src/main/resources/ui/src/components/Database/SchemaTable/SchemaTable.component.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -704,10 +704,7 @@ const SchemaTable = () => {
704704
})}
705705
<Typography.Text
706706
className={classNames(
707-
'm-b-0 d-block break-word cursor-pointer text-link-color',
708-
{
709-
'text-grey-600': !isEmpty(displayName),
710-
}
707+
'm-b-0 d-block break-word cursor-pointer text-link-color'
711708
)}
712709
data-testid="column-name">
713710
{stringToHTML(highlightSearchText(name, searchText))}

openmetadata-ui/src/main/resources/ui/src/components/Explore/EntitySummaryPanel/EntitySummaryPanel.component.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ export default function EntitySummaryPanel({
307307
fullyQualifiedName: entityDetails.details.fullyQualifiedName,
308308
id: entityDetails.details.id,
309309
description: data.description ?? entityDetails.details.description,
310-
displayName: entityDetails.details.displayName,
310+
displayName: data.displayName,
311311
name: entityDetails.details.name,
312312
deleted: entityDetails.details.deleted,
313313
serviceType: (entityDetails.details as any).serviceType,
@@ -470,6 +470,13 @@ export default function EntitySummaryPanel({
470470
[updateEntityData]
471471
);
472472

473+
const handleDisplayNameUpdate = useCallback(
474+
(updatedDisplayName: string) => {
475+
updateEntityData({ displayName: updatedDisplayName });
476+
},
477+
[entityData, updateEntityData]
478+
);
479+
473480
const handleExtensionUpdate = useCallback(
474481
async (updatedExtension: Record<string, unknown> | undefined) => {
475482
if (onEntityUpdate) {
@@ -698,7 +705,14 @@ export default function EntitySummaryPanel({
698705
<EntityTitleSection
699706
className="title-section"
700707
entityDetails={entityDetails.details}
708+
entityDisplayName={entityData?.displayName}
701709
entityLink={entityLink}
710+
entityType={entityType}
711+
hasEditPermission={getPrioritizedEditPermission(
712+
entityPermissions,
713+
Operation.EditDisplayName
714+
)}
715+
onDisplayNameUpdate={handleDisplayNameUpdate}
702716
/>
703717
)}
704718
<div className="overview-tab-content">{summaryComponentV1}</div>
@@ -732,6 +746,12 @@ export default function EntitySummaryPanel({
732746
className="title-section"
733747
entityDetails={entityDetails.details}
734748
entityLink={entityLink}
749+
entityType={entityType}
750+
hasEditPermission={getPrioritizedEditPermission(
751+
entityPermissions,
752+
Operation.EditDisplayName
753+
)}
754+
onDisplayNameUpdate={handleDisplayNameUpdate}
735755
/>
736756
)}
737757
<div className="entity-summary-panel-tab-content">
@@ -802,9 +822,16 @@ export default function EntitySummaryPanel({
802822
<EntityTitleSection
803823
className="drawer-title-section"
804824
entityDetails={entityDetails.details}
825+
entityDisplayName={entityData?.displayName}
805826
entityLink={entityLink}
827+
entityType={entityType}
828+
hasEditPermission={getPrioritizedEditPermission(
829+
entityPermissions,
830+
Operation.EditDisplayName
831+
)}
806832
testId="entity-header-title"
807833
tooltipPlacement="bottomLeft"
834+
onDisplayNameUpdate={handleDisplayNameUpdate}
808835
/>
809836
<Button
810837
aria-label={t('label.close')}

0 commit comments

Comments
 (0)