diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.component.tsx index 75f1726dade3..c13354a1d6f9 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.component.tsx @@ -32,11 +32,6 @@ import { import { Operation } from '../../../generated/entity/policies/policy'; import { TagSource } from '../../../generated/type/tagLabel'; import { usePaging } from '../../../hooks/paging/usePaging'; -import { useFqn } from '../../../hooks/useFqn'; -import { - getTableColumnsByFQN, - searchTableColumnsByFQN, -} from '../../../rest/tableAPI'; import { getPartialNameFromTableFQN } from '../../../utils/CommonUtils'; import { getColumnsDataWithVersionChanges, @@ -45,6 +40,7 @@ import { getEntityVersionByField, getEntityVersionTags, } from '../../../utils/EntityVersionUtils'; +import { searchInColumns } from '../../../utils/EntityUtils'; import { getPrioritizedViewPermission } from '../../../utils/PermissionsUtils'; import { getVersionPath } from '../../../utils/RouterUtils'; import { pruneEmptyChildren } from '../../../utils/TableUtils'; @@ -89,56 +85,24 @@ const TableVersion: React.FC = ({ paging, handlePagingChange, } = usePaging(PAGE_SIZE_LARGE); - const { fqn: tableFqn } = useFqn(); const [searchText, setSearchText] = useState(''); - // Pagination state for columns - const [tableColumns, setTableColumns] = useState([]); - const [columnsLoading, setColumnsLoading] = useState(true); // Start with loading state + const columnsLoading = isVersionLoading; const [changeDescription, setChangeDescription] = useState( currentVersionData.changeDescription as ChangeDescription ); - // Function to fetch paginated columns or search results - const fetchPaginatedColumns = useCallback( - async (page = 1, searchQuery?: string) => { - if (!tableFqn) { - return; - } + const allHistoricalColumns = useMemo( + () => pruneEmptyChildren(currentVersionData.columns) ?? [], + [currentVersionData.columns] + ); - setColumnsLoading(true); - try { - const offset = (page - 1) * pageSize; + const filteredHistoricalColumns = useMemo(() => { + if (!searchText) { + return allHistoricalColumns; + } - // Use search API if there's a search query, otherwise use regular pagination - const response = searchQuery - ? await searchTableColumnsByFQN(tableFqn, { - q: searchQuery, - limit: pageSize, - offset: offset, - fields: 'tags', - }) - : await getTableColumnsByFQN(tableFqn, { - limit: pageSize, - offset: offset, - fields: 'tags', - }); - - setTableColumns(pruneEmptyChildren(response.data) || []); - handlePagingChange(response.paging); - } catch { - // Set empty state if API fails - setTableColumns([]); - handlePagingChange({ - offset: 1, - limit: pageSize, - total: 0, - }); - } finally { - setColumnsLoading(false); - } - }, - [tableFqn, pageSize] - ); + return searchInColumns(allHistoricalColumns, searchText); + }, [allHistoricalColumns, searchText]); const handleSearchAction = useCallback( (searchValue: string) => { @@ -150,10 +114,9 @@ const TableVersion: React.FC = ({ const handleColumnsPageChange = useCallback( ({ currentPage }: PagingHandlerParams) => { - fetchPaginatedColumns(currentPage, searchText); handlePageChange(currentPage); }, - [paging, fetchPaginatedColumns, searchText] + [handlePageChange] ); const paginationProps = useMemo( @@ -161,7 +124,7 @@ const TableVersion: React.FC = ({ currentPage, showPagination, isLoading: columnsLoading, - isNumberBased: Boolean(searchText), + isNumberBased: true, pageSize, paging, pagingHandler: handleColumnsPageChange, @@ -171,7 +134,6 @@ const TableVersion: React.FC = ({ currentPage, showPagination, columnsLoading, - searchText, pageSize, paging, handleColumnsPageChange, @@ -196,10 +158,17 @@ const TableVersion: React.FC = ({ [changeDescription, owners, tier, domains] ); - const columns = useMemo(() => { - const colList = cloneDeep(tableColumns); + const tableColumns = useMemo(() => { + const offset = (currentPage - 1) * pageSize; + + return filteredHistoricalColumns.slice(offset, offset + pageSize); + }, [filteredHistoricalColumns, currentPage, pageSize]); - return getColumnsDataWithVersionChanges(changeDescription, colList); + const columns = useMemo(() => { + return getColumnsDataWithVersionChanges( + changeDescription, + cloneDeep(tableColumns) + ); }, [tableColumns, changeDescription]); const handleTabChange = (activeKey: string) => { @@ -355,20 +324,17 @@ const TableVersion: React.FC = ({ ] ); - // Fetch columns when search changes useEffect(() => { - if (tableFqn && !isVersionLoading) { - // Reset to first page when search changes - fetchPaginatedColumns(currentPage, searchText || undefined); + if (isVersionLoading) { + return; } - }, [ - isVersionLoading, - tableFqn, - searchText, - fetchPaginatedColumns, - pageSize, - currentPage, - ]); + const offset = (currentPage - 1) * pageSize; + handlePagingChange({ + offset, + limit: pageSize, + total: filteredHistoricalColumns.length, + }); + }, [isVersionLoading, filteredHistoricalColumns, currentPage, pageSize, handlePagingChange]); return ( <> diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.test.tsx index fef0dec17e71..3c04facfe024 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Database/TableVersion/TableVersion.test.tsx @@ -12,9 +12,14 @@ */ import { act, fireEvent, render, screen } from '@testing-library/react'; +import { DataType } from '../../../generated/entity/data/table'; import { ENTITY_PERMISSIONS } from '../../../mocks/Permissions.mock'; -import { tableVersionMockProps } from '../../../mocks/TableVersion.mock'; +import { + mockTableData, + tableVersionMockProps, +} from '../../../mocks/TableVersion.mock'; import TableVersion from './TableVersion.component'; +import VersionTable from '../../Entity/VersionTable/VersionTable.component'; const mockNavigate = jest.fn(); jest.mock( @@ -138,6 +143,50 @@ describe('TableVersion tests', () => { ); }); + it('should pass historical columns from currentVersionData to VersionTable, not from a live API call', async () => { + const historicalVersionData = { + ...mockTableData, + columns: [ + { + name: 'order_amount', + dataType: DataType.Decimal, + dataTypeDisplay: 'decimal(9,1)', + precision: 9, + scale: 1, + fullyQualifiedName: + 'sample_data.ecommerce_db.shopify.raw_product_catalog.order_amount', + tags: [], + ordinalPosition: 1, + }, + ], + changeDescription: { + fieldsAdded: [], + fieldsUpdated: [], + fieldsDeleted: [], + previousVersion: 0.1, + }, + }; + + const mockedVersionTable = VersionTable as jest.MockedFunction; + mockedVersionTable.mockClear(); + + await act(async () => { + render( + + ); + }); + + const calls = mockedVersionTable.mock.calls; + expect(calls.length).toBeGreaterThan(0); + const columnsPassedToVersionTable = calls[calls.length - 1][0].columns; + + expect(columnsPassedToVersionTable).toHaveLength(1); + expect(columnsPassedToVersionTable[0].dataTypeDisplay).toBe('decimal(9,1)'); + }); + describe('ViewCustomFields Permission Tests', () => { it('should render custom properties tab when ViewCustomFields is true', async () => { await act(async () => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Entity/VersionTable/VersionTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Entity/VersionTable/VersionTable.component.tsx index 420caf598c0e..2159a90ca716 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Entity/VersionTable/VersionTable.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Entity/VersionTable/VersionTable.component.tsx @@ -58,14 +58,14 @@ function VersionTable({ const [expandedRowKeys, setExpandedRowKeys] = useState([]); const data = useMemo(() => { - if (searchText) { + if (searchText && !handelSearchCallback) { const searchCols = searchInColumns(columns, searchText); return makeData(searchCols); - } else { - return makeData(columns); } - }, [searchText, columns]); + + return makeData(columns); + }, [searchText, columns, handelSearchCallback]); const renderColumnName = useCallback( (name: T['name'], record: T) => {