diff --git a/superset-frontend/cypress-base/cypress/e2e/explore/advanced_analytics.test.ts b/superset-frontend/cypress-base/cypress/e2e/explore/advanced_analytics.test.ts index 2d50460fd79..d7c3aff4e10 100644 --- a/superset-frontend/cypress-base/cypress/e2e/explore/advanced_analytics.test.ts +++ b/superset-frontend/cypress-base/cypress/e2e/explore/advanced_analytics.test.ts @@ -29,7 +29,7 @@ describe('Advanced analytics', () => { cy.visitChartByName('Num Births Trend'); cy.verifySliceSuccess({ waitAlias: '@v1Data' }); - cy.get('.ant-collapse-header') + cy.get('.antd5-collapse-header') .contains('Advanced analytics') .click({ force: true }); @@ -52,7 +52,7 @@ describe('Advanced analytics', () => { waitAlias: '@v1Data', }); cy.wait('@getExplore'); - cy.get('.ant-collapse-header') + cy.get('.antd5-collapse-header') .contains('Advanced analytics') .click({ force: true }); cy.get('[data-test=time_compare]') diff --git a/superset-frontend/cypress-base/cypress/support/directories.ts b/superset-frontend/cypress-base/cypress/support/directories.ts index 3669109bbc4..b1b4a63babc 100644 --- a/superset-frontend/cypress-base/cypress/support/directories.ts +++ b/superset-frontend/cypress-base/cypress/support/directories.ts @@ -52,16 +52,16 @@ export const securityAccess = { }; export const homePage = { homeSection: { - sectionArea: '.ant-collapse-content-box', + sectionArea: '.antd5-collapse-content-box', sectionElement: '.antd5-card-meta-title', }, sections: { - expandedSection: '.ant-collapse-item-active', + expandedSection: '.antd5-collapse-item-active', expandedSectionHeader: '[aria-expanded="true"]', - collapseExpandButton: '.ant-collapse-arrow', - collapsedSection: '[class="ant-collapse-item"]', + collapseExpandButton: '.antd5-collapse-arrow', + collapsedSection: '[class="antd5-collapse-item"]', collapsedSectionHeader: '[aria-expanded="false"]', - section: '[class^="ant-collapse-item"]', + section: '[class^="antd5-collapse-item"]', sectionsMenuContainer: "[role='navigation']", sectionsMenuItem: "[role='menuitem']", card: dataTestLocator('styled-card'), @@ -112,7 +112,7 @@ export const databasesPage = { advancedTab: '#rc-tabs-0-tab-2', activeTab: '.antd5-tabs-tab-active', securitySubMenu: - ':nth-child(3) > .ant-collapse-header > .anticon > svg > path', + ':nth-child(3) > .antd5-collapse-header > .anticon > svg > path', aceTextInput: '.ace_text-input', aceContent: '.ace_content', connectButton: '.css-16i3wh7', @@ -359,14 +359,14 @@ export const nativeFilters = { removeFilter: '[aria-label="remove"]', silentLoading: '.loading inline-centered css-101mkpk', filterConfigurationSections: { - sectionHeader: '.ant-collapse-header', + sectionHeader: '.antd5-collapse-header', displayedSection: 'div[style="height: 100%; overflow-y: auto;"]', - collapseExpandButton: '.ant-collapse-arrow', + collapseExpandButton: '.antd5-collapse-arrow', checkedCheckbox: '.ant-checkbox-wrapper-checked', infoTooltip: '[aria-label="Show info tooltip"]', parentFilterInput: dataTestLocator('parent-filter-input'), filterPlaceholder: '.ant-select-selection-placeholder', - collapsedSectionContainer: '[class="ant-collapse-content-box"]', + collapsedSectionContainer: '[class="antd5-collapse-content-box"]', }, filtersList: { list: '.antd5-tabs-nav-list', @@ -460,7 +460,7 @@ export const dashboardListView = { }; export const exploreView = { openDatasourceMenu: dataTestLocator('open-datasource-tab'), - sectionsHeader: '.ant-collapse-header', + sectionsHeader: '.antd5-collapse-header', datasourceMenuThreeDots: dataTestLocator('datasource-menu-trigger'), threeDotsMenuDropdown: { editDataset: dataTestLocator('edit-dataset'), @@ -495,7 +495,7 @@ export const exploreView = { }, controlPanel: { panel: dataTestLocator('control-tabs'), - categoryArea: '.ant-collapse-content-box', + categoryArea: '.antd5-collapse-content-box', dragField: dataTestLocator('datasource'), metricsField: dataTestLocator('metrics'), optionField: dataTestLocator('option-label'), diff --git a/superset-frontend/src/SqlLab/components/ColumnElement/ColumnElement.test.tsx b/superset-frontend/src/SqlLab/components/ColumnElement/ColumnElement.test.tsx index 09105bb5fa2..437be27504a 100644 --- a/superset-frontend/src/SqlLab/components/ColumnElement/ColumnElement.test.tsx +++ b/superset-frontend/src/SqlLab/components/ColumnElement/ColumnElement.test.tsx @@ -32,23 +32,23 @@ describe('ColumnElement', () => { it('renders a proper primary key', () => { const { container } = render(); expect(container.querySelector('i.fa-key')).toBeInTheDocument(); - expect(container.querySelector('.col-name')?.firstChild).toHaveTextContent( - 'id', - ); + expect( + container.querySelector('[data-test="col-name"]')?.firstChild, + ).toHaveTextContent('id'); }); it('renders a multi-key column', () => { const { container } = render(); expect(container.querySelector('i.fa-link')).toBeInTheDocument(); expect(container.querySelector('i.fa-bookmark')).toBeInTheDocument(); - expect(container.querySelector('.col-name')?.firstChild).toHaveTextContent( - 'first_name', - ); + expect( + container.querySelector('[data-test="col-name"]')?.firstChild, + ).toHaveTextContent('first_name'); }); it('renders a column with no keys', () => { const { container } = render(); expect(container.querySelector('i')).not.toBeInTheDocument(); - expect(container.querySelector('.col-name')?.firstChild).toHaveTextContent( - 'last_name', - ); + expect( + container.querySelector('[data-test="col-name"]')?.firstChild, + ).toHaveTextContent('last_name'); }); }); diff --git a/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx b/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx index 3cc9d14f552..d918af42812 100644 --- a/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx +++ b/superset-frontend/src/SqlLab/components/ColumnElement/index.tsx @@ -20,6 +20,7 @@ import { ReactNode } from 'react'; import { ClassNames } from '@emotion/react'; import { styled, useTheme, t } from '@superset-ui/core'; import { Tooltip } from 'src/components/Tooltip'; +import { Flex } from 'src/components/Flex'; const StyledTooltip = (props: any) => { const theme = useTheme(); @@ -104,15 +105,15 @@ const ColumnElement = ({ column }: ColumnElementProps) => { )); } return ( -
-
+ +
{columnName} {icons}
- + {column.type} -
+ ); }; diff --git a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx index b6d00e3a67d..897e5de4290 100644 --- a/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx +++ b/superset-frontend/src/SqlLab/components/SqlEditorLeftBar/index.tsx @@ -34,11 +34,8 @@ import { resetState, } from 'src/SqlLab/actions/sqlLab'; import Button from 'src/components/Button'; -import { t, styled, css, SupersetTheme } from '@superset-ui/core'; -import Collapse from 'src/components/Collapse'; -import { Icons } from 'src/components/Icons'; +import { t, styled, css } from '@superset-ui/core'; import { TableSelectorMultiple } from 'src/components/TableSelector'; -import { IconTooltip } from 'src/components/IconTooltip'; import useQueryEditor from 'src/SqlLab/hooks/useQueryEditor'; import type { DatabaseObject } from 'src/components/DatabaseSelector'; import { EmptyState } from 'src/components/EmptyState'; @@ -60,29 +57,6 @@ const StyledScrollbarContainer = styled.div` overflow: auto; `; -const collapseStyles = (theme: SupersetTheme) => css` - .ant-collapse-item { - margin-bottom: ${theme.sizeUnit * 3}px; - } - .ant-collapse-header { - padding: 0px !important; - display: flex; - align-items: center; - } - .ant-collapse-content-box { - padding: 0px ${theme.sizeUnit * 4}px 0px 0px !important; - } - .ant-collapse-arrow { - padding: 0 !important; - bottom: ${theme.sizeUnit}px !important; - right: ${theme.sizeUnit * 4}px !important; - color: ${theme.colorPrimaryText} !important; - &:hover { - color: ${theme.colorPrimaryTextHover} !important; - } - } -`; - const LeftBarStyles = styled.div` ${({ theme }) => css` height: 100%; @@ -194,25 +168,6 @@ const SqlEditorLeftBar = ({ }); }; - const renderExpandIconWithTooltip = ({ isActive }: { isActive: boolean }) => ( - - - - ); - const shouldShowReset = window.location.search === '?reset=1'; const tableMetaDataHeight = height - 130; // 130 is the height of the selects above @@ -276,20 +231,16 @@ const SqlEditorLeftBar = ({ height: ${tableMetaDataHeight}px; `} > - expanded) - .map(({ id }) => id)} - css={collapseStyles} - expandIconPosition="right" - ghost - onChange={onToggleTable} - expandIcon={renderExpandIconWithTooltip} - > - {tables.map(table => ( - - ))} - + {tables.map(table => ( + expanded) + .map(({ id }) => id)} + onChange={onToggleTable} + /> + ))}
{shouldShowReset && ( diff --git a/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.tsx b/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.tsx index b9cd94e5663..94fedeae9b6 100644 --- a/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.tsx +++ b/superset-frontend/src/SqlLab/components/TableElement/TableElement.test.tsx @@ -76,6 +76,7 @@ const mockedProps = { ...table, initialized: true, }, + activeKey: [table.id], }; test('renders', () => { diff --git a/superset-frontend/src/SqlLab/components/TableElement/index.tsx b/superset-frontend/src/SqlLab/components/TableElement/index.tsx index 061d67dcc76..b9a80a8bbd4 100644 --- a/superset-frontend/src/SqlLab/components/TableElement/index.tsx +++ b/superset-frontend/src/SqlLab/components/TableElement/index.tsx @@ -21,10 +21,10 @@ import { useState, useRef, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import type { Table } from 'src/SqlLab/types'; -import Collapse from 'src/components/Collapse'; +import Collapse, { CollapseProps } from 'src/components/Collapse'; import Card from 'src/components/Card'; import ButtonGroup from 'src/components/ButtonGroup'; -import { css, t, styled, useTheme } from '@superset-ui/core'; +import { t, styled, useTheme } from '@superset-ui/core'; import { debounce } from 'lodash'; import { @@ -46,6 +46,8 @@ import Loading from 'src/components/Loading'; import useEffectEvent from 'src/hooks/useEffectEvent'; import { ActionType } from 'src/types/Action'; import { Icons } from 'src/components/Icons'; +import { Flex } from 'src/components/Flex'; +import { Space } from 'src/components/Space'; import ColumnElement, { ColumnKeyTypeType } from '../ColumnElement'; import ShowSQL from '../ShowSQL'; @@ -55,15 +57,11 @@ export interface Column { type: string; } -export interface TableElementProps { +export interface TableElementProps extends CollapseProps { table: Table; } const StyledSpan = styled.span` - color: ${({ theme }) => theme.colorPrimaryText}; - &:hover { - color: ${({ theme }) => theme.colorPrimaryTextHover}; - } cursor: pointer; `; @@ -72,41 +70,8 @@ const Fade = styled.div` opacity: ${(props: { hovered: boolean }) => (props.hovered ? 1 : 0)}; `; -const StyledCollapsePanel = styled(Collapse.Panel)` - ${({ theme }) => css` - & { - .ws-el-controls { - margin-right: ${-theme.sizeUnit}px; - display: flex; - } - - .header-container { - display: flex; - flex: 1; - align-items: center; - width: 100%; - - .table-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: ${theme.fontSizeLG}px; - flex: 1; - } - - .header-right-side { - margin-left: auto; - display: flex; - align-items: center; - margin-right: ${theme.sizeUnit * 8}px; - } - } - } - `} -`; - const TableElement = ({ table, ...props }: TableElementProps) => { - const { dbId, catalog, schema, name, expanded } = table; + const { dbId, catalog, schema, name, expanded, id } = table; const theme = useTheme(); const dispatch = useDispatch(); const { @@ -273,77 +238,85 @@ const TableElement = ({ table, ...props }: TableElementProps) => { ); } return ( - - - - - {keyLink} - - {tableData.selectStar && ( - - - - } - text={tableData.selectStar} - shouldShowText={false} - /> + + {isMetadataFetching || isExtraMetadataLoading ? ( + + ) : ( + e.stopPropagation()} + > + + + + + + {keyLink} + + + + {tableData.selectStar && ( + + + + } + text={tableData.selectStar} + shouldShowText={false} + /> + )} + {tableData.view && ( + + )} + + + + + + )} - {tableData.view && ( - - )} - - - - + ); }; @@ -358,8 +331,6 @@ const TableElement = ({ table, ...props }: TableElementProps) => {
setHover(true)} - onMouseLeave={() => setHover(false)} > { {name} - -
- {isMetadataFetching || isExtraMetadataLoading ? ( - - ) : ( - e.stopPropagation()} - > - {renderControls()} - - )} -
); }; @@ -407,12 +364,7 @@ const TableElement = ({ table, ...props }: TableElementProps) => { } const metadata = ( -
setHover(true)} - onMouseLeave={() => setHover(false)} - css={{ paddingTop: 6 }} - > +
{renderWell()}
{cols?.map(col => )} @@ -423,15 +375,22 @@ const TableElement = ({ table, ...props }: TableElementProps) => { }; return ( - - {renderBody()} - + setHover(true), + onMouseLeave: () => setHover(false), + }, + ]} + /> ); }; diff --git a/superset-frontend/src/components/Collapse/Collapse.stories.tsx b/superset-frontend/src/components/Collapse/Collapse.stories.tsx index f20c0349dc7..eb6c57ba459 100644 --- a/superset-frontend/src/components/Collapse/Collapse.stories.tsx +++ b/superset-frontend/src/components/Collapse/Collapse.stories.tsx @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import { useTheme } from '@superset-ui/core'; import Collapse, { CollapseProps } from '.'; export default { @@ -24,30 +23,30 @@ export default { component: Collapse, }; -export const InteractiveCollapse = (args: CollapseProps) => { - const theme = useTheme(); - return ( - - - Content 1 - - - Content 2 - - - ); -}; +export const InteractiveCollapse = (args: CollapseProps) => ( + +); InteractiveCollapse.args = { ghost: false, bordered: true, accordion: false, + animateArrows: false, }; InteractiveCollapse.argTypes = { diff --git a/superset-frontend/src/components/Collapse/Collapse.test.tsx b/superset-frontend/src/components/Collapse/Collapse.test.tsx index 69eca8344e0..80f0687ae44 100644 --- a/superset-frontend/src/components/Collapse/Collapse.test.tsx +++ b/superset-frontend/src/components/Collapse/Collapse.test.tsx @@ -18,19 +18,25 @@ */ import { render, screen } from 'spec/helpers/testing-library'; import userEvent from '@testing-library/user-event'; -import { supersetTheme } from '@superset-ui/core'; import Collapse, { CollapseProps } from '.'; function renderCollapse(props?: CollapseProps) { return render( - - - Content 1 - - - Content 2 - - , + , ); } @@ -81,25 +87,3 @@ test('collapses on click', () => { ); expect(screen.queryByText('Content 2')).not.toBeInTheDocument(); }); - -test('renders with custom properties', () => { - renderCollapse({ - light: true, - bigger: true, - bold: true, - animateArrows: true, - }); - - const header = document.getElementsByClassName('ant-collapse-header')[0]; - const arrow = - document.getElementsByClassName('ant-collapse-arrow')[0].children[0]; - - const headerStyle = window.getComputedStyle(header); - const arrowStyle = window.getComputedStyle(arrow); - - expect(headerStyle.fontWeight).toBe( - supersetTheme.fontWeightStrong.toString(), - ); - expect(headerStyle.fontSize).toBe(`${supersetTheme.sizeUnit * 4}px`); - expect(arrowStyle.transition).toBe('transform 0.24s'); -}); diff --git a/superset-frontend/src/components/Collapse/index.tsx b/superset-frontend/src/components/Collapse/index.tsx index ad34c0c67b6..c8e2b16b0e6 100644 --- a/superset-frontend/src/components/Collapse/index.tsx +++ b/superset-frontend/src/components/Collapse/index.tsx @@ -17,86 +17,67 @@ * under the License. */ import { styled } from '@superset-ui/core'; -// eslint-disable-next-line no-restricted-imports -import { Collapse as AntdCollapse } from 'antd'; // TODO: Remove antd -// eslint-disable-next-line no-restricted-imports -import { CollapseProps as AntdCollapseProps } from 'antd/lib/collapse'; // TODO: Remove antd +import { + Collapse as AntdCollapse, + CollapseProps as AntdCollapseProps, +} from 'antd-v5'; export interface CollapseProps extends AntdCollapseProps { - light?: boolean; - bigger?: boolean; - bold?: boolean; animateArrows?: boolean; } -const Collapse = Object.assign( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - styled(({ light, bigger, bold, animateArrows, ...props }: CollapseProps) => ( - - ))` - .ant-collapse-item { - .ant-collapse-header { - font-weight: ${({ bold, theme }) => - bold ? theme.fontWeightStrong : theme.fontWeightNormal}; - font-size: ${({ bigger, theme }) => - bigger ? `${theme.sizeUnit * 4}px` : 'inherit'}; +const Collapse = styled((props: CollapseProps) => )` + .antd5-collapse-item { + .antd5-collapse-header { + .antd5-collapse-arrow svg { + transition: ${({ animateArrows }) => + animateArrows ? 'transform 0.24s' : 'none'}; + } - .ant-collapse-arrow svg { - transition: ${({ animateArrows }) => - animateArrows ? 'transform 0.24s' : 'none'}; - } - - ${({ expandIconPosition }) => - expandIconPosition && - expandIconPosition === 'right' && - ` - .anticon.anticon-right.ant-collapse-arrow > svg { + ${({ expandIconPosition }) => + expandIconPosition && + expandIconPosition === 'right' && + ` + .anticon.anticon-right.antd5-collapse-arrow > svg { transform: rotate(90deg) !important; } `} + } - ${({ light, theme }) => - light && - ` - color: ${theme.colorTextSecondary}; - .ant-collapse-arrow svg { - color: ${theme.colorTextSecondary}; - } - `} + ${({ ghost, bordered, theme }) => + ghost && + bordered && + ` + border-bottom: 1px solid ${theme.colorBorderSecondary}; + `} + .antd5-collapse-content { + color: ${({ theme }) => theme.colorText}; - ${({ ghost, bordered, theme }) => - ghost && - bordered && - ` - border-bottom: 1px solid ${theme.colorBorderSecondary}; - `} - } - .ant-collapse-content { - color: ${({ theme }) => theme.colorText}; - .ant-collapse-content-box { - .loading.inline { - margin: ${({ theme }) => theme.sizeUnit * 12}px auto; - display: block; - } + .antd5-collapse-content-box { + .loading.inline { + margin: ${({ theme }) => theme.sizeUnit * 12}px auto; + display: block; } } } - .ant-collapse-item-active { - .ant-collapse-header { - ${({ expandIconPosition }) => - expandIconPosition && - expandIconPosition === 'right' && - ` - .anticon.anticon-right.ant-collapse-arrow > svg { + } + + .hidden-collapse-header .antd5-collapse-header { + display: none; + } + + .antd5-collapse-item-active { + .antd5-collapse-header { + ${({ expandIconPosition }) => + expandIconPosition && + expandIconPosition === 'right' && + ` + .anticon.anticon-right.antd5-collapse-arrow > svg { transform: rotate(-90deg) !important; } `} - } } - `, - { - Panel: AntdCollapse.Panel, - }, -); + } +`; export default Collapse; diff --git a/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.tsx b/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.tsx index 5b59fbf9721..0251de7882d 100644 --- a/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.tsx +++ b/superset-frontend/src/components/ErrorMessage/MarshmallowErrorMessage.tsx @@ -17,7 +17,7 @@ * under the License. */ import { JSONTree } from 'react-json-tree'; -import { css, styled, SupersetTheme, t } from '@superset-ui/core'; +import { styled, t } from '@superset-ui/core'; import { useJsonTreeTheme } from 'src/hooks/useJsonTreeTheme'; import Collapse from 'src/components/Collapse'; @@ -37,18 +37,6 @@ const StyledUl = styled.ul` padding-top: ${({ theme }) => theme.sizeUnit * 4}px; `; -const collapseStyle = (theme: SupersetTheme) => css` - .ant-collapse-arrow { - left: 0px !important; - } - .ant-collapse-header { - padding-left: ${theme.sizeUnit * 4}px !important; - } - .ant-collapse-content-box { - padding: 0px !important; - } -`; - const extractInvalidValues = (messages: object, payload: object): string[] => { const invalidValues: string[] = []; @@ -99,16 +87,23 @@ export default function MarshmallowErrorMessage({ )} - - - true} - hideRoot - theme={jsonTreeTheme} - /> - - + true} + hideRoot + theme={jsonTreeTheme} + /> + ), + }, + ]} + />
); } diff --git a/superset-frontend/src/components/IconTooltip/index.tsx b/superset-frontend/src/components/IconTooltip/index.tsx index bb8c5bb7015..3e5cea7b3d7 100644 --- a/superset-frontend/src/components/IconTooltip/index.tsx +++ b/superset-frontend/src/components/IconTooltip/index.tsx @@ -18,7 +18,6 @@ */ import { ReactNode } from 'react'; import { Tooltip } from 'src/components/Tooltip'; -import { styled } from '@superset-ui/core'; export interface Props { children?: ReactNode; @@ -41,13 +40,6 @@ export interface Props { tooltip?: string | null; } -const StyledSpan = styled.span` - color: ${({ theme }) => theme.colorPrimaryText}; - &: hover { - color: ${({ theme }) => theme.colors.primary.dark2}; - } -`; - const IconTooltip = ({ children = null, className = '', @@ -57,13 +49,19 @@ const IconTooltip = ({ tooltip = null, }: Props) => { const iconTooltip = ( - {children} - + ); if (tooltip) { return ( diff --git a/superset-frontend/src/components/Icons/AntdEnhanced.tsx b/superset-frontend/src/components/Icons/AntdEnhanced.tsx index 574b2ebc88c..6c801589f79 100644 --- a/superset-frontend/src/components/Icons/AntdEnhanced.tsx +++ b/superset-frontend/src/components/Icons/AntdEnhanced.tsx @@ -113,6 +113,7 @@ import { FilterOutlined, UnorderedListOutlined, WarningOutlined, + SortAscendingOutlined, KeyOutlined, } from '@ant-design/icons'; import { FC } from 'react'; @@ -216,6 +217,7 @@ const AntdIcons = { FilterOutlined, UnorderedListOutlined, WarningOutlined, + SortAscendingOutlined, KeyOutlined, } as const; diff --git a/superset-frontend/src/components/index.ts b/superset-frontend/src/components/index.ts index b0eaf695d7e..591598452f9 100644 --- a/superset-frontend/src/components/index.ts +++ b/superset-frontend/src/components/index.ts @@ -27,7 +27,6 @@ export { Breadcrumb as AntdBreadcrumb, Checkbox as AntdCheckbox, - Collapse as AntdCollapse, Select as AntdSelect, } from 'antd'; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CrossFilters/VerticalCollapse.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CrossFilters/VerticalCollapse.tsx index 48915f09633..1b3361dcd4a 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CrossFilters/VerticalCollapse.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/CrossFilters/VerticalCollapse.tsx @@ -19,40 +19,16 @@ import { useMemo } from 'react'; import Collapse from 'src/components/Collapse'; -import { styled, t, useTheme, css } from '@superset-ui/core'; +import { t } from '@superset-ui/core'; import { FilterBarOrientation } from 'src/dashboard/types'; +import { Divider } from 'src/components/Divider'; import CrossFilter from './CrossFilter'; import { CrossFilterIndicator } from '../../selectors'; -const StyledCollapse = styled(Collapse)` - ${({ theme }) => ` - .ant-collapse-header { - margin-bottom: ${theme.sizeUnit * 4}px; - } - .ant-collapse-item > .ant-collapse-header { - padding-bottom: 0; - } - .ant-collapse-item > .ant-collapse-header > .ant-collapse-arrow { - font-size: ${theme.fontSizeXS}px; - padding-top: ${theme.sizeUnit * 3}px; - } - .ant-collapse-item > .ant-collapse-content > .ant-collapse-content-box { - padding-top: 0; - } - `} -`; - -const StyledCrossFiltersTitle = styled.span` - ${({ theme }) => ` - font-size: ${theme.fontSizeSM}px; - `} -`; - const CrossFiltersVerticalCollapse = (props: { crossFilters: CrossFilterIndicator[]; }) => { const { crossFilters } = props; - const theme = useTheme(); const crossFiltersIndicators = useMemo( () => crossFilters.map(filter => ( @@ -70,32 +46,23 @@ const CrossFiltersVerticalCollapse = (props: { } return ( - - - {t('Cross-filters')} - - } - > - {crossFiltersIndicators} - - - + items={[ + { + key: 'crossFilters', + label: t('Cross-filters'), + children: ( + <> + {crossFiltersIndicators} + + + ), + }, + ]} + /> ); }; diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx index fee23889a50..d9e44a4d9b1 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterControls/FilterControls.tsx @@ -145,7 +145,6 @@ const FilterControls: FC = ({ 0} renderer={renderer} /> )} diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx index 36f91fe1eaf..b52f7dfb0f3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersDropdownContent/index.tsx @@ -65,7 +65,6 @@ export const FiltersDropdownContent = ({ filtersOutOfScope={filtersOutOfScope} renderer={renderer} forceRender={forceRenderOutOfScope} - horizontalOverflow /> )}
diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx index ceb09dab1aa..59f934592d3 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FiltersOutOfScopeCollapsible/index.tsx @@ -18,82 +18,39 @@ */ import { ReactNode } from 'react'; import { css, Divider, Filter, SupersetTheme, t } from '@superset-ui/core'; -import { AntdCollapse } from 'src/components'; +import Collapse from 'src/components/Collapse'; export interface FiltersOutOfScopeCollapsibleProps { filtersOutOfScope: (Filter | Divider)[]; renderer: (filter: Filter | Divider, index: number) => ReactNode; - hasTopMargin?: boolean; - horizontalOverflow?: boolean; forceRender?: boolean; } export const FiltersOutOfScopeCollapsible = ({ filtersOutOfScope, renderer, - hasTopMargin, - horizontalOverflow, forceRender = false, }: FiltersOutOfScopeCollapsibleProps) => ( - - horizontalOverflow - ? css` - &.ant-collapse > .ant-collapse-item { - & > .ant-collapse-header { - padding: 0; - - & > .ant-collapse-arrow { - right: 0; - padding: 0; - } - } - - & .ant-collapse-content-box { - padding: ${theme.sizeUnit * 4}px 0 0; - margin-bottom: ${theme.sizeUnit * -4}px; - } - } - ` - : css` - &.ant-collapse { - margin-top: ${hasTopMargin ? theme.sizeUnit * 6 : 0}px; - & > .ant-collapse-item { - & > .ant-collapse-header { - padding-left: 0; - padding-bottom: ${theme.sizeUnit * 2}px; - - & > .ant-collapse-arrow { - right: ${theme.sizeUnit}px; - } - } - - & .ant-collapse-content-box { - padding: ${theme.sizeUnit * 4}px 0 0; - } - } - } - ` - } - > - css` - font-size: ${theme.fontSizeSM}px; - `} - > - {t('Filters out of scope (%d)', filtersOutOfScope.length)} - - } - key="1" - > - {filtersOutOfScope.map(renderer)} - - + items={[ + { + key: 'out-of-scope-filters', + label: ( + css` + font-size: ${theme.fontSizeSM}px; + `} + > + {t('Filters out of scope (%d)', filtersOutOfScope.length)} + + ), + children: filtersOutOfScope.map(renderer), + forceRender, + }, + ]} + /> ); diff --git a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx index 3a4d1c0b2f2..2d24cd7ecb4 100644 --- a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx +++ b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FiltersConfigForm/FiltersConfigForm.tsx @@ -163,36 +163,11 @@ const DefaultValueContainer = styled.div` align-items: center; `; -const StyledCollapse = styled(Collapse)` - border-left: 0; - border-top: 1px solid ${({ theme }) => theme.colorSplit}; - border-radius: 0; - - .ant-collapse-header { - border-bottom: 1px solid ${({ theme }) => theme.colorSplit}; - border-top: 1px solid ${({ theme }) => theme.colorSplit}; - margin-top: -1px; - border-radius: 0; - } - - .ant-collapse-content { - border: 0; - } - - .ant-collapse-content-box { - padding-top: ${({ theme }) => theme.sizeUnit * 2}px; - } - - &.ant-collapse > .ant-collapse-item { - border: 0; - border-radius: 0; - } -`; - const StyledAsterisk = styled.span` color: ${({ theme }) => theme.colorError}; font-size: ${({ theme }) => theme.fontSizeSM}px; margin-left: ${({ theme }) => theme.sizeUnit - 1}px; + &:before { content: '*'; } @@ -891,397 +866,445 @@ const FiltersConfigForm = ( )} )} - { handleActiveFilterPanelChange(key); }} expandIconPosition="right" key={`native-filter-config-${filterId}`} - > - {formFilter?.filterType !== 'filter_time' && ( - - {canDependOnOtherFilters && hasAvailableFilters && ( - - { - setNativeFilterFieldValues(form, filterId, { - dependencies, - }); - forceUpdate(); - validateDependencies(); - formChanged(); - }} - getDependencySuggestion={() => - getDependencySuggestion(filterId) - } - > - {hasTimeDependency ? timeColumn : undefined} - - - )} - {hasDataset && hasAdditionalFilters && ( - - + {canDependOnOtherFilters && hasAvailableFilters && ( + + { + setNativeFilterFieldValues(form, filterId, { + dependencies, + }); + forceUpdate(); + validateDependencies(); + formChanged(); + }} + getDependencySuggestion={() => + getDependencySuggestion(filterId) + } + > + {hasTimeDependency ? timeColumn : undefined} + + + )} + {hasDataset && hasAdditionalFilters && ( + + { - formChanged(); - if (checked) { - validatePreFilter(); - } - }} - > - - c.filterable, - ) || [] - } - savedMetrics={datasetDetails?.metrics || []} - datasource={datasetDetails} - onChange={(filters: AdhocFilter[]) => { - setNativeFilterFieldValues(form, filterId, { - adhoc_filters: filters, - }); - forceUpdate(); - formChanged(); - validatePreFilter(); - }} - label={ - - {t('Pre-filter')} - {!hasTimeRange && } - - } - /> - - {showTimeRangePicker && ( - {t('Time range')}} - initialValue={ - filterToEdit?.time_range || t('No filter') - } - required={!hasAdhoc} - rules={[ - { - validator: preFilterValidator, - }, - ]} - > - { - setNativeFilterFieldValues(form, filterId, { - time_range: timeRange, - }); - forceUpdate(); - formChanged(); - validatePreFilter(); - }} - /> - - )} - {hasTimeRange && !hasTimeDependency - ? timeColumn - : undefined} - - - )} - {formFilter?.filterType !== 'filter_range' ? ( - - { - onSortChanged(checked || undefined); - formChanged(); - }} - > - {t('Sort type')}} - > - { - onSortChanged(value.target.value); - formChanged(); - }} - /> - - {hasMetrics && ( - - {t('Sort Metric')}  - - - } - data-test="field-input" - > - ({ + value: metric.metric_name, + label: + metric.verbose_name ?? + metric.metric_name, + }))} + onChange={value => { + if (value !== undefined) { + setNativeFilterFieldValues( + form, + filterId, + { + sortMetric: value, + }, + ); + forceUpdate(); + } + formChanged(); + }} + /> + + )} + + + ) : ( + + { + onEnableSingleValueChanged( + checked ? SingleValueType.Exact : undefined, + ); + formChanged(); + }} + > + + {t('Single value type')} + + } + > + { + onEnableSingleValueChanged( + value.target.value, + ); + formChanged(); + }} + options={[ + { + label: t('Minimum'), + value: SingleValueType.Minimum, + }, + { + label: t('Exact'), + value: SingleValueType.Exact, + }, + { + label: t('Maximum'), + value: SingleValueType.Maximum, + }, + ]} + /> + + + )} - - ) : ( - t('Fill all required fields to enable "Default Value"') - )} - - )} - - - {Object.keys(controlItems) - .sort( - (a, b) => - controlsOrder.indexOf(a as ControlKey) - - controlsOrder.indexOf(b as ControlKey), - ) - .map(key => controlItems[key].element)} - - + + ), + }, + ] + : []), + { + label: FilterPanels.settings.name, + key: `${filterId}-${FilterPanels.settings.key}`, + forceRender: true, + children: ( + <> + {t('Description')}} + > + + +
); } diff --git a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx index 081ec504e33..1f0d9a9099e 100644 --- a/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx +++ b/superset-frontend/src/explore/components/controls/VizTypeControl/VizTypeGallery.tsx @@ -39,7 +39,6 @@ import { chartLabelWeight, chartLabelExplanations, } from '@superset-ui/core'; -import { AntdCollapse } from 'src/components'; import { Tooltip } from 'src/components/Tooltip'; import { Input } from 'src/components/Input'; import Label from 'src/components/Label'; @@ -47,6 +46,7 @@ import { usePluginContext } from 'src/components/DynamicPlugins'; import { Icons } from 'src/components/Icons'; import { nativeFilterGate } from 'src/dashboard/components/nativeFilters/utils'; import scrollIntoView from 'scroll-into-view-if-needed'; +import Collapse from 'src/components/Collapse'; interface VizTypeGalleryProps { onChange: (vizType: string | null) => void; @@ -116,14 +116,15 @@ const LeftPane = styled.div` border-right: 1px solid ${({ theme }) => theme.colorBorder}; overflow: auto; - .ant-collapse .ant-collapse-item { - .ant-collapse-header { + .antd5-collapse .antd5-collapse-item { + .antd5-collapse-header { font-size: ${({ theme }) => theme.fontSizeSM}px; color: ${({ theme }) => theme.colorText}; padding-left: ${({ theme }) => theme.sizeUnit * 2}px; padding-bottom: ${({ theme }) => theme.sizeUnit}px; } - .ant-collapse-content .ant-collapse-content-box { + + .antd5-collapse-content .antd5-collapse-content-box { display: flex; flex-direction: column; padding: 0 ${({ theme }) => theme.sizeUnit * 2}px; @@ -694,37 +695,37 @@ export default function VizTypeGallery(props: VizTypeGalleryProps) { } onClick={clickSelector} /> - - {Object.keys(sectionMap).map(sectionId => { + items={Object.keys(sectionMap).map(sectionId => { const section = sectionMap[sectionId as keyof typeof sectionMap]; - return ( - {section.title}} - key={sectionId} - > - {section.selectors.map((selector: string) => ( - - ))} - - ); + return { + key: sectionId, + label: {section.title}, + children: ( + <> + {section.selectors.map((selector: string) => ( + + ))} + + ), + }; })} - + /> diff --git a/superset-frontend/src/features/alerts/AlertReportModal.test.tsx b/superset-frontend/src/features/alerts/AlertReportModal.test.tsx index f526b465c1e..b79d27811e5 100644 --- a/superset-frontend/src/features/alerts/AlertReportModal.test.tsx +++ b/superset-frontend/src/features/alerts/AlertReportModal.test.tsx @@ -365,7 +365,7 @@ test('renders all Alert Condition fields', async () => { }); userEvent.click(screen.getByTestId('alert-condition-panel')); const database = screen.getByRole('combobox', { name: /database/i }); - const sql = screen.getAllByRole('textbox')[2]; + const sql = screen.getByRole('textbox'); const condition = screen.getByRole('combobox', { name: /condition/i }); const threshold = screen.getByRole('spinbutton'); expect(database).toBeInTheDocument(); diff --git a/superset-frontend/src/features/alerts/AlertReportModal.tsx b/superset-frontend/src/features/alerts/AlertReportModal.tsx index fb94c5c1114..63602cdb9ba 100644 --- a/superset-frontend/src/features/alerts/AlertReportModal.tsx +++ b/superset-frontend/src/features/alerts/AlertReportModal.tsx @@ -77,7 +77,6 @@ import NumberInput from './components/NumberInput'; import { AlertReportCronScheduler } from './components/AlertReportCronScheduler'; import { NotificationMethod } from './components/NotificationMethod'; import ValidatedPanelHeader from './components/ValidatedPanelHeader'; -import StyledPanel from './components/StyledPanel'; import { buildErrorTooltipMessage } from './buildErrorTooltipMessage'; const TIMEOUT_MIN = 1; @@ -210,14 +209,11 @@ const StyledModal = styled(Modal)` margin-top: ${({ theme }) => theme.sizeUnit}px; } - .ant-collapse > .ant-collapse-item { - border-bottom: none; - } - .inline-container { display: flex; flex-direction: row; align-items: center; + &.wrap { flex-wrap: wrap; } @@ -253,6 +249,7 @@ export const StyledInputContainer = styled.div` -webkit-appearance: none; margin: 0; } + input[type='number'] { -moz-appearance: textfield; } @@ -1471,473 +1468,502 @@ const AlertReportModal: FunctionComponent = ({ expandIconPosition="right" defaultActiveKey="general" accordion - css={css` - border: 'none'; - `} - > - - } - key="general" - > -
- -
- {isReport ? t('Report name') : t('Alert name')} - * -
-
- -
-
- -
- {t('Owners')} - * -
-
- -
-
- -
{t('Description')}
-
- -
-
- - -
- {isReport ? t('Report is active') : t('Alert is active')} -
-
-
-
- {!isReport && ( - - } - key="condition" - > - -
- {t('Database')} - * -
-
- -
-
- -
- {t('SQL Query')} - - * -
- -
-
- -
- {t('Trigger Alert If...')} - * -
-
- +
+
+ +
+ {t('Owners')} + * +
+
+ +
+
+ +
{t('Description')}
+
+ +
+
+ + -
- - -
- {t('Value')}{' '} - {!conditionNotNull && *} -
-
- -
-
- -
- )} - - } - key="contents" - > - -
- {t('Content type')} - * -
- FORMAT_OPTIONS[key as FORMAT_OPTIONS_KEY], - ) - : /* If chart is of text based viz type: show text - format option */ - TEXT_BASED_VISUALIZATION_TYPES.includes(chartVizType) - ? Object.values(FORMAT_OPTIONS) - : ['pdf', 'png', 'csv'].map( - key => FORMAT_OPTIONS[key as FORMAT_OPTIONS_KEY], - ) - } - placeholder={t('Select format')} - /> - - )} -
- {tabsEnabled && contentType === ContentType.Dashboard && ( - - <> -
{t('Select tab')}
- - -
- )} - {isScreenshot && ( - -
{t('Screenshot width')}
-
- +
+ {isReport ? t('Report is active') : t('Alert is active')} +
+
-
- )} - {(isReport || contentType === ContentType.Dashboard) && ( -
- - {t('Ignore cache when generating report')} - -
- )} -
- - } - key="schedule" - > - updateAlertState('crontab', newVal)} - /> - -
- {t('Timezone')} * -
- -
- -
- {t('Log retention')} - * -
-
- +
+
+ +
+ {t('Value')}{' '} + {!conditionNotNull && ( + * + )} +
+
+ +
+
+ + + ), + }, + ] + : []), { - // Prohibit 'add notification method' button if only one present - allowedNotificationMethodsCount > notificationSettings.length && ( - - ) - } -
- + ), + children: ( + <> + +
+ {t('Content type')} + * +
+ + FORMAT_OPTIONS[key as FORMAT_OPTIONS_KEY], + ) + : /* If chart is of text based viz type: show text + format option */ + TEXT_BASED_VISUALIZATION_TYPES.includes( + chartVizType, + ) + ? Object.values(FORMAT_OPTIONS) + : ['pdf', 'png', 'csv'].map( + key => + FORMAT_OPTIONS[key as FORMAT_OPTIONS_KEY], + ) + } + placeholder={t('Select format')} + /> + + )} +
+ {tabsEnabled && contentType === ContentType.Dashboard && ( + + <> +
{t('Select tab')}
+ + +
+ )} + {isScreenshot && ( + +
{t('Screenshot width')}
+
+ +
+
+ )} + {(isReport || contentType === ContentType.Dashboard) && ( +
+ + {t('Ignore cache when generating report')} + +
+ )} + + ), + }, + { + key: 'schedule', + label: ( + + ), + children: ( + <> + updateAlertState('crontab', newVal)} + /> + +
+ {t('Timezone')} * +
+ +
+ +
+ {t('Log retention')} + * +
+
+ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + ), + }, + ]} + /> ); }; diff --git a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx index 969901fd2db..1e90d663554 100644 --- a/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx +++ b/superset-frontend/src/features/databases/DatabaseModal/ExtraOptions.tsx @@ -33,7 +33,6 @@ import { StyledInputContainer, StyledJsonEditor, StyledExpandableForm, - antdCollapseStyles, no_margin_bottom, } from './styles'; import { DatabaseObject, ExtraJson } from '../types'; @@ -86,547 +85,575 @@ const ExtraOptions = ({ antdCollapseStyles(theme)} - > - -

{t('SQL Lab')}

-

- {t('Adjust how this database will interact with SQL Lab.')} -

-
- } - key="1" - > - -
- - -
- - -
- - -
-
- -
- - -
- -
{t('CTAS & CVAS SCHEMA')}
+ items={[ + { + key: 'sql-lab', + label: ( +
+

{t('SQL Lab')}

+

{t('Adjust how this database will interact with SQL Lab.')}

+
+ ), + children: ( + <> + +
+ + +
+ + +
+ + +
+
+ +
+ + +
+ +
+ {t('CTAS & CVAS SCHEMA')} +
+
+ +
+
+ {t( + 'Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.', + )} +
+
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+
+
+ + ), + }, + { + key: 'performance', + label: ( +
+

{t('Performance')}

+

{t('Adjust performance settings of this database.')}

+
+ ), + children: ( + <> + +
{t('Chart cache timeout')}
{t( - 'Force all tables and views to be created in this schema when clicking CTAS or CVAS in SQL Lab.', + 'Duration (in seconds) of the caching timeout for charts of this database.' + + ' A timeout of 0 indicates that the cache never expires, and -1 bypasses the cache.' + + ' Note this defaults to the global timeout if undefined.', )}
-
- -
- - +
{t('Schema cache timeout')}
+
+ +
+
+ {t( + 'Duration (in seconds) of the metadata caching timeout for schemas of ' + + 'this database. If left unset, the cache never expires.', )} - /> -
- - -
- - + + +
{t('Table cache timeout')}
+
+ +
+
+ {t( + 'Duration (in seconds) of the metadata caching timeout for tables of ' + + 'this database. If left unset, the cache never expires. ', )} - /> -
-
- -
- - + + +
+ + + {isAllowRunAsyncDisabled && ( + )} - /> -
-
- -
- - -
-
- -
- - -
-
- - - - -

{t('Performance')}

-

- {t('Adjust performance settings of this database.')} -

-
- } - key="2" - > - -
{t('Chart cache timeout')}
-
- -
-
- {t( - 'Duration (in seconds) of the caching timeout for charts of this database.' + - ' A timeout of 0 indicates that the cache never expires, and -1 bypasses the cache.' + - ' Note this defaults to the global timeout if undefined.', - )} -
-
- -
{t('Schema cache timeout')}
-
- -
-
- {t( - 'Duration (in seconds) of the metadata caching timeout for schemas of ' + - 'this database. If left unset, the cache never expires.', - )} -
-
- -
{t('Table cache timeout')}
-
- -
-
- {t( - 'Duration (in seconds) of the metadata caching timeout for tables of ' + - 'this database. If left unset, the cache never expires. ', - )} -
-
- -
- - - {isAllowRunAsyncDisabled && ( - - )} -
-
- -
- - -
-
- - -

{t('Security')}

-

{t('Add extra connection information.')}

-
- } - key="3" - > - -
{t('Secure extra')}
-
- - onEditorChange({ json, name: 'masked_encrypted_extra' }) - } - width="100%" - height="160px" - /> -
-
+
+
+ +
+ + +
+
+ + ), + }, + { + key: 'security', + label: (
- {t( - 'JSON string containing additional connection configuration. ' + - 'This is used to provide connection information for systems ' + - 'like Hive, Presto and BigQuery which do not conform to the ' + - 'username:password syntax normally used by SQLAlchemy.', - )} +

{t('Security')}

+

{t('Add extra connection information.')}

-
-
- -
{t('Root certificate')}
-
-