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} -

+ -

+ {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')} -

+ } >