From 67aa991099df4392fed7fce9f55110e4a95cfe9f Mon Sep 17 00:00:00 2001
From: Enzo Martellucci <52219496+EnxDev@users.noreply.github.com>
Date: Mon, 12 May 2025 09:00:05 +0200
Subject: [PATCH] refactor(ui): replace native HTML elements with Ant Design 5
components for consistent theming (#33231)
---
.../e2e/explore/visualizations/table.test.ts | 12 +-
superset-frontend/package-lock.json | 1 +
.../src/components/ControlHeader.tsx | 31 +++--
.../src/components/Dropdown.tsx | 3 +-
.../src/components/Menu.tsx | 3 +-
.../src/components/MetricOption.tsx | 20 +--
.../src/components/Select.tsx | 9 +-
.../components/RadioButtonControl.tsx | 22 ++-
.../tooltip/TooltipTable.tsx | 79 ++++++-----
.../tooltip/TooltipTable.test.tsx | 47 ++++---
.../shared/components/VerifyCORS.tsx | 9 +-
.../src/react-pivottable/Styles.js | 1 +
.../plugins/plugin-chart-table/package.json | 3 +-
.../src/DataTable/DataTable.tsx | 11 +-
.../src/DataTable/components/GlobalFilter.tsx | 11 +-
.../DataTable/components/SelectPageSize.tsx | 27 ++--
.../plugins/plugin-chart-table/src/Styles.tsx | 20 ++-
.../plugin-chart-table/src/TableChart.tsx | 41 +++---
.../test/TableChart.test.tsx | 2 +-
.../src/assets/stylesheets/superset.less | 4 -
.../components/ErrorMessage/ErrorAlert.tsx | 12 +-
.../src/components/ListView/ListView.tsx | 131 +++++++++---------
.../src/components/Pagination/Wrapper.tsx | 21 +--
superset-frontend/src/components/index.ts | 2 +
.../components/PropertiesModal/index.tsx | 27 ++--
.../components/PropertiesModal/index.tsx | 17 ++-
.../ZoomConfigControl/ZoomConfigControl.tsx | 4 +-
.../src/features/alerts/AlertReportModal.tsx | 7 +-
.../AnnotationLayerModal.test.jsx | 7 +-
.../annotationLayers/AnnotationLayerModal.tsx | 7 +-
.../cssTemplates/CssTemplateModal.test.jsx | 4 +-
.../cssTemplates/CssTemplateModal.tsx | 7 +-
.../DatabaseConnectionForm/TableCatalog.tsx | 5 +-
.../databases/DatabaseModal/ModalHeader.tsx | 25 ++--
.../features/reports/ReportModal/index.tsx | 10 +-
.../features/rls/RowLevelSecurityModal.tsx | 5 +-
36 files changed, 381 insertions(+), 266 deletions(-)
diff --git a/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/table.test.ts b/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/table.test.ts
index 603cc7f2c8d..ed4689a37f5 100644
--- a/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/table.test.ts
+++ b/superset-frontend/cypress-base/cypress/e2e/explore/visualizations/table.test.ts
@@ -193,7 +193,9 @@ describe('Visualization > Table', () => {
});
// should display in raw records mode
- cy.get('div[data-test="query_mode"] .btn.active').contains('Raw records');
+ cy.get(
+ 'div[data-test="query_mode"] .antd5-radio-button-wrapper-checked',
+ ).contains('Raw records');
cy.get('div[data-test="all_columns"]').should('be.visible');
cy.get('div[data-test="groupby"]').should('not.exist');
@@ -201,8 +203,12 @@ describe('Visualization > Table', () => {
cy.get('[data-test="row-count-label"]').contains('100 rows');
// should allow switch back to aggregate mode
- cy.get('div[data-test="query_mode"] .btn').contains('Aggregate').click();
- cy.get('div[data-test="query_mode"] .btn.active').contains('Aggregate');
+ cy.get('div[data-test="query_mode"] .antd5-radio-button-wrapper')
+ .contains('Aggregate')
+ .click();
+ cy.get(
+ 'div[data-test="query_mode"] .antd5-radio-button-wrapper-checked',
+ ).contains('Aggregate');
cy.get('div[data-test="all_columns"]').should('not.exist');
cy.get('div[data-test="groupby"]').should('be.visible');
});
diff --git a/superset-frontend/package-lock.json b/superset-frontend/package-lock.json
index 08682f0b907..8ff096847a0 100644
--- a/superset-frontend/package-lock.json
+++ b/superset-frontend/package-lock.json
@@ -54988,6 +54988,7 @@
"@react-icons/all-files": "^4.1.0",
"@types/d3-array": "^2.9.0",
"@types/react-table": "^7.7.20",
+ "antd-v5": "npm:antd@^5.24.6",
"classnames": "^2.5.1",
"d3-array": "^2.4.0",
"lodash": "^4.17.21",
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx
index 0172b5656a5..65d52fe5579 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/ControlHeader.tsx
@@ -17,7 +17,8 @@
* under the License.
*/
import { ReactNode } from 'react';
-import { t } from '@superset-ui/core';
+import { t, css } from '@superset-ui/core';
+import { InfoCircleOutlined } from '@ant-design/icons';
import { InfoTooltipWithTrigger } from './InfoTooltipWithTrigger';
import { Tooltip } from './Tooltip';
@@ -88,6 +89,7 @@ export function ControlHeader({
return null;
}
const labelClass = validationErrors.length > 0 ? 'text-danger' : '';
+
return (
@@ -105,18 +107,24 @@ export function ControlHeader({
{warning && (
- {/* TODO: Remove fa-icon */}
- {/* eslint-disable-next-line icons/no-fa-icons-usage */}
-
+ css`
+ font-size: ${theme.sizeUnit * 3}px;
+ color: ${theme.colorError};
+ `}
+ />
{' '}
)}
{danger && (
- {/* TODO: Remove fa-icon */}
- {/* eslint-disable-next-line icons/no-fa-icons-usage */}
-
+ css`
+ font-size: ${theme.sizeUnit * 3}px;
+ color: ${theme.colorError};
+ `}
+ />{' '}
{' '}
)}
@@ -127,9 +135,12 @@ export function ControlHeader({
placement="top"
title={validationErrors.join(' ')}
>
- {/* TODO: Remove fa-icon */}
- {/* eslint-disable-next-line icons/no-fa-icons-usage */}
-
+
css`
+ font-size: ${theme.sizeUnit * 3}px;
+ color: ${theme.colorError};
+ `}
+ />{' '}
{' '}
)}
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
index 032365ebd5d..6e0bcdf35a3 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/Dropdown.tsx
@@ -17,5 +17,4 @@
* under the License.
*/
-export { Dropdown } from 'antd';
-export type { DropDownProps } from 'antd/lib/dropdown';
+export { Dropdown, type DropDownProps } from 'antd-v5';
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
index 89a7405cde5..97c20923c0b 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/Menu.tsx
@@ -17,5 +17,4 @@
* under the License.
*/
-export { Menu } from 'antd';
-export type { MenuProps } from 'antd/lib/menu';
+export { Menu, type MenuProps } from 'antd-v5';
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/MetricOption.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/MetricOption.tsx
index d3f2df4c885..dda211db6f4 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/components/MetricOption.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/MetricOption.tsx
@@ -25,6 +25,7 @@ import {
SafeMarkdown,
SupersetTheme,
} from '@superset-ui/core';
+import { Typography } from 'antd-v5';
import { InfoTooltipWithTrigger } from './InfoTooltipWithTrigger';
import { ColumnTypeLabel } from './ColumnTypeLabel/ColumnTypeLabel';
import CertifiedIconWithTooltip from './CertifiedIconWithTooltip';
@@ -61,13 +62,6 @@ export function MetricOption({
url = '',
}: MetricOptionProps) {
const verbose = metric.verbose_name || metric.metric_name || metric.label;
- const link = url ? (
-
- {verbose}
-
- ) : (
- verbose
- );
const label = (
- {link}
+ {url ? (
+
+ {verbose}
+
+ ) : (
+ verbose
+ )}
);
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/components/Select.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/components/Select.tsx
index 01fb74d2e8e..148ddbf3ff4 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/components/Select.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/components/Select.tsx
@@ -17,7 +17,10 @@
* under the License.
*/
import { useState, ReactNode } from 'react';
-import AntdSelect, { SelectProps as AntdSelectProps } from 'antd/lib/select';
+import {
+ Select as AntdSelect,
+ type SelectProps as AntdSelectProps,
+} from 'antd-v5';
export const { Option }: any = AntdSelect;
@@ -35,7 +38,7 @@ export type SelectProps = Omit, 'options'> & {
export default function Select({
creatable,
onSearch,
- dropdownMatchSelectWidth = false,
+ popupMatchSelectWidth = false,
minWidth = '100%',
showSearch: showSearch_ = true,
onChange,
@@ -73,7 +76,7 @@ export default function Select({
return (
- dropdownMatchSelectWidth={dropdownMatchSelectWidth}
+ popupMatchSelectWidth={popupMatchSelectWidth}
showSearch={showSearch}
onSearch={handleSearch}
onChange={handleChange}
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/RadioButtonControl.tsx b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/RadioButtonControl.tsx
index 81bca2c4d40..03cb83d27d3 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/RadioButtonControl.tsx
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/components/RadioButtonControl.tsx
@@ -18,6 +18,7 @@
*/
import { ReactNode } from 'react';
import { JsonValue, useTheme } from '@superset-ui/core';
+import { Radio } from 'antd-v5';
import { ControlHeader } from '../../components/ControlHeader';
// [value, label]
@@ -71,22 +72,17 @@ export default function RadioButtonControl({
}}
>
-
+ onChange(e.target.value)}
+ >
{options.map(([val, label]) => (
-
+
))}
-
+
);
}
diff --git a/superset-frontend/packages/superset-ui-core/src/chart-composition/tooltip/TooltipTable.tsx b/superset-frontend/packages/superset-ui-core/src/chart-composition/tooltip/TooltipTable.tsx
index 4952d821f1a..949cb609948 100644
--- a/superset-frontend/packages/superset-ui-core/src/chart-composition/tooltip/TooltipTable.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/chart-composition/tooltip/TooltipTable.tsx
@@ -16,8 +16,8 @@
* specific language governing permissions and limitations
* under the License.
*/
-
-import { CSSProperties, PureComponent, ReactNode } from 'react';
+import { CSSProperties, ReactNode } from 'react';
+import { Table, type TableColumnsType } from 'antd-v5';
interface TooltipRowData {
key: string | number;
@@ -27,43 +27,52 @@ interface TooltipRowData {
valueStyle?: CSSProperties;
}
-const defaultProps = {
- className: '',
- data: [] as TooltipRowData[],
-};
-
-type Props = {
+interface TooltipTableProps {
className?: string;
data: TooltipRowData[];
-} & Readonly
;
+}
const VALUE_CELL_STYLE: CSSProperties = { paddingLeft: 8, textAlign: 'right' };
-export default class TooltipTable extends PureComponent {
- static defaultProps = defaultProps;
+const TooltipTable = ({ className = '', data }: TooltipTableProps) => {
+ const columns: TableColumnsType = [
+ {
+ title: '',
+ dataIndex: 'keyColumn',
+ key: 'keyColumn',
+ render: (text, record) => (
+ {record.keyColumn ?? record.key}
+ ),
+ },
+ {
+ title: '',
+ dataIndex: 'valueColumn',
+ key: 'valueColumn',
+ align: 'right',
+ render: (text, record) => (
+
+ {record.valueColumn}
+
+ ),
+ },
+ ];
- render() {
- const { className, data } = this.props;
+ return (
+
+ );
+};
- return (
-
-
- {data.map(({ key, keyColumn, keyStyle, valueColumn, valueStyle }) => (
-
- | {keyColumn ?? key} |
-
- {valueColumn}
- |
-
- ))}
-
-
- );
- }
-}
+export default TooltipTable;
diff --git a/superset-frontend/packages/superset-ui-core/test/chart-composition/tooltip/TooltipTable.test.tsx b/superset-frontend/packages/superset-ui-core/test/chart-composition/tooltip/TooltipTable.test.tsx
index 7df4e8c5faa..c27cb44f4c5 100644
--- a/superset-frontend/packages/superset-ui-core/test/chart-composition/tooltip/TooltipTable.test.tsx
+++ b/superset-frontend/packages/superset-ui-core/test/chart-composition/tooltip/TooltipTable.test.tsx
@@ -18,20 +18,25 @@
*/
import '@testing-library/jest-dom';
-import { screen, render } from '@testing-library/react';
+import { screen, render, within } from '@testing-library/react';
import { TooltipTable } from '@superset-ui/core';
import { CSSProperties } from 'react';
describe('TooltipTable', () => {
it('sets className', () => {
- const { container } = render();
- expect(container.querySelector('[class="test-class"]')).toBeInTheDocument();
+ const { container } = render(
+ ,
+ );
+ expect(container.querySelector('.test-class')).toBeInTheDocument();
});
it('renders empty table', () => {
- const { container } = render();
- expect(container.querySelector('tbody')).toBeInTheDocument();
- expect(container.querySelector('tr')).not.toBeInTheDocument();
+ render();
+ const table = screen.getByRole('table');
+ expect(table).toBeInTheDocument();
+ const rows = within(table).queryAllByRole('row');
+ expect(rows.length).toBe(1);
+ expect(rows[0]).toHaveTextContent(/No Data|empty/i);
});
it('renders table with content', async () => {
@@ -41,29 +46,33 @@ describe('TooltipTable', () => {
keyColumn: 'Cersei',
keyStyle: { padding: '10' },
valueColumn: 2,
- valueStyle: { textAlign: 'right' } as CSSProperties,
+ valueStyle: { textAlign: 'right' as CSSProperties['textAlign'] },
},
{
key: 'Jaime',
keyColumn: 'Jaime',
keyStyle: { padding: '10' },
valueColumn: 1,
- valueStyle: { textAlign: 'right' } as CSSProperties,
- },
- {
- key: 'Tyrion',
- keyStyle: { padding: '10' },
- valueColumn: 2,
+ valueStyle: { textAlign: 'right' as CSSProperties['textAlign'] },
},
+ { key: 'Tyrion', keyStyle: { padding: '10' }, valueColumn: 2 },
];
render();
- for await (const { key, valueColumn } of data) {
- const keyCell = await screen.findByText(key);
- const valueCell = keyCell?.nextSibling as HTMLElement;
- expect(keyCell).toBeInTheDocument();
- expect(valueCell?.textContent).toEqual(String(valueColumn));
- }
+ await Promise.all(
+ data.map(async ({ keyColumn, key, valueColumn }) => {
+ const keyText = keyColumn ?? key;
+ const keyCell = await screen.findByText(keyText);
+ expect(keyCell).toBeInTheDocument();
+
+ const row = keyCell.closest('tr');
+ expect(row).toBeInTheDocument();
+
+ const cells = within(row!).getAllByRole('cell');
+ expect(cells[0]).toHaveTextContent(String(keyText));
+ expect(cells[1]).toHaveTextContent(String(valueColumn));
+ }),
+ );
});
});
diff --git a/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx b/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx
index 82d3c536d43..d87f83bccc6 100644
--- a/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx
+++ b/superset-frontend/packages/superset-ui-demo/storybook/shared/components/VerifyCORS.tsx
@@ -25,6 +25,7 @@ import {
SupersetApiError,
t,
} from '@superset-ui/core';
+import { Button } from 'antd-v5';
import ErrorMessage from './ErrorMessage';
export type Props = {
@@ -117,13 +118,9 @@ export default class VerifyCORS extends Component {
3) click below to verify authentication. You may debug CORS further
using the `@superset-ui/connection` story.
-
diff --git a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js
index 3a7ff4c40be..ceec36621c0 100644
--- a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js
+++ b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/Styles.js
@@ -33,6 +33,7 @@ export const Styles = styled.div`
}
table thead {
+ background-color: ${theme.colorBgBase};
position: ${isDashboardEditMode ? 'inherit' : 'sticky'};
top: 0;
}
diff --git a/superset-frontend/plugins/plugin-chart-table/package.json b/superset-frontend/plugins/plugin-chart-table/package.json
index 4abf7dacfe7..418a6a1b609 100644
--- a/superset-frontend/plugins/plugin-chart-table/package.json
+++ b/superset-frontend/plugins/plugin-chart-table/package.json
@@ -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",
diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
index 21ce6541cf2..a9d8d0d1ba9 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/DataTable.tsx
@@ -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({
) : null}
{searchInput ? (
-
+
searchInput={
typeof searchInput === 'boolean' ? undefined : searchInput
diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/GlobalFilter.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/GlobalFilter.tsx
index 89e18140f22..24e3c9031b1 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/GlobalFilter.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/GlobalFilter.tsx
@@ -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 {
function DefaultSearchInput({ count, value, onChange }: SearchInputProps) {
return (
-
- Search{' '}
-
+ Search
+
-
+
);
}
diff --git a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx
index 02052f10304..b172cdf5809 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/DataTable/components/SelectPageSize.tsx
@@ -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 (
{t('Show')}{' '}
- {' '}
+ {' '}
{t('entries')}
);
diff --git a/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx b/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx
index 8c861bf6e3f..8079484ace0 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/Styles.tsx
@@ -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 {
diff --git a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
index 590e4b862a7..eac9e008eaf 100644
--- a/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
+++ b/superset-frontend/plugins/plugin-chart-table/src/TableChart.tsx
@@ -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({ column }: { column: ColumnInstance }) {
function SearchInput({ count, value, onChange }: SearchInputProps) {
return (
-
- {t('Search')}{' '}
-
+ {t('Search')}
+
-
+
);
}
@@ -196,23 +198,22 @@ function SelectPageSize({
current,
onChange,
}: SelectPageSizeRendererProps) {
+ const { Option } = Select;
+
return (
-
+ <>
{t('Show')}{' '}
- {' '}
+ {' '}
{t('entries per page')}
-
+ >
);
}
@@ -953,7 +954,7 @@ export default function TableChart(
},
Header: ({ column: col, onClick, style, onDragStart, onDrop }) => (
{
'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(
diff --git a/superset-frontend/src/assets/stylesheets/superset.less b/superset-frontend/src/assets/stylesheets/superset.less
index b7650a90c29..1c244ccaede 100644
--- a/superset-frontend/src/assets/stylesheets/superset.less
+++ b/superset-frontend/src/assets/stylesheets/superset.less
@@ -38,10 +38,6 @@ i {
white-space: nowrap;
}
-input.form-control {
- background-color: @lightest;
-}
-
.disabledButton {
pointer-events: none;
}
diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
index 0e4c332592a..1bb843fbc90 100644
--- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
@@ -23,6 +23,7 @@ import { Tooltip } from '../Tooltip';
import { Alert } from '../Alert';
import { Modal } from '../Modal';
import type { ErrorAlertProps } from './types';
+import { Typography } from '../Typography';
export const ErrorAlert: React.FC = ({
errorType = t('Error'),
@@ -72,14 +73,19 @@ export const ErrorAlert: React.FC = ({
{message && {message} }
{description && (
-
+
{description}
-
+
)}
{descriptionDetails && (
{isDescriptionVisible && (
- {descriptionDetails}
+
+ {descriptionDetails}
+
)}
`
+ text-align: center;
- .superset-list-view {
- text-align: left;
- border-radius: 4px 0;
- margin: 0 ${({ theme }) => theme.sizeUnit * 4}px;
+ .superset-list-view {
+ text-align: left;
+ border-radius: 4px 0;
+ margin: 0 ${theme.sizeUnit * 4}px;
- .header {
- display: flex;
- padding-bottom: ${({ theme }) => theme.sizeUnit * 4}px;
-
- & .controls {
+ .header {
display: flex;
- flex-wrap: wrap;
- column-gap: ${({ theme }) => theme.sizeUnit * 6}px;
- row-gap: ${({ theme }) => theme.sizeUnit * 4}px;
+ padding-bottom: ${theme.sizeUnit * 4}px;
+
+ & .controls {
+ display: flex;
+ flex-wrap: wrap;
+ column-gap: ${theme.sizeUnit * 6}px;
+ row-gap: ${theme.sizeUnit * 4}px;
+ }
+ }
+
+ .body.empty table {
+ margin-bottom: 0;
+ }
+
+ .body {
+ overflow-x: auto;
+ }
+
+ .antd5-empty {
+ .antd5-empty-image {
+ height: auto;
+ }
}
}
- .body.empty table {
- margin-bottom: 0;
+ .pagination-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ margin-bottom: ${theme.sizeUnit * 4}px;
}
- .body {
- overflow-x: auto;
+ .row-count-container {
+ margin-top: ${theme.sizeUnit * 2}px;
+ color: ${theme.colors.grayscale.base};
}
-
- .antd5-empty {
- .antd5-empty-image {
- height: auto;
- }
- }
- }
-
- .pagination-container {
- display: flex;
- flex-direction: column;
- justify-content: center;
- margin-bottom: ${({ theme }) => theme.sizeUnit * 4}px;
- }
-
- .row-count-container {
- margin-top: ${({ theme }) => theme.sizeUnit * 2}px;
- color: ${({ theme }) => theme.colors.grayscale.base};
- }
+ `}
`;
const BulkSelectWrapper = styled(Alert)`
@@ -106,9 +108,7 @@ const BulkSelectWrapper = styled(Alert)`
}
.divider {
- margin: ${`${-theme.sizeUnit * 2}px 0 ${-theme.sizeUnit * 2}px ${
- theme.sizeUnit * 4
- }px`};
+ margin: ${`${-theme.sizeUnit * 2}px 0 ${-theme.sizeUnit * 2}px ${theme.sizeUnit * 4}px`};
width: 1px;
height: ${theme.sizeUnit * 8}px;
box-shadow: inset -1px 0px 0px ${theme.colorBorder};
@@ -139,36 +139,41 @@ const bulkSelectColumnConfig = {
};
const ViewModeContainer = styled.div`
- padding-right: ${({ theme }) => theme.sizeUnit * 4}px;
- margin-top: ${({ theme }) => theme.sizeUnit * 5 + 1}px;
- white-space: nowrap;
- display: inline-block;
-
- .toggle-button {
+ ${({ theme }) => `
+ padding-right: ${theme.sizeUnit * 4}px;
+ margin-top: ${theme.sizeUnit * 5 + 1}px;
+ white-space: nowrap;
display: inline-block;
- border-radius: ${({ theme }) => theme.borderRadius}px;
- padding: ${({ theme }) => theme.sizeUnit}px;
- padding-bottom: ${({ theme }) => theme.sizeUnit * 0.5}px;
- &:first-of-type {
- margin-right: ${({ theme }) => theme.sizeUnit * 2}px;
- }
- }
+ .toggle-button {
+ display: inline-block;
+ border-radius: ${theme.borderRadius}px;
+ padding: ${theme.sizeUnit}px;
+ padding-bottom: ${theme.sizeUnit * 0.5}px;
- .active {
- background-color: ${({ theme }) => theme.colors.grayscale.base};
- svg {
- color: ${({ theme }) => theme.colorBgLayout};
+ &:first-of-type {
+ margin-right: ${theme.sizeUnit * 2}px;
+ }
}
- }
+
+ .active {
+ background-color: ${theme.colors.grayscale.base};
+
+ svg {
+ color: ${theme.colorBgLayout};
+ }
+ }
+ `}
`;
const EmptyWrapper = styled.div`
- padding: ${({ theme }) => theme.sizeUnit * 40}px 0;
+ ${({ theme }) => `
+ padding: ${theme.sizeUnit * 40}px 0;
- &.table {
- background: ${({ theme }) => theme.colorBgContainer};
- }
+ &.table {
+ background: ${theme.colorBgContainer};
+ }
+ `}
`;
const ViewModeToggle = ({
@@ -343,7 +348,7 @@ export function ListView({
onHide={() => setShowBulkTagModal(false)}
/>
)}
-
+
{cardViewEnabled && (
@@ -366,7 +371,7 @@ export function ListView({
)}
-
+
{bulkSelectEnabled && (
`
display: inline-block;
- margin: 16px 0;
- padding: 0;
+ padding: ${theme.sizeUnit * 3}px;
li {
display: inline;
@@ -39,16 +39,16 @@ const PaginationList = styled.ul`
> span {
padding: 8px 12px;
text-decoration: none;
- background-color: ${({ theme }) => theme.colorBgContainer};
- border: 1px solid ${({ theme }) => theme.colorBorder};
- border-radius: ${({ theme }) => theme.borderRadius}px;
- color: ${({ theme }) => theme.colorText};
+ background-color: ${theme.colorBgContainer};
+ border: 1px solid ${theme.colorBorder};
+ border-radius: ${theme.borderRadius}px;
+ color: ${theme.colorText};
&:hover,
&:focus {
z-index: 2;
- color: ${({ theme }) => theme.colorText};
- background-color: ${({ theme }) => theme.colorBgLayout};
+ color: ${theme.colorText};
+ background-color: ${theme.colorBgLayout};
}
}
@@ -65,9 +65,9 @@ const PaginationList = styled.ul`
&.active {
span {
z-index: 3;
- color: ${({ theme }) => theme.colorBgLayout};
+ color: ${theme.colorBgLayout};
cursor: default;
- background-color: ${({ theme }) => theme.colorPrimary};
+ background-color: ${theme.colorPrimary};
&:focus {
outline: none;
@@ -75,6 +75,7 @@ const PaginationList = styled.ul`
}
}
}
+`}
`;
function Pagination({ children }: PaginationProps) {
diff --git a/superset-frontend/src/components/index.ts b/superset-frontend/src/components/index.ts
index 7f467983535..4cc7a10e1a6 100644
--- a/superset-frontend/src/components/index.ts
+++ b/superset-frontend/src/components/index.ts
@@ -197,6 +197,8 @@ export { Skeleton, type SkeletonProps } from './Skeleton';
export { Switch, type SwitchProps } from './Switch';
+export { Tag } from './Tag';
+
export { TreeSelect, type TreeSelectProps } from './TreeSelect';
export { Typography, type TypographyProps } from './Typography';
diff --git a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
index ba83e002f4b..ecc75e2b42f 100644
--- a/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
+++ b/superset-frontend/src/dashboard/components/PropertiesModal/index.tsx
@@ -30,6 +30,7 @@ import {
Col,
Input,
} from 'src/components';
+import { Typography } from 'src/components/Typography';
import rison from 'rison';
import {
ensureIsArray,
@@ -444,7 +445,9 @@ const PropertiesModal = ({
return (
- {t('Access')}
+
+ {t('Access')}
+
- {t('Colors')}
+
+ {t('Colors')}
+
- {t('Access')}
+
+ {t('Access')}
+
@@ -646,7 +653,9 @@ const PropertiesModal = ({
>
- {t('Basic information')}
+
+ {t('Basic information')}
+
@@ -673,7 +682,7 @@ const PropertiesModal = ({
: getRowsWithoutRoles()}
- {t('Certification')}
+ {t('Certification')}
@@ -700,7 +709,9 @@ const PropertiesModal = ({
{isFeatureEnabled(FeatureFlag.TaggingSystem) ? (
- {t('Tags')}
+
+ {t('Tags')}
+
) : null}
@@ -725,7 +736,7 @@ const PropertiesModal = ({
) : null}
-
+
setIsAdvancedOpen(!isAdvancedOpen)}
@@ -740,7 +751,7 @@ const PropertiesModal = ({
/>
{t('Advanced')}
-
+
{isAdvancedOpen && (
<>
diff --git a/superset-frontend/src/explore/components/PropertiesModal/index.tsx b/superset-frontend/src/explore/components/PropertiesModal/index.tsx
index 4d28c64b685..c18f239d33e 100644
--- a/superset-frontend/src/explore/components/PropertiesModal/index.tsx
+++ b/superset-frontend/src/explore/components/PropertiesModal/index.tsx
@@ -46,6 +46,7 @@ import withToasts from 'src/components/MessageToasts/withToasts';
import { loadTags } from 'src/components/Tag/utils';
import { fetchTags, OBJECT_TYPES } from 'src/features/tags/tags';
import TagType from 'src/types/TagType';
+import { Typography } from 'src/components/Typography';
export type PropertiesModalProps = {
slice: Slice;
@@ -316,7 +317,9 @@ function PropertiesModal({
>
- {t('Basic information')}
+
+ {t('Basic information')}
+
- {t('Certification')}
+ {t('Certification')}
@@ -363,7 +366,7 @@ function PropertiesModal({
- {t('Configuration')}
+ {t('Configuration')}
@@ -374,7 +377,9 @@ function PropertiesModal({
)}
- {t('Access')}
+
+ {t('Access')}
+
{isFeatureEnabled(FeatureFlag.TaggingSystem) && (
- {t('Tags')}
+
+ {t('Tags')}
+
)}
{isFeatureEnabled(FeatureFlag.TaggingSystem) && (
diff --git a/superset-frontend/src/explore/components/controls/ZoomConfigControl/ZoomConfigControl.tsx b/superset-frontend/src/explore/components/controls/ZoomConfigControl/ZoomConfigControl.tsx
index a9863824440..43c3c8e2a15 100644
--- a/superset-frontend/src/explore/components/controls/ZoomConfigControl/ZoomConfigControl.tsx
+++ b/superset-frontend/src/explore/components/controls/ZoomConfigControl/ZoomConfigControl.tsx
@@ -18,8 +18,10 @@
*/
import { ControlHeader } from '@superset-ui/chart-controls';
import { css, styled, t } from '@superset-ui/core';
+// I restored the import from antd because the component is not working as expected.
+// TODO: It requires a rework; after that, we can switch to antd-v5.
// eslint-disable-next-line no-restricted-imports
-import { Form, Tag } from 'antd'; // TODO: Remove antd
+import { Form, Tag } from 'antd';
import { FC, useState } from 'react';
import { isZoomConfigsLinear, isZoomConfigsExp } from './typeguards';
import { ZoomConfigs, ZoomConfigsControlProps } from './types';
diff --git a/superset-frontend/src/features/alerts/AlertReportModal.tsx b/superset-frontend/src/features/alerts/AlertReportModal.tsx
index 0469d1ff4f2..e4de3f59654 100644
--- a/superset-frontend/src/features/alerts/AlertReportModal.tsx
+++ b/superset-frontend/src/features/alerts/AlertReportModal.tsx
@@ -78,6 +78,7 @@ import {
import { useSelector } from 'react-redux';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
import { Icons } from 'src/components/Icons';
+import { Typography } from 'src/components/Typography';
import NumberInput from './components/NumberInput';
import { AlertReportCronScheduler } from './components/AlertReportCronScheduler';
import { NotificationMethod } from './components/NotificationMethod';
@@ -1454,7 +1455,11 @@ const AlertReportModal: FunctionComponent = ({
show={show}
width="500px"
centered
- title={{getTitleText()}}
+ title={
+
+ {getTitleText()}
+
+ }
>
{
it('renders add header when no layer is included', async () => {
const addWrapper = await mountAndWait({});
expect(
- addWrapper.find('[data-test="annotation-layer-modal-title"]').text(),
+ addWrapper
+ .find('[data-test="annotation-layer-modal-title"]')
+ .first()
+ .text(),
).toEqual('Add annotation layer');
});
it('renders edit header when layer prop is included', () => {
expect(
- wrapper.find('[data-test="annotation-layer-modal-title"]').text(),
+ wrapper.find('[data-test="annotation-layer-modal-title"]').first().text(),
).toEqual('Edit annotation layer properties');
});
diff --git a/superset-frontend/src/features/annotationLayers/AnnotationLayerModal.tsx b/superset-frontend/src/features/annotationLayers/AnnotationLayerModal.tsx
index ba8d3fba1aa..9d2c77cb33f 100644
--- a/superset-frontend/src/features/annotationLayers/AnnotationLayerModal.tsx
+++ b/superset-frontend/src/features/annotationLayers/AnnotationLayerModal.tsx
@@ -22,6 +22,7 @@ import { css, styled, t, useTheme } from '@superset-ui/core';
import { useSingleViewResource } from 'src/views/CRUD/hooks';
import { Icons } from 'src/components/Icons';
+import { Typography } from 'src/components/Typography';
import { Input, Modal } from 'src/components';
import withToasts from 'src/components/MessageToasts/withToasts';
@@ -235,7 +236,7 @@ const AnnotationLayerModal: FunctionComponent = ({
show={show}
width="55%"
title={
-
+
{isEditMode ? (
= ({
{isEditMode
? t('Edit annotation layer properties')
: t('Add annotation layer')}
-
+
}
>
- {t('Basic information')}
+ {t('Basic information')}
diff --git a/superset-frontend/src/features/cssTemplates/CssTemplateModal.test.jsx b/superset-frontend/src/features/cssTemplates/CssTemplateModal.test.jsx
index d29e0c1b803..f5b8bf3ce2d 100644
--- a/superset-frontend/src/features/cssTemplates/CssTemplateModal.test.jsx
+++ b/superset-frontend/src/features/cssTemplates/CssTemplateModal.test.jsx
@@ -71,13 +71,13 @@ describe('CssTemplateModal', () => {
it('renders add header when no css template is included', async () => {
const addWrapper = await mountAndWait({});
expect(
- addWrapper.find('[data-test="css-template-modal-title"]').text(),
+ addWrapper.find('[data-test="css-template-modal-title"]').first().text(),
).toEqual('Add CSS template');
});
it('renders edit header when css template prop is included', () => {
expect(
- wrapper.find('[data-test="css-template-modal-title"]').text(),
+ wrapper.find('[data-test="css-template-modal-title"]').first().text(),
).toEqual('Edit CSS template properties');
});
diff --git a/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx b/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
index b4965051e80..6b520b787f8 100644
--- a/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
+++ b/superset-frontend/src/features/cssTemplates/CssTemplateModal.tsx
@@ -24,6 +24,7 @@ import { useSingleViewResource } from 'src/views/CRUD/hooks';
import { Icons } from 'src/components/Icons';
import withToasts from 'src/components/MessageToasts/withToasts';
import { Input, CssEditor, Modal } from 'src/components';
+import { Typography } from 'src/components/Typography';
import { OnlyKeyWithType } from 'src/utils/types';
import { TemplateObject } from './types';
@@ -231,7 +232,7 @@ const CssTemplateModal: FunctionComponent = ({
show={show}
width="55%"
title={
-
+
{isEditMode ? (
= ({
{isEditMode
? t('Edit CSS template properties')
: t('Add CSS template')}
-
+
}
>
- {t('Basic information')}
+ {t('Basic information')}
diff --git a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx
index de2d9245c64..3f4fca97b69 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/DatabaseConnectionForm/TableCatalog.tsx
@@ -22,6 +22,7 @@ import {
LabeledErrorBoundInput as ValidatedInput,
} from 'src/components';
import { Icons } from 'src/components/Icons';
+import { Typography } from 'src/components/Typography';
import { StyledFooterButton, StyledCatalogTable } from '../styles';
import { CatalogObject, FieldPropTypes } from '../../types';
@@ -36,9 +37,9 @@ export const TableCatalog = ({
const catalogError = validationErrors || {};
return (
-
+
{t('Connect Google Sheets as tables to this database')}
-
+
{tableCatalog?.map((sheet: CatalogObject, idx: number) => (
<>
diff --git a/superset-frontend/src/features/databases/DatabaseModal/ModalHeader.tsx b/superset-frontend/src/features/databases/DatabaseModal/ModalHeader.tsx
index 29365e1941a..55846a25fbe 100644
--- a/superset-frontend/src/features/databases/DatabaseModal/ModalHeader.tsx
+++ b/superset-frontend/src/features/databases/DatabaseModal/ModalHeader.tsx
@@ -17,16 +17,17 @@
* under the License.
*/
+import { t } from '@superset-ui/core';
import { getDatabaseDocumentationLinks } from 'src/views/CRUD/hooks';
import { UploadFile } from 'src/components/Upload';
-import { t } from '@superset-ui/core';
+import { Typography } from 'src/components/Typography';
+import { DatabaseForm, DatabaseObject } from '../types';
import {
EditHeaderTitle,
EditHeaderSubtitle,
StyledFormHeader,
StyledStickyHeader,
} from './styles';
-import { DatabaseForm, DatabaseObject } from '../types';
const supersetTextDocs = getDatabaseDocumentationLinks();
@@ -100,7 +101,9 @@ const ModalHeader = ({
stepLast: 2,
})}
- {t('Enter Primary Credentials')}
+
+ {t('Enter Primary Credentials')}
+
{t('Need help? Learn how to connect your database')}{' '}
- {t('Database connected')}
+
+ {t('Database connected')}
+
{t(`Create a dataset to begin visualizing your data as a chart or go to
SQL Lab to query your data.`)}
@@ -142,11 +147,11 @@ const ModalHeader = ({
stepLast: 3,
})}
-
+
{t('Enter the required %(dbModelName)s credentials', {
dbModelName: dbModel.name,
})}
-
+
{t('Need help? Learn more about')}{' '}
- {t('Select a database to connect')}
+
+ {t('Select a database to connect')}
+
@@ -186,11 +193,11 @@ const ModalHeader = ({
stepLast: 2,
})}
-
+
{t('Enter the required %(dbModelName)s credentials', {
dbModelName: dbModel.name,
})}
-
+
{fileCheck ? fileList[0].name : ''}
diff --git a/superset-frontend/src/features/reports/ReportModal/index.tsx b/superset-frontend/src/features/reports/ReportModal/index.tsx
index e181f5abceb..6b31146c474 100644
--- a/superset-frontend/src/features/reports/ReportModal/index.tsx
+++ b/superset-frontend/src/features/reports/ReportModal/index.tsx
@@ -44,6 +44,7 @@ import {
} from 'src/components';
import TimezoneSelector from 'src/components/TimezoneSelector';
import { Icons } from 'src/components/Icons';
+import { Typography } from 'src/components/Typography';
import { Radio, RadioChangeEvent } from 'src/components/Radio';
import withToasts from 'src/components/MessageToasts/withToasts';
import { ChartState } from 'src/explore/types';
@@ -254,7 +255,7 @@ function ReportModal({
const renderMessageContentSection = (
<>
- {t('Message content')}
+ {t('Message content')}
- SectionHeaderStyle(theme)}>
+ SectionHeaderStyle(theme)}
+ >
{t('Schedule')}
-
+
{t('The report will be sent to your email at')}
diff --git a/superset-frontend/src/features/rls/RowLevelSecurityModal.tsx b/superset-frontend/src/features/rls/RowLevelSecurityModal.tsx
index b745990712e..67d589e7543 100644
--- a/superset-frontend/src/features/rls/RowLevelSecurityModal.tsx
+++ b/superset-frontend/src/features/rls/RowLevelSecurityModal.tsx
@@ -28,6 +28,7 @@ import {
LabeledErrorBoundInput,
Input,
} from 'src/components';
+import { Typography } from 'src/components/Typography';
import rison from 'rison';
import { useSingleViewResource } from 'src/views/CRUD/hooks';
import { FILTER_OPTIONS } from './constants';
@@ -335,7 +336,7 @@ function RowLevelSecurityModal(props: RowLevelSecurityModalProps) {
width="30%"
maxWidth="1450px"
title={
-
+
{isEditMode ? (
)}
{isEditMode ? t('Edit Rule') : t('Add Rule')}
-
+
}
>
|