diff --git a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Table.spec.ts b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Table.spec.ts index 2bcabd03624..a1ad17a2fd1 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Table.spec.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/Table.spec.ts @@ -14,6 +14,7 @@ import test, { expect } from '@playwright/test'; import { SidebarItem } from '../../constant/sidebar'; import { TableClass } from '../../support/entity/TableClass'; import { createNewPage, redirectToHomePage } from '../../utils/common'; +import { getFirstRowColumnLink } from '../../utils/entity'; import { sidebarClick } from '../../utils/sidebar'; // use the admin user to login @@ -92,4 +93,50 @@ test.describe('Table pagination sorting search scenarios ', () => { await expect(page.getByRole('tab', { name: 'Schema' })).toContainText('4'); }); + + test('should persist current page', async ({ page }) => { + page.goto('/databaseSchema/sample_data.ecommerce_db.shopify'); + + await expect(page.getByTestId('databaseSchema-tables')).toBeVisible(); + + await page.getByTestId('next').click(); + + const initialPageIndicator = await page + .locator('[data-testid="page-indicator"]') + .textContent(); + + const linkInColumn = getFirstRowColumnLink(page); + await linkInColumn.click(); + + await page.goBack(); + + const pageIndicatorAfterBack = await page + .locator('[data-testid="page-indicator"]') + .textContent(); + + expect(pageIndicatorAfterBack).toBe(initialPageIndicator); + }); + + test('should persist page size', async ({ page }) => { + page.goto('/databaseSchema/sample_data.ecommerce_db.shopify'); + + await expect(page.getByTestId('databaseSchema-tables')).toBeVisible(); + + const pageSizeDropdown = page.getByTestId('page-size-selection-dropdown'); + await pageSizeDropdown.click(); + + const dropdownOptions = page.locator('.ant-dropdown-menu'); + + await expect(dropdownOptions).toBeVisible(); + + const optionToSelect = dropdownOptions.locator('text="15 / Page"'); + await optionToSelect.click(); + + const linkInColumn = getFirstRowColumnLink(page); + await linkInColumn.click(); + + await page.goBack(); + + await expect(pageSizeDropdown).toHaveText('15 / Page'); + }); }); diff --git a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts index f2b386d91c7..900a0a076f5 100644 --- a/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts +++ b/openmetadata-ui/src/main/resources/ui/playwright/utils/entity.ts @@ -1367,3 +1367,12 @@ export const getTextFromHtmlString = (description?: string): string => { return description.replace(/<[^>]*>/g, '').trim(); }; + +export const getFirstRowColumnLink = (page: Page) => { + const table = page.locator('[data-testid="databaseSchema-tables"]'); + const firstRowFirstColumn = table.locator( + 'tbody tr:first-child td:first-child' + ); + + return firstRowFirstColumn.locator('[data-testid="column-name"] a'); +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetAsyncSelectList/DataAssetAsyncSelectList.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetAsyncSelectList/DataAssetAsyncSelectList.test.tsx index 08e778cea53..25746813cbc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetAsyncSelectList/DataAssetAsyncSelectList.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DataAssets/DataAssetAsyncSelectList/DataAssetAsyncSelectList.test.tsx @@ -99,6 +99,19 @@ const mockSearchAPIResponse = { }, }, }; +const mockLocationPathname = '/mock-path'; + +jest.mock('react-router-dom', () => ({ + useHistory: jest.fn().mockImplementation(() => ({ + history: { + push: jest.fn(), + }, + replace: jest.fn(), + })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), +})); describe('DataAssetAsyncSelectList', () => { it('should render without crashing', async () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestinoPipelineList.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestinoPipelineList.test.tsx index 1db1dbde7da..894aff4b77e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestinoPipelineList.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/Ingestion/IngestionPipelineList/IngestinoPipelineList.test.tsx @@ -69,6 +69,19 @@ jest.mock('../../../../../rest/ingestionPipelineAPI', () => ({ }) ), })); +const mockLocationPathname = '/mock-path'; + +jest.mock('react-router-dom', () => ({ + useHistory: jest.fn().mockImplementation(() => ({ + history: { + push: jest.fn(), + }, + replace: jest.fn(), + })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), +})); describe('IngestionPipelineList', () => { it('should show loader until get status of airflow', () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/NextPrevious/NextPrevious.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/NextPrevious/NextPrevious.tsx index 77d62a6eac4..4de92bd088c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/NextPrevious/NextPrevious.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/NextPrevious/NextPrevious.tsx @@ -120,7 +120,9 @@ const NextPrevious: FC = ({ onClick: () => onShowSizeChange(size), })), }}> - diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts index 01f6ccb800c..a638efc481c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts +++ b/openmetadata-ui/src/main/resources/ui/src/constants/constants.ts @@ -612,3 +612,7 @@ export const STATUS_LABEL = { [Status.Stopped]: 'Stopped', [Status.Success]: 'Success', }; + +export const INITIAL_TABLE_FILTERS = { + showDeletedTables: false, +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/hooks/paging/usePaging.ts b/openmetadata-ui/src/main/resources/ui/src/hooks/paging/usePaging.ts index 2344d7fba2d..669ba42d796 100644 --- a/openmetadata-ui/src/main/resources/ui/src/hooks/paging/usePaging.ts +++ b/openmetadata-ui/src/main/resources/ui/src/hooks/paging/usePaging.ts @@ -10,6 +10,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import qs from 'qs'; import { Dispatch, SetStateAction, @@ -17,49 +18,118 @@ import { useMemo, useState, } from 'react'; +import { useHistory } from 'react-router-dom'; import { INITIAL_PAGING_VALUE, PAGE_SIZE_BASE, pagingObject, } from '../../constants/constants'; +import { CursorType } from '../../enums/pagination.enum'; import { Paging } from '../../generated/type/paging'; +import useCustomLocation from '../useCustomLocation/useCustomLocation'; + +interface CursorState { + cursorType: CursorType | null; + cursorValue: string | null; +} + +interface PagingHistoryStateData { + cursorData: CursorState; + currentPage: number | null; + pageSize: number | null; +} export interface UsePagingInterface { paging: Paging; handlePagingChange: Dispatch>; currentPage: number; - handlePageChange: Dispatch>; + handlePageChange: ( + page: number | ((page: number) => number), + cursorData?: CursorState, + pageSize?: number + ) => void; pageSize: number; handlePageSizeChange: (page: number) => void; showPagination: boolean; + pagingCursor: PagingHistoryStateData; } - export const usePaging = ( defaultPageSize = PAGE_SIZE_BASE ): UsePagingInterface => { + // Extract initial values from history state if present + const history = useHistory(); + const location = useCustomLocation(); + const historyState = location.state as any; + const initialPageSize = historyState?.pageSize ?? defaultPageSize; + const initialCurrentPage = historyState?.cursorData?.cursorType + ? historyState.currentPage + : INITIAL_PAGING_VALUE; + const [paging, setPaging] = useState(pagingObject); - const [currentPage, setCurrentPage] = useState(INITIAL_PAGING_VALUE); - const [pageSize, setPageSize] = useState(defaultPageSize); + const [currentPage, setCurrentPage] = useState(initialCurrentPage); + const [pageSize, setPageSize] = useState(initialPageSize); + + const pagingCursorHistoryState: PagingHistoryStateData = { + cursorData: historyState?.cursorData, + currentPage: historyState?.currentPage, + pageSize: historyState?.pageSize, + }; const handlePageSize = useCallback( (page: number) => { setPageSize(page); setCurrentPage(INITIAL_PAGING_VALUE); + const searchParams = qs.stringify( + qs.parse(location.search, { ignoreQueryPrefix: true }), + { addQueryPrefix: true } + ); + // Update location state to persist pageSize for navigation + history.replace({ + state: { + pageSize: page, + }, + search: searchParams, + }); }, - [setPageSize, setCurrentPage] + [setPageSize, setCurrentPage, history, location] ); - const paginationVisible = useMemo(() => { return paging.total > pageSize || pageSize !== defaultPageSize; }, [defaultPageSize, paging, pageSize]); + const handlePageChange = useCallback( + ( + page: number | ((page: number) => number), + cursorData?: CursorState, + pageSize?: number + ) => { + const searchParams = qs.stringify( + qs.parse(location.search, { ignoreQueryPrefix: true }), + { addQueryPrefix: true } + ); + setCurrentPage(page); + if (cursorData) { + history.replace({ + state: { + cursorData, + currentPage: page, + pageSize, + }, + search: searchParams, + }); + } + }, + [setCurrentPage, history, location] + ); + return { paging, handlePagingChange: setPaging, currentPage, - handlePageChange: setCurrentPage, + handlePageChange, pageSize, handlePageSizeChange: handlePageSize, showPagination: paginationVisible, + pagingCursor: pagingCursorHistoryState, }; }; diff --git a/openmetadata-ui/src/main/resources/ui/src/hooks/useTableFilters.ts b/openmetadata-ui/src/main/resources/ui/src/hooks/useTableFilters.ts new file mode 100644 index 00000000000..74052684929 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/hooks/useTableFilters.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2025 Collate. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { isArray, isEmpty, isNil } from 'lodash'; +import qs, { ParsedQs } from 'qs'; +import { useMemo } from 'react'; +import { useHistory } from 'react-router-dom'; +import { useLocationSearch } from './LocationSearch/useLocationSearch'; +import useCustomLocation from './useCustomLocation/useCustomLocation'; + +type FilterState = Record; + +export const useTableFilters = (initialFilters: T) => { + const location = useCustomLocation(); + const history = useHistory(); + const searchQuery = useLocationSearch(); + + const parseFiltersFromUrl = (): T => { + const parsedFilters = { ...initialFilters }; + + for (const key of Object.keys(initialFilters)) { + const paramValue = searchQuery[key]; + const initialValue = initialFilters[key as keyof T]; + + if (!isNil(paramValue)) { + if (typeof initialValue === 'boolean') { + parsedFilters[key as keyof T] = (paramValue === 'true') as T[keyof T]; + } else if (isArray(initialValue)) { + parsedFilters[key as keyof T] = + typeof paramValue === 'string' + ? (paramValue.split(',').map((val) => val.trim()) as T[keyof T]) + : (paramValue as T[keyof T]); + } else { + parsedFilters[key as keyof T] = paramValue as T[keyof T]; + } + } + } + + return parsedFilters; + }; + + // Update URL with the filters applied for the table as query parameters. + const updateUrlWithFilters = (updatedFilters: FilterState) => { + const currentQueryParams = qs.parse(window.location.search, { + ignoreQueryPrefix: true, + }); + + // Merge the existing query params with the updated filters + const mergedQueryParams = { + ...currentQueryParams, + ...updatedFilters, + }; + + Object.keys(mergedQueryParams).forEach((key) => { + const value = mergedQueryParams[key]; + + if (isNil(value) || (isArray(value) && isEmpty(value))) { + delete mergedQueryParams[key]; + } else if (isArray(value)) { + mergedQueryParams[key] = value.join(','); + } + }); + history.replace({ + search: qs.stringify(mergedQueryParams, { + addQueryPrefix: true, + }), + }); + }; + + const filters = useMemo( + () => parseFiltersFromUrl(), + [location.search, initialFilters] + ); + + // Update multiple filters at a time + const setFilters = (newFilters: FilterState) => { + updateUrlWithFilters(newFilters); + }; + + return { filters, setFilters }; +}; diff --git a/openmetadata-ui/src/main/resources/ui/src/mocks/Ingestion.mock.ts b/openmetadata-ui/src/main/resources/ui/src/mocks/Ingestion.mock.ts index 6d74a017446..2e42ef98487 100644 --- a/openmetadata-ui/src/main/resources/ui/src/mocks/Ingestion.mock.ts +++ b/openmetadata-ui/src/main/resources/ui/src/mocks/Ingestion.mock.ts @@ -212,6 +212,15 @@ const mockPaging = { total: 1, }; +const mockPagingCursor = { + cursorData: { + cursorType: null, + cursorValue: null, + }, + currentPage: 1, + pageSize: 10, +}; + const mockCurrentHandleIngestionListUpdate = jest.fn(); const mockCurrentHandleSearchChange = jest.fn(); const mockCurrentOnPageChange = jest.fn(); @@ -240,5 +249,6 @@ export const ingestionProps: IngestionProps = { pageSize: 10, handlePageSizeChange: jest.fn(), showPagination: true, + pagingCursor: mockPagingCursor, }, }; diff --git a/openmetadata-ui/src/main/resources/ui/src/mocks/IngestionListTable.mock.ts b/openmetadata-ui/src/main/resources/ui/src/mocks/IngestionListTable.mock.ts index 9e3a3865f52..4d91e35e80b 100644 --- a/openmetadata-ui/src/main/resources/ui/src/mocks/IngestionListTable.mock.ts +++ b/openmetadata-ui/src/main/resources/ui/src/mocks/IngestionListTable.mock.ts @@ -15,6 +15,7 @@ import { AddIngestionButtonProps } from '../components/Settings/Services/Ingesti import { IngestionListTableProps } from '../components/Settings/Services/Ingestion/IngestionListTable/IngestionListTable.interface'; import { PipelineActionsProps } from '../components/Settings/Services/Ingestion/IngestionListTable/PipelineActions/PipelineActions.interface'; import { PipelineActionsDropdownProps } from '../components/Settings/Services/Ingestion/IngestionListTable/PipelineActions/PipelineActionsDropdown.interface'; +import { CursorType } from '../enums/pagination.enum'; import { ServiceCategory } from '../enums/service.enum'; import { DatabaseServiceType } from '../generated/entity/data/database'; import { ConfigType } from '../generated/entity/services/databaseService'; @@ -146,6 +147,14 @@ export const mockESIngestionData: IngestionPipeline = { deleted: false, provider: ProviderType.User, }; +const mockPagingCursor = { + cursorData: { + cursorType: CursorType.AFTER, + cursorValue: 'mockCursorValue', + }, + currentPage: 1, + pageSize: 10, +}; const mockPagingInfoObj = { paging: { total: 10 }, handlePagingChange: jest.fn(), @@ -154,6 +163,7 @@ const mockPagingInfoObj = { pageSize: 10, handlePageSizeChange: jest.fn(), showPagination: true, + pagingCursor: mockPagingCursor, }; export const mockIngestionListTableProps: IngestionListTableProps = { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.component.tsx index 00e7e11781e..8e82df971e5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.component.tsx @@ -40,6 +40,7 @@ import { getEntityDetailsPath, getVersionPath, INITIAL_PAGING_VALUE, + INITIAL_TABLE_FILTERS, PAGE_SIZE, ROUTES, } from '../../constants/constants'; @@ -65,6 +66,7 @@ import { Include } from '../../generated/type/include'; import { TagLabel } from '../../generated/type/tagLabel'; import { usePaging } from '../../hooks/paging/usePaging'; import { useFqn } from '../../hooks/useFqn'; +import { useTableFilters } from '../../hooks/useTableFilters'; import { FeedCounts } from '../../interface/feed.interface'; import { getDatabaseSchemaDetailsByFQN, @@ -100,13 +102,16 @@ const DatabaseSchemaPage: FunctionComponent = () => { handlePagingChange, currentPage, handlePageChange, + pagingCursor, } = pagingInfo; + const { filters: tableFilters, setFilters } = useTableFilters( + INITIAL_TABLE_FILTERS + ); const { tab: activeTab = EntityTabs.TABLE } = useParams<{ tab: EntityTabs }>(); const { fqn: decodedDatabaseSchemaFQN } = useFqn(); const history = useHistory(); - const [threadType, setThreadType] = useState( ThreadType.Conversation ); @@ -126,7 +131,6 @@ const DatabaseSchemaPage: FunctionComponent = () => { const [threadLink, setThreadLink] = useState(''); const [databaseSchemaPermission, setDatabaseSchemaPermission] = useState(DEFAULT_ENTITY_PERMISSION); - const [showDeletedTables, setShowDeletedTables] = useState(false); const [storedProcedureCount, setStoredProcedureCount] = useState(0); const [updateProfilerSetting, setUpdateProfilerSetting] = @@ -143,7 +147,7 @@ const DatabaseSchemaPage: FunctionComponent = () => { ); const handleShowDeletedTables = (value: boolean) => { - setShowDeletedTables(value); + setFilters({ showDeletedTables: value }); handlePageChange(INITIAL_PAGING_VALUE); }; @@ -226,7 +230,11 @@ const DatabaseSchemaPage: FunctionComponent = () => { const { description: schemaDescription = '' } = response; setDatabaseSchema(response); setDescription(schemaDescription); - setShowDeletedTables(response.deleted ?? false); + if (response.deleted) { + setFilters({ + showDeletedTables: response.deleted, + }); + } } catch (err) { // Error if ((err as AxiosError)?.response?.status === ClientErrors.FORBIDDEN) { @@ -245,7 +253,9 @@ const DatabaseSchemaPage: FunctionComponent = () => { ...params, databaseSchema: decodedDatabaseSchemaFQN, limit: pageSize, - include: showDeletedTables ? Include.Deleted : Include.NonDeleted, + include: tableFilters.showDeletedTables + ? Include.Deleted + : Include.NonDeleted, }); setTableData(res.data); handlePagingChange(res.paging); @@ -255,7 +265,7 @@ const DatabaseSchemaPage: FunctionComponent = () => { setTableDataLoading(false); } }, - [decodedDatabaseSchemaFQN, showDeletedTables, pageSize] + [decodedDatabaseSchemaFQN, tableFilters.showDeletedTables, pageSize] ); const onDescriptionEdit = useCallback((): void => { @@ -422,6 +432,13 @@ const DatabaseSchemaPage: FunctionComponent = () => { ); const handleToggleDelete = (version?: number) => { + history.replace({ + state: { + cursorData: null, + pageSize: null, + currentPage: INITIAL_PAGING_VALUE, + }, + }); setDatabaseSchema((prev) => { if (!prev) { return prev; @@ -461,10 +478,18 @@ const DatabaseSchemaPage: FunctionComponent = () => { ({ cursorType, currentPage }: PagingHandlerParams) => { if (cursorType) { getSchemaTables({ [cursorType]: paging[cursorType] }); + handlePageChange( + currentPage, + { + cursorType: cursorType, + cursorValue: paging[cursorType]!, + }, + pageSize + ); } handlePageChange(currentPage); }, - [paging, getSchemaTables] + [paging, getSchemaTables, handlePageChange] ); const versionHandler = useCallback(() => { @@ -521,10 +546,19 @@ const DatabaseSchemaPage: FunctionComponent = () => { useEffect(() => { if (viewDatabaseSchemaPermission && decodedDatabaseSchemaFQN) { - getSchemaTables({ limit: pageSize }); + if (pagingCursor?.cursorData?.cursorType) { + // Fetch data if cursorType is present in state with cursor Value to handle browser back navigation + getSchemaTables({ + [pagingCursor?.cursorData?.cursorType]: + pagingCursor?.cursorData?.cursorValue, + }); + } else { + // Otherwise, just fetch the data without cursor value + getSchemaTables({ limit: pageSize }); + } } }, [ - showDeletedTables, + tableFilters.showDeletedTables, decodedDatabaseSchemaFQN, viewDatabaseSchemaPermission, deleted, @@ -588,7 +622,7 @@ const DatabaseSchemaPage: FunctionComponent = () => { description, editDescriptionPermission, isEdit, - showDeletedTables, + showDeletedTables: tableFilters.showDeletedTables, tableDataLoading, editCustomAttributePermission, editTagsPermission, @@ -620,7 +654,7 @@ const DatabaseSchemaPage: FunctionComponent = () => { description, editDescriptionPermission, isEdit, - showDeletedTables, + tableFilters.showDeletedTables, tableDataLoading, editCustomAttributePermission, editTagsPermission, diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.test.tsx index e67b7bd520d..7da1b6accdc 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaPage/DatabaseSchemaPage.test.tsx @@ -186,11 +186,18 @@ const API_FIELDS = [ 'dataProducts', ]; +const mockLocationPathname = + '/databaseSchema/sample_data.ecommerce_db.shopify/table'; + jest.mock('react-router-dom', () => ({ useHistory: jest.fn().mockImplementation(() => ({ history: { push: jest.fn(), }, + replace: jest.fn(), + })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, })), useParams: jest.fn().mockImplementation(() => mockParams), })); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaVersionPage/DatabaseSchemaVersionPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaVersionPage/DatabaseSchemaVersionPage.test.tsx index 0106e93a0f1..9a87f13c5ad 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaVersionPage/DatabaseSchemaVersionPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatabaseSchemaVersionPage/DatabaseSchemaVersionPage.test.tsx @@ -151,12 +151,15 @@ jest.mock('../../utils/EntityVersionUtils', () => ({ })); const mockPush = jest.fn(); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ useParams: jest.fn(() => MOCK_PARAMS), useHistory: jest.fn(() => ({ push: mockPush, })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), })); describe('DatabaseSchemaVersionPage', () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/Glossary/GlossaryPage/GlossaryPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/Glossary/GlossaryPage/GlossaryPage.test.tsx index 727c965f5fd..9e96b4b174a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/Glossary/GlossaryPage/GlossaryPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/Glossary/GlossaryPage/GlossaryPage.test.tsx @@ -24,7 +24,7 @@ import GlossaryPage from './GlossaryPage.component'; jest.mock('../../../hooks/useFqn', () => ({ useFqn: jest.fn().mockReturnValue({ fqn: 'Business Glossary' }), })); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ useHistory: () => ({ push: jest.fn(), @@ -33,6 +33,9 @@ jest.mock('react-router-dom', () => ({ useParams: jest.fn().mockReturnValue({ glossaryName: 'GlossaryName', }), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), })); jest.mock('../../../components/MyData/LeftSidebar/LeftSidebar.component', () => diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/NotificationListPage/NotificationListPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/NotificationListPage/NotificationListPage.test.tsx index c9fbf86a420..49240bd8e0c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/NotificationListPage/NotificationListPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/NotificationListPage/NotificationListPage.test.tsx @@ -52,6 +52,7 @@ const MOCK_DATA = [ }, ]; const mockPush = jest.fn(); +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ Link: jest @@ -64,6 +65,9 @@ jest.mock('react-router-dom', () => ({ useHistory: jest.fn().mockImplementation(() => ({ push: mockPush, })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), })); jest.mock('../../rest/alertsAPI', () => ({ diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ObservabilityAlertsPage/ObservabilityAlertsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ObservabilityAlertsPage/ObservabilityAlertsPage.test.tsx index 296a7c18912..c742be7cbd1 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/ObservabilityAlertsPage/ObservabilityAlertsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/ObservabilityAlertsPage/ObservabilityAlertsPage.test.tsx @@ -50,7 +50,7 @@ const MOCK_DATA = [ }, ]; const mockPush = jest.fn(); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ Link: jest .fn() @@ -62,6 +62,9 @@ jest.mock('react-router-dom', () => ({ useHistory: jest.fn().mockImplementation(() => ({ push: mockPush, })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), })); jest.mock('../../rest/alertsAPI', () => ({ diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/PoliciesPage/PoliciesListPage/PoliciesListPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/PoliciesPage/PoliciesListPage/PoliciesListPage.test.tsx index 6900ca2a79e..b36732c95db 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/PoliciesPage/PoliciesListPage/PoliciesListPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/PoliciesPage/PoliciesListPage/PoliciesListPage.test.tsx @@ -18,11 +18,14 @@ import { POLICY_LIST_WITH_PAGING } from '../../RolesPage/Roles.mock'; import PoliciesListPage from './PoliciesListPage'; const mockPush = jest.fn(); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ useHistory: jest.fn().mockImplementation(() => ({ push: mockPush, })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), Link: jest.fn().mockImplementation(({ children, to, ...res }) => ( {children} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/RolesPage/RolesListPage/RolesListPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/RolesPage/RolesListPage/RolesListPage.test.tsx index 8f954cb182e..c27f70daf02 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/RolesPage/RolesListPage/RolesListPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/RolesPage/RolesListPage/RolesListPage.test.tsx @@ -18,11 +18,14 @@ import { ROLES_LIST_WITH_PAGING } from '../Roles.mock'; import RolesListPage from './RolesListPage'; const mockPush = jest.fn(); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ useHistory: jest.fn().mockImplementation(() => ({ push: mockPush, })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), Link: jest.fn().mockImplementation(({ children, to, ...res }) => ( {children} diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedureTab.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedureTab.test.tsx index 0bbb9c6d0d8..4fd4b4e63ef 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedureTab.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/StoredProcedure/StoredProcedureTab.test.tsx @@ -44,11 +44,18 @@ jest.mock('../../components/common/Loader/Loader', () => { }); // mock library imports +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => ({ Link: jest .fn() .mockImplementation(({ children }) => {children}), useParams: jest.fn().mockImplementation(() => ({ fqn: 'something' })), + useHistory: jest.fn().mockImplementation(() => ({ + push: jest.fn(), + })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), })); jest.mock('../../utils/EntityUtils', () => ({ diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.test.tsx index 6db0077b0c9..fd4eb529ab9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TestSuiteDetailsPage/TestSuiteDetailsPage.test.tsx @@ -73,11 +73,14 @@ jest.mock('../../hooks/useApplicationStore', () => { .mockImplementation(() => ({ isAuthDisabled: true })), }; }); - +const mockLocationPathname = '/mock-path'; jest.mock('react-router-dom', () => { return { useHistory: jest.fn().mockImplementation(() => ({ push: jest.fn() })), useParams: jest.fn().mockImplementation(() => ({ fqn: 'testSuiteFQN' })), + useLocation: jest.fn().mockImplementation(() => ({ + pathname: mockLocationPathname, + })), }; }); jest.mock('../../rest/testAPI', () => {