refactor(ui): replace native HTML elements with Ant Design 5 components for consistent theming (#33231)

This commit is contained in:
Enzo Martellucci
2025-05-12 09:00:05 +02:00
committed by GitHub
parent 5267ec2028
commit 67aa991099
36 changed files with 381 additions and 266 deletions

View File

@@ -33,7 +33,8 @@
"memoize-one": "^5.2.1",
"react-table": "^7.8.0",
"regenerator-runtime": "^0.14.1",
"xss": "^1.0.15"
"xss": "^1.0.15",
"antd-v5": "npm:antd@^5.24.6"
},
"peerDependencies": {
"@ant-design/icons": "^5.2.6",

View File

@@ -25,7 +25,7 @@ import {
CSSProperties,
DragEvent,
} from 'react';
import { css, typedMemo, usePrevious } from '@superset-ui/core';
import {
useTable,
usePagination,
@@ -39,7 +39,6 @@ import {
Row,
} from 'react-table';
import { matchSorter, rankings } from 'match-sorter';
import { typedMemo, usePrevious } from '@superset-ui/core';
import { isEqual } from 'lodash';
import GlobalFilter, { GlobalFilterProps } from './components/GlobalFilter';
import SelectPageSize, {
@@ -381,7 +380,13 @@ export default typedMemo(function DataTable<D extends object>({
) : null}
</div>
{searchInput ? (
<div className="col-sm-6">
<div
className="col-sm-6"
css={css`
display: flex;
justify-content: end;
`}
>
<GlobalFilter<D>
searchInput={
typeof searchInput === 'boolean' ? undefined : searchInput

View File

@@ -18,6 +18,7 @@
*/
import { memo, ComponentType, ChangeEventHandler } from 'react';
import { Row, FilterValue } from 'react-table';
import { Input, Space } from 'antd-v5';
import useAsyncState from '../utils/useAsyncState';
export interface SearchInputProps {
@@ -37,15 +38,15 @@ export interface GlobalFilterProps<D extends object> {
function DefaultSearchInput({ count, value, onChange }: SearchInputProps) {
return (
<span className="dt-global-filter">
Search{' '}
<input
className="form-control input-sm"
<Space direction="horizontal" size={4}>
Search
<Input
size="small"
placeholder={`${count} records...`}
value={value}
onChange={onChange}
/>
</span>
</Space>
);
}

View File

@@ -17,8 +17,9 @@
* under the License.
*/
import { memo } from 'react';
import { t } from '@superset-ui/core';
import { css, t } from '@superset-ui/core';
import { formatSelectOptions } from '@superset-ui/chart-controls';
import { Select } from 'antd-v5';
export type SizeOption = [number, string];
@@ -33,16 +34,18 @@ function DefaultSelectRenderer({
options,
onChange,
}: SelectPageSizeRendererProps) {
const { Option } = Select;
return (
<span className="dt-select-page-size form-inline">
{t('Show')}{' '}
<select
className="form-control input-sm"
<Select<number>
value={current}
onBlur={() => {}}
onChange={e => {
onChange(Number((e.target as HTMLSelectElement).value));
}}
onChange={value => onChange(value)}
size="small"
css={theme => css`
width: ${theme.sizeUnit * 18}px;
`}
>
{options.map(option => {
const [size, text] = Array.isArray(option)
@@ -50,16 +53,16 @@ function DefaultSelectRenderer({
: [option, option];
const sizeLabel = size === 0 ? t('all') : size;
return (
<option
aria-label={t('Show %s entries', sizeLabel)}
<Option
key={size}
value={size}
value={Number(size)}
aria-label={t('Show %s entries', sizeLabel)}
>
{text}
</option>
</Option>
);
})}
</select>{' '}
</Select>{' '}
{t('entries')}
</span>
);

View File

@@ -101,13 +101,29 @@ export default styled.div`
/* use padding instead of margin so clientHeight can capture it */
padding-top: 0.5em;
}
.dt-pagination .pagination {
margin: 0;
.dt-pagination .pagination > li > a,
.dt-pagination .pagination > li > span {
background-color: ${theme.colorBgBase};
color: ${theme.colorText};
border-color: ${theme.colorBorderSecondary};
}
.dt-pagination .pagination > li.active > a,
.dt-pagination .pagination > li.active > span,
.dt-pagination .pagination > li.active > a:focus,
.dt-pagination .pagination > li.active > a:hover,
.dt-pagination .pagination > li.active > span:focus,
.dt-pagination .pagination > li.active > span:hover {
background-color: ${theme.colorPrimary};
color: ${theme.colorBgContainer};
border-color: ${theme.colorBorderSecondary};
}
.pagination > li > span.dt-pagination-ellipsis:focus,
.pagination > li > span.dt-pagination-ellipsis:hover {
background: ${theme.colorBgLayout};
border-color: ${theme.colorBorderSecondary};
}
.dt-no-results {

View File

@@ -51,6 +51,7 @@ import {
t,
tn,
useTheme,
SupersetTheme,
} from '@superset-ui/core';
import { Dropdown, Menu, Tooltip } from '@superset-ui/chart-controls';
import {
@@ -62,6 +63,7 @@ import {
TableOutlined,
} from '@ant-design/icons';
import { isEmpty } from 'lodash';
import { Input, Space, Select } from 'antd-v5';
import {
ColorSchemeEnum,
DataColumnMeta,
@@ -178,16 +180,16 @@ function SortIcon<D extends object>({ column }: { column: ColumnInstance<D> }) {
function SearchInput({ count, value, onChange }: SearchInputProps) {
return (
<span className="dt-global-filter">
{t('Search')}{' '}
<input
<Space direction="horizontal" size={4}>
{t('Search')}
<Input
size="small"
aria-label={t('Search %s records', count)}
className="form-control input-sm"
placeholder={tn('search.num_records', count)}
value={value}
onChange={onChange}
/>
</span>
</Space>
);
}
@@ -196,23 +198,22 @@ function SelectPageSize({
current,
onChange,
}: SelectPageSizeRendererProps) {
const { Option } = Select;
return (
<span
className="dt-select-page-size form-inline"
role="group"
aria-label={t('Select page size')}
>
<>
<label htmlFor="pageSizeSelect" className="sr-only">
{t('Select page size')}
</label>
{t('Show')}{' '}
<select
<Select<number>
id="pageSizeSelect"
className="form-control input-sm"
value={current}
onChange={e => {
onChange(Number((e.target as HTMLSelectElement).value));
}}
onChange={value => onChange(value)}
size="small"
css={(theme: SupersetTheme) => css`
width: ${theme.sizeUnit * 18}px;
`}
aria-label={t('Show entries per page')}
>
{options.map(option => {
@@ -220,14 +221,14 @@ function SelectPageSize({
? option
: [option, option];
return (
<option key={size} value={size}>
<Option key={size} value={Number(size)}>
{text}
</option>
</Option>
);
})}
</select>{' '}
</Select>{' '}
{t('entries per page')}
</span>
</>
);
}
@@ -953,7 +954,7 @@ export default function TableChart<D extends DataRecord = DataRecord>(
},
Header: ({ column: col, onClick, style, onDragStart, onDrop }) => (
<th
id={`header-${column.key}`}
id={`header-${column.originalLabel}`}
title={t('Shift + Click to sort by multiple columns')}
className={[className, col.isSorted ? 'is-sorted' : ''].join(' ')}
style={{

View File

@@ -495,7 +495,7 @@ describe('plugin-chart-table', () => {
'rgb(255, 255, 255)',
);
});
it('should display originalLabel in grouped headers', () => {
it('should display original label in grouped headers', () => {
const props = transformProps(testData.comparison);
render(