You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ms...@apache.org on 2025/04/01 18:16:02 UTC
(superset) 01/03: refactor(Table): first working iteration
This is an automated email from the ASF dual-hosted git repository.
msyavuz pushed a commit to branch msyavuz/refactor/use-ant-tables
in repository https://gitbox.apache.org/repos/asf/superset.git
commit e6b555aa128fbd9a58fda8e025d99d0ccfc35cd0
Author: Mehmet Salih Yavuz <sa...@proton.me>
AuthorDate: Tue Apr 1 18:55:12 2025 +0300
refactor(Table): first working iteration
---
superset-frontend/src/components/Table/index.tsx | 3 +-
.../src/components/TableCollection/index.tsx | 404 +++++++--------------
2 files changed, 138 insertions(+), 269 deletions(-)
diff --git a/superset-frontend/src/components/Table/index.tsx b/superset-frontend/src/components/Table/index.tsx
index cf55b7e4b7..fef01289f1 100644
--- a/superset-frontend/src/components/Table/index.tsx
+++ b/superset-frontend/src/components/Table/index.tsx
@@ -50,6 +50,7 @@ export type OnChangeFunction<RecordType> =
export enum TableSize {
Small = 'small',
Middle = 'middle',
+ Large = 'large',
}
export interface TableProps<RecordType> {
@@ -76,7 +77,7 @@ export interface TableProps<RecordType> {
/**
* Controls the size of the table.
*/
- size: TableSize;
+ size?: TableSize;
/**
* Controls if table rows are selectable and if multiple select is supported.
*/
diff --git a/superset-frontend/src/components/TableCollection/index.tsx b/superset-frontend/src/components/TableCollection/index.tsx
index dc97a09c02..7d25cea682 100644
--- a/superset-frontend/src/components/TableCollection/index.tsx
+++ b/superset-frontend/src/components/TableCollection/index.tsx
@@ -19,7 +19,7 @@
import { memo } from 'react';
import cx from 'classnames';
import { TableInstance } from 'react-table';
-import { styled } from '@superset-ui/core';
+import { Table, TableSize, ColumnsType } from 'src/components/Table';
import { Icons } from 'src/components/Icons';
interface TableCollectionProps {
@@ -34,176 +34,28 @@ interface TableCollectionProps {
columnsForWrapText?: string[];
}
-export const Table = styled.table`
- ${({ theme }) => `
- background-color: ${theme.colorBgContainer};
- border-collapse: separate;
- border-radius: ${theme.borderRadius}px;
-
- thead > tr > th {
- border: 0;
- }
-
- tbody {
- tr:first-of-type > td {
- border-top: 0;
- }
- tr > td {
- border-top: 1px solid ${theme.colorSplit};
- }
- }
- th {
- position: sticky;
- top: 0;
-
- &:first-of-type {
- padding-left: ${theme.sizeUnit * 4}px;
- }
-
- &.xs {
- min-width: 25px;
- }
- &.sm {
- min-width: 50px;
- }
- &.md {
- min-width: 75px;
- }
- &.lg {
- min-width: 100px;
- }
- &.xl {
- min-width: 150px;
- }
- &.xxl {
- min-width: 200px;
- }
-
- span {
- white-space: nowrap;
- display: flex;
- align-items: center;
- line-height: 2;
- }
-
- svg {
- display: inline-block;
- position: relative;
- }
- }
-
- td {
- &.xs {
- width: 25px;
- }
- &.sm {
- width: 50px;
- }
- &.md {
- width: 75px;
- }
- &.lg {
- width: 100px;
- }
- &.xl {
- width: 150px;
- }
- &.xxl {
- width: 200px;
- }
- }
-
- .table-cell-loader {
- position: relative;
-
- .loading-bar {
- background-color: ${theme.colorBgTextHover};
- border-radius: 7px;
-
- span {
- visibility: hidden;
- }
- }
-
- .empty-loading-bar {
- display: inline-block;
- width: 100%;
- height: 1.2em;
- }
- }
-
- .actions {
- white-space: nowrap;
- min-width: 100px;
-
- svg,
- i {
- margin-right: 8px;
-
- &:hover {
- path {
- fill: ${theme.colorPrimary};
- }
- }
- }
- }
-
- .table-row {
- .actions {
- opacity: 0;
- font-size: ${theme.fontSizeXL}px;
- display: flex;
- }
-
- &:hover {
- background-color: ${theme.colorBgTextHover};
-
- .actions {
- opacity: 1;
- transition: opacity ease-in ${theme.motionDurationMid};
- }
- }
- }
-
- .table-row-selected {
- background-color: ${theme.colorPrimaryBgHover};
-
- &:hover {
- background-color: ${theme.colorPrimaryBgHover};
- }
- }
-
- .table-cell {
- font-feature-settings: 'tnum' 1;
- text-overflow: ellipsis;
- overflow: hidden;
- max-width: 320px;
- line-height: 1;
- vertical-align: middle;
- &:first-of-type {
- padding-left: ${theme.sizeUnit * 4}px;
- }
- &__wrap {
- white-space: normal;
- }
- &__nowrap {
- white-space: nowrap;
- }
- }
-
- @keyframes loading-shimmer {
- 40% {
- background-position: 100% 0;
- }
-
- 100% {
- background-position: 100% 0;
- }
- }
- `}
-`;
-
-Table.displayName = 'table';
+const mapColumns = (columns: TableInstance['columns']): ColumnsType => {
+ console.log({ columns });
+ return columns.map((column: any) => ({
+ title: column.Header,
+ dataIndex: column.accessor,
+ key: column.accessor,
+ hidden: column.hidden,
+ render: (val, record, index) => {
+ if (column.Cell) {
+ return column.Cell({ row: { original: record, id: index } });
+ }
+ return val;
+ },
+ }));
+};
+
+const mapRows = (rows: TableInstance['rows']): any[] => {
+ console.log({ rows });
+ return rows.map(row => ({
+ ...row.values,
+ }));
+};
export default memo(
({
@@ -216,115 +68,131 @@ export default memo(
loading,
highlightRowId,
columnsForWrapText,
- }: TableCollectionProps) => (
- <Table
- {...getTableProps()}
- className="table table-hover"
- data-test="listview-table"
- >
- <thead>
- {headerGroups.map(headerGroup => (
- <tr {...headerGroup.getHeaderGroupProps()}>
- {headerGroup.headers.map(column => {
- let sortIcon = <Icons.Sort />;
- if (column.isSorted && column.isSortedDesc) {
- sortIcon = <Icons.SortDesc />;
- } else if (column.isSorted && !column.isSortedDesc) {
- sortIcon = <Icons.SortAsc />;
- }
- return column.hidden ? null : (
- <th
- {...column.getHeaderProps(
- column.canSort ? column.getSortByToggleProps() : {},
- )}
- data-test="sort-header"
- className={cx({
- [column.size || '']: column.size,
- })}
- >
- <span>
- {column.render('Header')}
- {column.canSort && sortIcon}
- </span>
- </th>
- );
- })}
- </tr>
- ))}
- </thead>
- <tbody {...getTableBodyProps()}>
- {loading &&
- rows.length === 0 &&
- [...new Array(12)].map((_, i) => (
- <tr key={i}>
- {columns.map((column, i2) => {
- if (column.hidden) return null;
- return (
- <td
- key={i2}
- className={cx('table-cell', {
- 'table-cell-loader': loading,
+ }: TableCollectionProps) => {
+ console.log({
+ mappedColumns: mapColumns(columns),
+ });
+
+ return (
+ <Table
+ columns={mapColumns(columns)}
+ data={mapRows(rows)}
+ size={TableSize.Large}
+ />
+ );
+ return (
+ <Table
+ {...getTableProps()}
+ className="table table-hover"
+ data-test="listview-table"
+ >
+ <thead>
+ {headerGroups.map(headerGroup => (
+ <tr {...headerGroup.getHeaderGroupProps()}>
+ {headerGroup.headers.map(column => {
+ let sortIcon = <Icons.Sort />;
+ if (column.isSorted && column.isSortedDesc) {
+ sortIcon = <Icons.SortDesc />;
+ } else if (column.isSorted && !column.isSortedDesc) {
+ sortIcon = <Icons.SortAsc />;
+ }
+ return column.hidden ? null : (
+ <th
+ {...column.getHeaderProps(
+ column.canSort ? column.getSortByToggleProps() : {},
+ )}
+ data-test="sort-header"
+ className={cx({
+ [column.size || '']: column.size,
})}
>
- <span
- className="loading-bar empty-loading-bar"
- role="progressbar"
- aria-label="loading"
- />
- </td>
+ <span>
+ {column.render('Header')}
+ {column.canSort && sortIcon}
+ </span>
+ </th>
);
})}
</tr>
))}
- {rows.length > 0 &&
- rows.map(row => {
- prepareRow(row);
- // @ts-ignore
- const rowId = row.original.id;
- return (
- <tr
- data-test="table-row"
- {...row.getRowProps()}
- className={cx('table-row', {
- 'table-row-selected':
- row.isSelected ||
- (typeof rowId !== 'undefined' && rowId === highlightRowId),
- })}
- >
- {row.cells.map(cell => {
- if (cell.column.hidden) return null;
- const columnCellProps = cell.column.cellProps || {};
- const isWrapText = columnsForWrapText?.includes(
- cell.column.Header as string,
- );
+ </thead>
+ <tbody {...getTableBodyProps()}>
+ {loading &&
+ rows.length === 0 &&
+ [...new Array(12)].map((_, i) => (
+ <tr key={i}>
+ {columns.map((column, i2) => {
+ if (column.hidden) return null;
return (
<td
- data-test="table-row-cell"
- className={cx(
- `table-cell table-cell__${
- isWrapText ? 'wrap' : 'nowrap'
- }`,
- {
- 'table-cell-loader': loading,
- [cell.column.size || '']: cell.column.size,
- },
- )}
- {...cell.getCellProps()}
- {...columnCellProps}
+ key={i2}
+ className={cx('table-cell', {
+ 'table-cell-loader': loading,
+ })}
>
<span
- className={cx({ 'loading-bar': loading })}
- role={loading ? 'progressbar' : undefined}
- >
- <span data-test="cell-text">{cell.render('Cell')}</span>
- </span>
+ className="loading-bar empty-loading-bar"
+ role="progressbar"
+ aria-label="loading"
+ />
</td>
);
})}
</tr>
- );
- })}
- </tbody>
- </Table>
- ),
+ ))}
+ {rows.length > 0 &&
+ rows.map(row => {
+ prepareRow(row);
+ // @ts-ignore
+ const rowId = row.original.id;
+ return (
+ <tr
+ data-test="table-row"
+ {...row.getRowProps()}
+ className={cx('table-row', {
+ 'table-row-selected':
+ row.isSelected ||
+ (typeof rowId !== 'undefined' &&
+ rowId === highlightRowId),
+ })}
+ >
+ {row.cells.map(cell => {
+ if (cell.column.hidden) return null;
+ const columnCellProps = cell.column.cellProps || {};
+ const isWrapText = columnsForWrapText?.includes(
+ cell.column.Header as string,
+ );
+ return (
+ <td
+ data-test="table-row-cell"
+ className={cx(
+ `table-cell table-cell__${
+ isWrapText ? 'wrap' : 'nowrap'
+ }`,
+ {
+ 'table-cell-loader': loading,
+ [cell.column.size || '']: cell.column.size,
+ },
+ )}
+ {...cell.getCellProps()}
+ {...columnCellProps}
+ >
+ <span
+ className={cx({ 'loading-bar': loading })}
+ role={loading ? 'progressbar' : undefined}
+ >
+ <span data-test="cell-text">
+ {cell.render('Cell')}
+ </span>
+ </span>
+ </td>
+ );
+ })}
+ </tr>
+ );
+ })}
+ </tbody>
+ </Table>
+ );
+ },
);