diff --git a/openmetadata-ui/src/main/resources/ui/playwright/constant/customizeDetail.ts b/openmetadata-ui/src/main/resources/ui/playwright/constant/customizeDetail.ts index 924e7009907..90e23265c2c 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/constant/customizeDetail.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/constant/customizeDetail.ts @@ -32,138 +32,188 @@ export enum ECustomizedGovernance { GLOSSARY_TERM = 'Glossary Term', } +export enum EntityTabs { + SCHEMA = 'schema', + SCHEMAS = 'schemas', + ACTIVITY_FEED = 'activity_feed', + SAMPLE_DATA = 'sample_data', + TABLE_QUERIES = 'table_queries', + PROFILER = 'profiler', + LINEAGE = 'lineage', + KNOWLEDGE_GRAPH = 'knowledge_graph', + DBT = 'dbt', + VIEW_DEFINITION = 'view_definition', + SCHEMA_DEFINITION = 'schema_definition', + CUSTOM_PROPERTIES = 'custom_properties', + MODEL = 'model', + FEATURES = 'features', + TASKS = 'tasks', + CONFIG = 'config', + DETAILS = 'details', + CHILDREN = 'children', + EXECUTIONS = 'executions', + TABLE = 'table', + TEST_CASES = 'test-cases', + PIPELINE = 'pipeline', + DATA_Model = 'data-model', + AGENTS = 'agents', + CONNECTION = 'connection', + SQL = 'sql', + FIELDS = 'fields', + SEARCH_INDEX_SETTINGS = 'search-index-settings', + STORED_PROCEDURE = 'stored_procedure', + CODE = 'code', + API_COLLECTION = 'apiCollection', + API_ENDPOINT = 'apiEndpoint', + OVERVIEW = 'overview', + INCIDENTS = 'incidents', + TERMS = 'terms', + GLOSSARY_TERMS = 'glossary_terms', + ASSETS = 'assets', + EXPRESSION = 'expression', + INSIGHTS = 'insights', + DASHBOARD = 'dashboard', + DOCUMENTATION = 'documentation', + DATA_PRODUCTS = 'data_products', + SUBDOMAINS = 'subdomains', + CONTRACT = 'contract', +} + export const TABLE_DEFAULT_TABS = [ - 'Activity Feeds & Tasks', - 'Contract', - 'Custom Properties', - 'Data Observability', - 'Lineage', - 'Queries', - 'Sample Data', - 'Schema', - 'View Definition', - 'dbt', + EntityTabs.ACTIVITY_FEED, + EntityTabs.CONTRACT, + EntityTabs.CUSTOM_PROPERTIES, + EntityTabs.PROFILER, + EntityTabs.LINEAGE, + EntityTabs.TABLE_QUERIES, + EntityTabs.SAMPLE_DATA, + EntityTabs.SCHEMA, + EntityTabs.VIEW_DEFINITION, + EntityTabs.DBT, ]; export const TOPIC_DEFAULT_TABS = [ - 'Schema', - 'Activity Feeds & Tasks', - 'Sample Data', - 'Config', - 'Lineage', - 'Custom Properties', + EntityTabs.SCHEMA, + EntityTabs.ACTIVITY_FEED, + EntityTabs.SAMPLE_DATA, + EntityTabs.CONFIG, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DASHBOARD_DEFAULT_TABS = [ - 'Details', - 'Activity Feeds & Tasks', - 'Lineage', - 'Custom Properties', + EntityTabs.DETAILS, + EntityTabs.ACTIVITY_FEED, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const MLMODEL_DEFAULT_TABS = [ - 'Features', - 'Activity Feeds & Tasks', - 'Details', - 'Lineage', - 'Custom Properties', + EntityTabs.FEATURES, + EntityTabs.ACTIVITY_FEED, + EntityTabs.DETAILS, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const PIPELINE_DEFAULT_TABS = [ - 'Tasks', - 'Activity Feeds & Tasks', - 'Executions', - 'Lineage', - 'Custom Properties', + EntityTabs.TASKS, + EntityTabs.ACTIVITY_FEED, + EntityTabs.EXECUTIONS, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DASHBOARD_DATAMODEL_DEFAULT_TABS = [ - 'Model', - 'Activity Feeds & Tasks', - 'SQL', - 'Lineage', - 'Custom Properties', + EntityTabs.MODEL, + EntityTabs.ACTIVITY_FEED, + EntityTabs.SQL, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const API_COLLECTION_DEFAULT_TABS = [ - 'Endpoints', - 'Activity Feeds & Tasks', - 'Custom Properties', + EntityTabs.API_ENDPOINT, + EntityTabs.ACTIVITY_FEED, + EntityTabs.CUSTOM_PROPERTIES, ]; export const SEARCH_INDEX_DEFAULT_TABS = [ - 'Fields', - 'Activity Feeds & Tasks', - 'Sample Data', - 'Lineage', - 'Search Index Settings', - 'Custom Properties', + EntityTabs.FIELDS, + EntityTabs.ACTIVITY_FEED, + EntityTabs.SAMPLE_DATA, + EntityTabs.LINEAGE, + EntityTabs.SEARCH_INDEX_SETTINGS, + EntityTabs.CUSTOM_PROPERTIES, ]; export const CONTAINER_DEFAULT_TABS = [ - 'Schema', - 'Children', - 'Activity Feeds & Tasks', - 'Lineage', - 'Custom Properties', + EntityTabs.SCHEMA, + EntityTabs.CHILDREN, + EntityTabs.ACTIVITY_FEED, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DATABASE_DEFAULT_TABS = [ - 'Schemas', - 'Activity Feeds & Tasks', - 'Custom Properties', + EntityTabs.SCHEMAS, + EntityTabs.ACTIVITY_FEED, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DATABASE_SCHEMA_DEFAULT_TABS = [ - 'Tables', - 'Stored Procedures', - 'Activity Feeds & Tasks', - 'Custom Properties', + EntityTabs.TABLE, + EntityTabs.STORED_PROCEDURE, + EntityTabs.ACTIVITY_FEED, + EntityTabs.CUSTOM_PROPERTIES, ]; export const STORED_PROCEDURE_DEFAULT_TABS = [ - 'Code', - 'Activity Feeds & Tasks', - 'Lineage', - 'Custom Properties', + EntityTabs.CODE, + EntityTabs.ACTIVITY_FEED, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const API_ENDPOINT_DEFAULT_TABS = [ - 'Schema', - 'Activity Feeds & Tasks', - 'Lineage', - 'Custom Properties', + EntityTabs.SCHEMA, + EntityTabs.ACTIVITY_FEED, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DASHBOARD_DATA_MODEL_DEFAULT_TABS = [ - 'Model', - 'Activity Feeds & Tasks', - 'Lineage', - 'Custom Properties', + EntityTabs.MODEL, + EntityTabs.ACTIVITY_FEED, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const ML_MODEL_DEFAULT_TABS = [ - 'Features', - 'Activity Feeds & Tasks', - 'Details', - 'Lineage', - 'Custom Properties', + EntityTabs.FEATURES, + EntityTabs.ACTIVITY_FEED, + EntityTabs.DETAILS, + EntityTabs.LINEAGE, + EntityTabs.CUSTOM_PROPERTIES, ]; export const DOMAIN_DEFAULT_TABS = [ - 'Documentation', - 'Sub Domains', - 'Data Products', - 'Assets', - 'Custom Properties', + EntityTabs.DOCUMENTATION, + EntityTabs.SUBDOMAINS, + EntityTabs.DATA_PRODUCTS, + EntityTabs.ASSETS, + EntityTabs.CUSTOM_PROPERTIES, ]; -export const GLOSSARY_DEFAULT_TABS = ['Terms', 'Activity Feeds & Tasks']; +export const GLOSSARY_DEFAULT_TABS = [ + EntityTabs.TERMS, + EntityTabs.ACTIVITY_FEED, +]; export const GLOSSARY_TERM_DEFAULT_TABS = [ - 'Overview', - 'Glossary Terms', - 'Assets', - 'Activity Feeds & Tasks', - 'Custom Properties', + EntityTabs.OVERVIEW, + EntityTabs.GLOSSARY_TERMS, + EntityTabs.ASSETS, + EntityTabs.ACTIVITY_FEED, + EntityTabs.CUSTOM_PROPERTIES, ]; diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CustomizeDetailPage.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CustomizeDetailPage.spec.ts index 5fa1c2f8d35..dcdf56a3f4d 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CustomizeDetailPage.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/CustomizeDetailPage.spec.ts @@ -388,7 +388,7 @@ test.describe('Persona customization', () => { .getByTestId('remove-widget-button') .click(); - await adminPage.getByTestId('tab-Custom Properties').click(); + await adminPage.getByTestId('tab-custom_properties').click(); await adminPage.getByText('Hide', { exact: true }).click(); await adminPage.getByRole('button', { name: 'Add tab' }).click(); @@ -470,9 +470,9 @@ test.describe('Persona customization', () => { for (const tabName of expectedTabs) { await expect( - adminPage.getByTestId('customize-tab-card').getByRole('button', { - name: tabName, - }) + adminPage + .getByTestId('customize-tab-card') + .getByTestId(`tab-${tabName}`) ).toBeVisible(); } } @@ -489,6 +489,9 @@ test.describe('Persona customization', () => { .click(); await adminPage.getByRole('button', { name: 'Add tab' }).click(); + + await expect(adminPage.getByRole('dialog')).toBeVisible(); + await adminPage .getByRole('dialog') .getByRole('button', { name: 'Add' }) @@ -551,8 +554,8 @@ test.describe('Persona customization', () => { state: 'detached', }); - const dragElement = adminPage.getByTestId('tab-Overview'); - const dropTarget = adminPage.getByTestId('tab-Custom Properties'); + const dragElement = adminPage.getByTestId('tab-overview'); + const dropTarget = adminPage.getByTestId('tab-custom_properties'); await dragElement.dragTo(dropTarget); @@ -597,4 +600,98 @@ test.describe('Persona customization', () => { ).toBeVisible(); }); }); + + test("customize tab label should only render if it's customize by user", async ({ + adminPage, + userPage, + }) => { + await test.step('apply tab label customization for Table', async () => { + await settingClick(adminPage, GlobalSettingOptions.PERSONA); + await adminPage.waitForLoadState('networkidle'); + await adminPage + .getByTestId(`persona-details-card-${persona.data.name}`) + .click(); + await adminPage.getByRole('tab', { name: 'Customize UI' }).click(); + await adminPage.waitForLoadState('networkidle'); + await adminPage.getByText('Data Assets').click(); + await adminPage.getByText('Table', { exact: true }).click(); + + await adminPage.waitForSelector('[data-testid="loader"]', { + state: 'detached', + }); + + await expect( + adminPage + .getByTestId('customize-tab-card') + .getByTestId(`tab-sample_data`) + ).toBeVisible(); + + await adminPage + .getByTestId('customize-tab-card') + .getByTestId(`tab-sample_data`) + .click(); + + await adminPage.getByRole('menuitem', { name: 'Rename' }).click(); + + await expect(adminPage.getByRole('dialog')).toBeVisible(); + + await adminPage.getByRole('dialog').getByRole('textbox').clear(); + await adminPage + .getByRole('dialog') + .getByRole('textbox') + .fill('Sample Data Updated'); + + await adminPage + .getByRole('dialog') + .getByRole('button', { name: 'Ok' }) + .click(); + + await expect( + adminPage + .getByTestId('customize-tab-card') + .getByTestId(`tab-sample_data`) + ).toHaveText('Sample Data Updated'); + + await adminPage.getByTestId('save-button').click(); + + await toastNotification( + adminPage, + /^Page layout (created|updated) successfully\.$/ + ); + }); + + await test.step( + 'validate applied label change and language support for page', + async () => { + await redirectToHomePage(userPage); + + const entity = getCustomizeDetailsEntity(ECustomizedDataAssets.TABLE); + await entity.visitEntityPage(userPage); + await userPage.waitForLoadState('networkidle'); + await userPage.waitForSelector('[data-testid="loader"]', { + state: 'detached', + }); + + // Change language to French + await userPage.getByRole('button', { name: 'EN' }).click(); + await userPage.getByRole('menuitem', { name: 'Français - FR' }).click(); + await userPage.waitForLoadState('networkidle'); + await userPage.waitForSelector('[data-testid="loader"]', { + state: 'detached', + }); + + await expect( + userPage.getByRole('tab', { name: 'Sample Data Updated' }) + ).toBeVisible(); + // Overview tab in French, only customized tab should be non-localized rest should be localized + await expect( + userPage.getByRole('tab', { name: 'Colonnes' }) + ).toBeVisible(); + + await expect( + userPage.getByRole('tab', { name: "Flux d'Activité & Tâches" }) + ).toBeVisible(); + } + ); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContracts.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContracts.spec.ts index 8b4dd3ca3e7..8f848458652 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContracts.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContracts.spec.ts @@ -696,7 +696,7 @@ test.describe('Data Contracts', () => { }); // Hide the Contract tab - await page.getByTestId('tab-Contract').click(); + await page.getByTestId('tab-contract').click(); await page.getByText('Hide', { exact: true }).click(); // Save the customization diff --git a/openmetadata-ui/src/main/resources/ui/src/App.tsx b/openmetadata-ui/src/main/resources/ui/src/App.tsx index fcfd17f345b..150103bb9e3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/App.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/App.tsx @@ -32,6 +32,8 @@ import { useApplicationStore } from './hooks/useApplicationStore'; import { getCustomUiThemePreference } from './rest/settingConfigAPI'; import { getBasePath } from './utils/HistoryUtils'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import i18n from './utils/i18next/LocalUtil'; import { getThemeConfig } from './utils/ThemeUtils'; @@ -88,7 +90,9 @@ const App: FC = () => { - + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Customization/CustomizeTabWidget/CustomizeTabWidget.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Customization/CustomizeTabWidget/CustomizeTabWidget.tsx index 43a04d1a603..9e2650515a4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Customization/CustomizeTabWidget/CustomizeTabWidget.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Customization/CustomizeTabWidget/CustomizeTabWidget.tsx @@ -13,17 +13,8 @@ import { EyeFilled, MoreOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Card, Col, Dropdown, Input, Modal, Space } from 'antd'; -import { - cloneDeep, - isEmpty, - isNil, - isUndefined, - toString, - uniqueId, -} from 'lodash'; +import { cloneDeep, isEmpty, isNil, isUndefined, uniqueId } from 'lodash'; import { useCallback, useMemo, useState } from 'react'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; import RGL, { Layout, WidthProvider } from 'react-grid-layout'; import { useTranslation } from 'react-i18next'; import { @@ -50,6 +41,7 @@ import { getCustomizableWidgetByPage, getDefaultTabs, getDefaultWidgetForTab, + getTabDisplayName, } from '../../../utils/CustomizePage/CustomizePageUtils'; import { getEntityName } from '../../../utils/EntityUtils'; import { TabItem } from '../../common/DraggableTabs/DraggableTabs'; @@ -388,46 +380,44 @@ export const CustomizeTabWidget = () => { } title={t('label.customize-tab-plural')}> - -
- {items.map((item, index) => ( - - ))} - {hiddenTabs.map((item) => ( - , - }, - ], - onClick: () => add(item), - }} - trigger={['click']}> - - - ))} -
-
+
+ {items.map((item, index) => ( + + ))} + {hiddenTabs.map((item) => ( + , + }, + ], + onClick: () => add(item), + }} + trigger={['click']}> + + + ))} +
@@ -508,7 +498,7 @@ export const CustomizeTabWidget = () => { onOk={handleRenameSave}> 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 7fd540ea50e..44fe7e5d4f8 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 @@ -32,8 +32,6 @@ import classNames from 'classnames'; import { compare } from 'fast-json-patch'; import { cloneDeep, isEmpty, isUndefined } from 'lodash'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; import { useTranslation } from 'react-i18next'; import { Link, useNavigate } from 'react-router-dom'; import { ReactComponent as IconDrag } from '../../../assets/svg/drag.svg'; @@ -882,28 +880,26 @@ const GlossaryTermTab = ({ isGlossary, className }: GlossaryTermTabProps) => { {/* Have use the col to set the width of the table, to only use the viewport width for the table columns */} {glossaryTerms.length > 0 ? ( - - - +
) : ( )} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx index 55dafe85996..925c9ab1317 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTermTab/GlossaryTermTab.test.tsx @@ -19,6 +19,8 @@ import { getByText, render, } from '@testing-library/react'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import { MemoryRouter } from 'react-router-dom'; import { mockedGlossaryTerms, @@ -104,6 +106,15 @@ jest.mock('../../Customization/GenericProvider/GenericProvider', () => ({ })), })); +const renderWithDndProvider = (props = {}) => { + return render( + + + , + { wrapper: MemoryRouter } + ); +}; + describe('Test GlossaryTermTab component', () => { it('should show the ErrorPlaceHolder component, if no glossary is present', () => { const { container } = render(, { @@ -132,9 +143,7 @@ describe('Test GlossaryTermTab component', () => { glossaryChildTerms: mockedGlossaryTerms, updateActiveGlossary: jest.fn(), })); - const { container } = render(, { - wrapper: MemoryRouter, - }); + const { container } = renderWithDndProvider(); expect(getByTestId(container, 'Clothing')).toBeInTheDocument(); expect( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.test.tsx index b5e9bb0bfa0..f7e0c42e656 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.test.tsx @@ -11,7 +11,9 @@ * limitations under the License. */ -import { act, fireEvent, render, screen } from '@testing-library/react'; +import { fireEvent, render, screen } from '@testing-library/react'; +import { DndProvider } from 'react-dnd'; +import { HTML5Backend } from 'react-dnd-html5-backend'; import { MemoryRouter } from 'react-router-dom'; import { MOCK_CURRENT_TEAM, @@ -80,13 +82,18 @@ jest.mock('../../../common/SearchBarComponent/SearchBar.component', () => jest.fn().mockImplementation(() =>
SearchBar
) ); +const renderComponent = (props = {}) => { + return render( + + + , + { wrapper: MemoryRouter } + ); +}; + describe('Team Hierarchy page', () => { it('Initially, Table should load', async () => { - await act(async () => { - render(, { - wrapper: MemoryRouter, - }); - }); + renderComponent(); const table = await screen.findByTestId('team-hierarchy-table'); @@ -94,11 +101,7 @@ describe('Team Hierarchy page', () => { }); it('Should render all table columns', async () => { - await act(async () => { - render(, { - wrapper: MemoryRouter, - }); - }); + renderComponent(); const table = await screen.findByTestId('team-hierarchy-table'); const teamsColumn = await screen.findByText('label.team-plural'); @@ -121,11 +124,7 @@ describe('Team Hierarchy page', () => { }); it('Should render child row in table', async () => { - await act(async () => { - render(, { - wrapper: MemoryRouter, - }); - }); + renderComponent(); const table = await screen.findByTestId('team-hierarchy-table'); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.tsx index 289f6ca387d..cdcd38b4fb1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamDetails/TeamHierarchy.tsx @@ -19,8 +19,6 @@ import classNames from 'classnames'; import { compare } from 'fast-json-patch'; import { isEmpty, isUndefined } from 'lodash'; import { FC, useCallback, useMemo, useState } from 'react'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; import { useTranslation } from 'react-i18next'; import { Link } from 'react-router-dom'; import { @@ -271,51 +269,49 @@ const TeamHierarchy: FC = ({ return (
- -
- - - - {t('label.deleted')} - - +
+ + + + {t('label.deleted')} + + - {createTeamPermission && !isTeamDeleted && ( - - )} - - } - loading={isTableLoading} - locale={{ - emptyText: , - }} - pagination={false} - rowKey="name" - searchProps={searchProps} - size="small" - onHeaderRow={onTableHeader} - onRow={onTableRow} - /> - + {createTeamPermission && !isTeamDeleted && ( + + )} + + } + loading={isTableLoading} + locale={{ + emptyText: , + }} + pagination={false} + rowKey="name" + searchProps={searchProps} + size="small" + onHeaderRow={onTableHeader} + onRow={onTableRow} + /> ({ - getEntityName: jest.fn().mockReturnValue('Test Tab'), +jest.mock('../../../utils/CustomizePage/CustomizePageUtils', () => ({ + getTabDisplayName: jest.fn().mockReturnValue('Test Tab'), })); describe('TabItem', () => { @@ -53,12 +52,12 @@ describe('TabItem', () => { it('renders tab item with correct name', () => { renderComponent(); - expect(screen.getByText('Test Tab')).toBeInTheDocument(); + expect(screen.getByTestId('tab-Test Tab')).toBeInTheDocument(); }); it('calls onItemClick when tab is clicked', () => { renderComponent(); - fireEvent.click(screen.getByText('Test Tab')); + fireEvent.click(screen.getByTestId('tab-Test Tab')); expect(defaultProps.onItemClick).toHaveBeenCalledWith(mockTab.id); }); diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/DraggableTabs/DraggableTabs.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/DraggableTabs/DraggableTabs.tsx index 5ca49f5254a..c46cb325223 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/DraggableTabs/DraggableTabs.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/DraggableTabs/DraggableTabs.tsx @@ -22,7 +22,7 @@ import React from 'react'; import { useDrag, useDrop } from 'react-dnd'; import { useTranslation } from 'react-i18next'; import { Tab } from '../../../generated/system/ui/tab'; -import { getEntityName } from '../../../utils/EntityUtils'; +import { getTabDisplayName } from '../../../utils/CustomizePage/CustomizePageUtils'; import './draggable-tabs.less'; type TargetKey = React.MouseEvent | React.KeyboardEvent | string; @@ -118,10 +118,10 @@ export const TabItem = ({ trigger={['click']}> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/Table/Table.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/Table/Table.tsx index 776911096cd..005d31e00dd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/Table/Table.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/Table/Table.tsx @@ -33,8 +33,6 @@ import { } from 'react'; import { useAntdColumnResize } from 'react-antd-column-resize'; import { Column } from 'react-antd-column-resize/dist/useAntdColumnResize/types'; -import { DndProvider } from 'react-dnd'; -import { HTML5Backend } from 'react-dnd-html5-backend'; import { useTranslation } from 'react-i18next'; import { ReactComponent as ColumnIcon } from '../../../assets/svg/ic-column.svg'; import { useCurrentUserPreferences } from '../../../hooks/currentUserStore/useCurrentUserStore'; @@ -291,24 +289,22 @@ const Table = >( span={searchProps ? 12 : 24}> {rest.extraTableFilters} {isCustomizeColumnEnable && ( - - - - - + + + )} )} diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.test.ts b/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.test.ts index 5dc11fed648..9e309e5fc01 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.test.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.test.ts @@ -17,6 +17,7 @@ import { WidgetConfig } from '../../pages/CustomizablePage/CustomizablePage.inte import { checkIfExpandViewSupported, getDefaultTabs, + getTabDisplayName, getTabLabelFromId, getTabLabelMapFromTabs, sortTabs, @@ -24,6 +25,43 @@ import { } from './CustomizePageUtils'; describe('CustomizePageUtils', () => { + describe('getTabDisplayName', () => { + it('should return displayName if present', () => { + const tab: Tab = { + id: EntityTabs.OVERVIEW, + name: EntityTabs.OVERVIEW, + displayName: 'Custom Overview', + layout: [], + }; + + expect(getTabDisplayName(tab)).toBe('Custom Overview'); + }); + + it('should fallback to getTabLabelFromId if displayName is missing', () => { + const tab: Tab = { + id: EntityTabs.OVERVIEW, + name: EntityTabs.OVERVIEW, + layout: [], + }; + + const result = getTabDisplayName(tab); + + expect(typeof result).toBe('string'); + }); + + it('should return empty string if displayName and name are missing', () => { + const tab: Tab = { + id: EntityTabs.OVERVIEW, + name: '' as EntityTabs, + layout: [], + }; + + const result = getTabDisplayName(tab); + + expect(typeof result).toBe('string'); + }); + }); + describe('sortTabs', () => { it('should sort tabs according to given order', () => { const tabs: TabsProps['items'] = [ diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.ts index 08796c6c3b4..48127d64ac1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/CustomizePage/CustomizePageUtils.ts @@ -691,3 +691,7 @@ export const updateWidgetHeightRecursively = ( return acc; }, [] as WidgetConfig[]); + +export const getTabDisplayName = (item: Tab) => { + return item.displayName ?? getTabLabelFromId(item.name as EntityTabs); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts b/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts index cb9f5e7d41a..5ec28ce8011 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts +++ b/openmetadata-ui/src/main/resources/ui/src/utils/TableClassBase.ts @@ -28,7 +28,6 @@ import { Tab } from '../generated/system/ui/uiCustomization'; import { TestSummary } from '../generated/tests/testCase'; import { FeedCounts } from '../interface/feed.interface'; import { WidgetConfig } from '../pages/CustomizablePage/CustomizablePage.interface'; -import { getTabLabelFromId } from './CustomizePage/CustomizePageUtils'; import i18n from './i18next/LocalUtil'; import { getTableDetailPageBaseTabs, @@ -106,7 +105,6 @@ class TableClassBase { ].map((tab: EntityTabs) => ({ id: tab, name: tab, - displayName: getTabLabelFromId(tab), layout: this.getDefaultLayout(tab), editable: tab === EntityTabs.SCHEMA, }));