+ );
+ });
+ }}
+ />
+
+ );
+ expect(screen.getAllByRole('table').length).toBe(1);
+ expect(screen.getAllByRole('row').length).toBe(3);
+ expect(screen.getAllByRole('columnheader').length).toBe(2);
+
+ // Check onClick on column
+ const column1 = screen.getByText('col1');
+ fireEvent.click(column1);
+ // dependency on vite-jest to check useState sortColumn if col1 gets set.
+ });
+});
diff --git a/web/vtadmin/src/components/dataTable/SortedDataTable.tsx b/web/vtadmin/src/components/dataTable/SortedDataTable.tsx
new file mode 100644
index 00000000000..a8766aa9ee3
--- /dev/null
+++ b/web/vtadmin/src/components/dataTable/SortedDataTable.tsx
@@ -0,0 +1,170 @@
+/**
+ * Copyright 2025 The Vitess Authors.
+ *
+ * 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 * as React from 'react';
+import { useLocation } from 'react-router-dom';
+
+import { useURLPagination } from '../../hooks/useURLPagination';
+import { useURLQuery } from '../../hooks/useURLQuery';
+import { stringify } from '../../util/queryString';
+import { PaginationNav } from './PaginationNav';
+import { useCallback, useMemo, useState } from 'react';
+import { Icon, Icons } from '../Icon';
+
+export interface ColumnProps {
+ // Coulmn display name string | JSX.Element
+ display: string | JSX.Element;
+ // Column data accessor
+ accessor: string;
+}
+
+interface Props {
+ // When passing a JSX.Element, note that the column element
+ // will be rendered *inside* a
+ );
+};
diff --git a/web/vtadmin/src/components/routes/Schemas.tsx b/web/vtadmin/src/components/routes/Schemas.tsx
index fff3bb8b2db..5da3870efbc 100644
--- a/web/vtadmin/src/components/routes/Schemas.tsx
+++ b/web/vtadmin/src/components/routes/Schemas.tsx
@@ -25,7 +25,7 @@ import { formatBytes } from '../../util/formatBytes';
import { getTableDefinitions } from '../../util/tableDefinitions';
import { DataCell } from '../dataTable/DataCell';
import { DataFilter } from '../dataTable/DataFilter';
-import { DataTable } from '../dataTable/DataTable';
+import { ColumnProps, SortedDataTable } from '../dataTable/SortedDataTable';
import { ContentContainer } from '../layout/ContentContainer';
import { WorkspaceHeader } from '../layout/WorkspaceHeader';
import { WorkspaceTitle } from '../layout/WorkspaceTitle';
@@ -33,31 +33,43 @@ import { KeyspaceLink } from '../links/KeyspaceLink';
import { QueryLoadingPlaceholder } from '../placeholders/QueryLoadingPlaceholder';
import { HelpTooltip } from '../tooltip/HelpTooltip';
-const TABLE_COLUMNS = [
- 'Keyspace',
- 'Table',
-
- Approx. Size{' '}
-
- Size is an approximate value derived from INFORMATION_SCHEMA.
-
- }
- />
-
,
-
- Approx. Rows{' '}
-
- Row count is an approximate value derived from INFORMATION_SCHEMA
- . Actual values may vary by as much as 40% to 50%.
-
- }
- />
-
+ Approx. Rows{' '}
+
+ Row count is an approximate value derived from{' '}
+ INFORMATION_SCHEMA. Actual values may vary by as much as
+ 40% to 50%.
+
+ }
+ />
+