From 5e02cfdcfa290f70cd37cb9a946b361525d4abc4 Mon Sep 17 00:00:00 2001 From: geido Date: Sun, 29 Aug 2021 18:11:41 +0300 Subject: [PATCH 01/31] Refactor Select DatasourceEditor --- superset-frontend/src/datasource/DatasourceEditor.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx index e11b8310bb75c..5450e92bd1651 100644 --- a/superset-frontend/src/datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/datasource/DatasourceEditor.jsx @@ -41,6 +41,7 @@ import { getClientErrorObject } from 'src/utils/getClientErrorObject'; import CheckboxControl from 'src/explore/components/controls/CheckboxControl'; import TextControl from 'src/explore/components/controls/TextControl'; import SelectControl from 'src/explore/components/controls/SelectControl'; +import { Select } from 'src/components'; import TextAreaControl from 'src/explore/components/controls/TextAreaControl'; import SelectAsyncControl from 'src/explore/components/controls/SelectAsyncControl'; import SpatialControl from 'src/explore/components/controls/SpatialControl'; @@ -113,7 +114,12 @@ const ColumnButtonWrapper = styled.div` const checkboxGenerator = (d, onChange) => ( ); -const DATA_TYPES = ['STRING', 'NUMERIC', 'DATETIME', 'BOOLEAN']; +const DATA_TYPES = [ + { value: 'STRING', label: 'STRING' }, + { value: 'NUMERIC', label: 'NUMERIC' }, + { value: 'DATETIME', label: 'DATETIME' }, + { value: 'BOOLEAN', label: 'BOOLEAN' }, +]; const DATASOURCE_TYPES_ARR = [ { key: 'physical', label: t('Physical (table or view)') }, @@ -199,7 +205,7 @@ function ColumnCollectionTable({ fieldKey="type" label={t('Data type')} control={ - + + } + header={} name="annotation-layer-stroke" // see '../../../visualizations/nvd3_vis.css' options={[ diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx index 22350af54363c..3c3b68525b3bd 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.test.tsx @@ -83,8 +83,8 @@ test('renders extra checkboxes when type is time series', () => { test('enables apply and ok buttons', async () => { render(); - userEvent.type(screen.getByLabelText('Name'), 'Test'); - userEvent.type(screen.getByLabelText('Formula'), '2x'); + userEvent.type(screen.getByRole('textbox', { name: 'Name' }), 'Test'); + userEvent.type(screen.getByRole('textbox', { name: 'Formula' }), '2x'); await waitFor(() => { expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled(); expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled(); @@ -153,12 +153,17 @@ test('renders chart options', async () => { annotationType={ANNOTATION_TYPES_METADATA.EVENT.value} />, ); - userEvent.click(screen.getByText('2 option(s)')); - userEvent.click(screen.getByText('Superset annotation')); - expect(await screen.findByLabelText('Annotation layer')).toBeInTheDocument(); + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation source type' }), + ); userEvent.click(screen.getByText('Superset annotation')); + expect(screen.getByText('Annotation layer')).toBeInTheDocument(); + + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation source type' }), + ); userEvent.click(screen.getByText('Table')); - expect(await screen.findByLabelText('Chart')).toBeInTheDocument(); + expect(screen.getByText('Chart')).toBeInTheDocument(); }); test('keeps apply disabled when missing required fields', async () => { @@ -169,18 +174,28 @@ test('keeps apply disabled when missing required fields', async () => { sourceType="Table" />, ); - userEvent.click(await screen.findByText('1 option(s)')); - userEvent.click(screen.getByText('Chart A')); + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation layer value' }), + ); + userEvent.click(await screen.findByText('Chart A')); expect( screen.getByText('Annotation Slice Configuration'), ).toBeInTheDocument(); userEvent.click(screen.getByRole('button', { name: 'Automatic Color' })); - userEvent.click(screen.getByLabelText('Title Column')); + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation layer title column' }), + ); userEvent.click(screen.getByText('None')); - userEvent.click(screen.getByLabelText('Style')); + userEvent.click(screen.getByText('Style')); + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation layer stroke' }), + ); userEvent.click(screen.getByText('Dashed')); - userEvent.click(screen.getByLabelText('Opacity')); + userEvent.click(screen.getByText('Opacity')); + userEvent.click( + screen.getByRole('combobox', { name: 'Annotation layer opacity' }), + ); userEvent.click(screen.getByText('0.5')); const checkboxes = screen.getAllByRole('checkbox'); From 67a23322d9aeac706857fccd97053d3ad5fcd889 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 30 Aug 2021 18:05:50 +0300 Subject: [PATCH 07/31] Refactor Select in SpatialControl --- superset-frontend/src/components/Select/Select.tsx | 1 + .../explore/components/controls/SpatialControl.jsx | 11 +++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/superset-frontend/src/components/Select/Select.tsx b/superset-frontend/src/components/Select/Select.tsx index 64b816a0d7ed5..8f5b9ce121140 100644 --- a/superset-frontend/src/components/Select/Select.tsx +++ b/superset-frontend/src/components/Select/Select.tsx @@ -53,6 +53,7 @@ type PickedSelectProps = Pick< | 'notFoundContent' | 'onChange' | 'onClear' + | 'onFocus' | 'placeholder' | 'showSearch' | 'value' diff --git a/superset-frontend/src/explore/components/controls/SpatialControl.jsx b/superset-frontend/src/explore/components/controls/SpatialControl.jsx index cf9ae6b8c8764..74de44ef536db 100644 --- a/superset-frontend/src/explore/components/controls/SpatialControl.jsx +++ b/superset-frontend/src/explore/components/controls/SpatialControl.jsx @@ -25,8 +25,8 @@ import Label from 'src/components/Label'; import Popover from 'src/components/Popover'; import PopoverSection from 'src/components/PopoverSection'; import Checkbox from 'src/components/Checkbox'; +import { Select } from 'src/components'; import ControlHeader from '../ControlHeader'; -import SelectControl from './SelectControl'; const spatialTypes = { latlong: 'latlong', @@ -133,11 +133,14 @@ export default class SpatialControl extends React.Component { renderSelect(name, type) { return ( - ({ + value: o[0], + label: o[1], + }))} value={this.state[name]} - clearable={false} onFocus={() => { this.setType(type); }} From baa04dc4d970eb61fdfa547c91c29e7b5798cbf1 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 30 Aug 2021 18:21:00 +0300 Subject: [PATCH 08/31] Show search --- superset-frontend/src/datasource/DatasourceEditor.jsx | 1 + .../controls/AnnotationLayerControl/AnnotationLayer.jsx | 9 +++++++++ .../src/explore/components/controls/SpatialControl.jsx | 1 + 3 files changed, 11 insertions(+) diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx index a7f961efab734..31da9f3808617 100644 --- a/superset-frontend/src/datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/datasource/DatasourceEditor.jsx @@ -210,6 +210,7 @@ function ColumnCollectionTable({ name="type" allowNewOptions allowClear + showSearch /> } /> diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx index fcb10545e8667..adc887bf932f5 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx @@ -434,6 +434,7 @@ export default class AnnotationLayer extends React.PureComponent { }))} value={value} allowClear + showSearch /> ); } @@ -508,6 +509,7 @@ export default class AnnotationLayer extends React.PureComponent { onChange={v => this.setState({ timeColumn: v })} options={timeColumnOptions} value={timeColumn} + showSearch /> )} {annotationType === ANNOTATION_TYPES.INTERVAL && ( @@ -533,6 +535,7 @@ export default class AnnotationLayer extends React.PureComponent { options={columns} value={intervalEndColumn} allowClear + showSearch /> )} )}
@@ -680,6 +685,7 @@ export default class AnnotationLayer extends React.PureComponent { ]} onChange={v => this.setState({ style: v })} value={style} + showSearch /> )} {this.renderValueConfiguration()} diff --git a/superset-frontend/src/explore/components/controls/SpatialControl.jsx b/superset-frontend/src/explore/components/controls/SpatialControl.jsx index 74de44ef536db..e75ac6dda03d6 100644 --- a/superset-frontend/src/explore/components/controls/SpatialControl.jsx +++ b/superset-frontend/src/explore/components/controls/SpatialControl.jsx @@ -147,6 +147,7 @@ export default class SpatialControl extends React.Component { onChange={value => { this.setState({ [name]: value }, this.onChange); }} + showSearch /> ); } From 46be115adcc4ee518888b81e408555a156fe1e88 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 30 Aug 2021 18:39:16 +0300 Subject: [PATCH 09/31] Refactor Select in FilterBox --- .../controls/FilterBoxItemControl/index.jsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx b/superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx index e04ce8bb1a0fc..b3eef3508297f 100644 --- a/superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx +++ b/superset-frontend/src/explore/components/controls/FilterBoxItemControl/index.jsx @@ -23,7 +23,7 @@ import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls'; import Popover from 'src/components/Popover'; import FormRow from 'src/components/FormRow'; -import SelectControl from 'src/explore/components/controls/SelectControl'; +import { Select } from 'src/components'; import CheckboxControl from 'src/explore/components/controls/CheckboxControl'; import TextControl from 'src/explore/components/controls/TextControl'; import { FILTER_CONFIG_ATTRIBUTES } from 'src/explore/constants'; @@ -136,12 +136,12 @@ export default class FilterBoxItemControl extends React.Component { col !== this.state.column) + .filter(col => col.column_name !== this.state.column) .map(col => ({ value: col.column_name, label: col.column_name, @@ -150,6 +150,7 @@ export default class FilterBoxItemControl extends React.Component { { value: this.state.column, label: this.state.column }, ])} onChange={v => this.onControlChange('column', v)} + showSearch /> } /> @@ -184,11 +185,12 @@ export default class FilterBoxItemControl extends React.Component { label={t('Sort metric')} tooltip={t('Metric to sort the results by')} control={ - metric !== this.state.metric) + .filter(m => m.metric_name !== this.state.metric) .map(m => ({ value: m.metric_name, label: m.metric_name, @@ -197,6 +199,7 @@ export default class FilterBoxItemControl extends React.Component { { value: this.state.metric, label: this.state.metric }, ])} onChange={v => this.onControlChange('metric', v)} + showSearch /> } /> From 75e2dcbed7ace2d5bb8ae76ec1b7fe661e57a1b6 Mon Sep 17 00:00:00 2001 From: geido Date: Mon, 30 Aug 2021 19:04:59 +0300 Subject: [PATCH 10/31] Remove search where unnecessary --- superset-frontend/src/datasource/DatasourceEditor.jsx | 1 - .../controls/AnnotationLayerControl/AnnotationLayer.jsx | 3 --- 2 files changed, 4 deletions(-) diff --git a/superset-frontend/src/datasource/DatasourceEditor.jsx b/superset-frontend/src/datasource/DatasourceEditor.jsx index 31da9f3808617..a7f961efab734 100644 --- a/superset-frontend/src/datasource/DatasourceEditor.jsx +++ b/superset-frontend/src/datasource/DatasourceEditor.jsx @@ -210,7 +210,6 @@ function ColumnCollectionTable({ name="type" allowNewOptions allowClear - showSearch /> } /> diff --git a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx index adc887bf932f5..8eb152dd4dd45 100644 --- a/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx +++ b/superset-frontend/src/explore/components/controls/AnnotationLayerControl/AnnotationLayer.jsx @@ -685,7 +685,6 @@ export default class AnnotationLayer extends React.PureComponent { ]} onChange={v => this.setState({ style: v })} value={style} - showSearch /> Date: Mon, 30 Aug 2021 20:11:07 +0300 Subject: [PATCH 11/31] Update SelectControl - WIP --- .../explore/components/SelectControl_spec.jsx | 41 ---- .../spec/javascripts/explore/fixtures.tsx | 2 - .../components/controls/SelectControl.jsx | 212 +++++------------- superset-frontend/src/explore/controls.jsx | 3 - 4 files changed, 50 insertions(+), 208 deletions(-) diff --git a/superset-frontend/spec/javascripts/explore/components/SelectControl_spec.jsx b/superset-frontend/spec/javascripts/explore/components/SelectControl_spec.jsx index b9c76e38056e9..7201f742b0890 100644 --- a/superset-frontend/spec/javascripts/explore/components/SelectControl_spec.jsx +++ b/superset-frontend/spec/javascripts/explore/components/SelectControl_spec.jsx @@ -66,22 +66,6 @@ describe('SelectControl', () => { expect(defaultProps.onChange.calledWith(50)).toBe(true); }); - it('returns all options on select all', () => { - const expectedValues = ['one', 'two']; - const selectAllProps = { - multi: true, - allowAll: true, - choices: expectedValues, - name: 'row_limit', - label: 'Row Limit', - valueKey: 'value', - onChange: sinon.spy(), - }; - wrapper.setProps(selectAllProps); - wrapper.instance().onChange([{ meta: true, value: 'Select all' }]); - expect(selectAllProps.onChange.calledWith(expectedValues)).toBe(true); - }); - describe('render', () => { it('renders with Select by default', () => { expect(wrapper.find(OnPasteSelect)).not.toExist(); @@ -207,14 +191,6 @@ describe('SelectControl', () => { expect(wrapper.instance().optionsRemaining()).toEqual(2); }); }); - describe('with Select all', () => { - it('does not count it', () => { - const props = { ...defaultProps, multi: true, allowAll: true }; - const wrapper = mount(); - expect(wrapper.instance().getOptions(props).length).toEqual(3); - expect(wrapper.instance().optionsRemaining()).toEqual(2); - }); - }); }); describe('getOptions', () => { @@ -223,23 +199,6 @@ describe('SelectControl', () => { expect(wrapper.instance().getOptions(defaultProps)).toEqual(options); }); - it('shows Select-All when enabled', () => { - const selectAllProps = { - choices: ['one', 'two'], - name: 'name', - freeForm: true, - allowAll: true, - multi: true, - valueKey: 'value', - }; - wrapper.setProps(selectAllProps); - expect(wrapper.instance().getOptions(selectAllProps)).toContainEqual({ - label: 'Select all', - meta: true, - value: 'Select all', - }); - }); - it('returns the correct options when freeform is set to true', () => { const freeFormProps = { choices: [], diff --git a/superset-frontend/spec/javascripts/explore/fixtures.tsx b/superset-frontend/spec/javascripts/explore/fixtures.tsx index d9185cf83eafc..81e9f722dae7e 100644 --- a/superset-frontend/spec/javascripts/explore/fixtures.tsx +++ b/superset-frontend/spec/javascripts/explore/fixtures.tsx @@ -95,11 +95,9 @@ export const controlPanelSectionsChartOptionsTable: ControlPanelSectionConfig[] optionRenderer: c => , valueRenderer: c => , valueKey: 'column_name', - allowAll: true, mapStateToProps: stateRef => ({ options: stateRef.datasource ? stateRef.datasource.columns : [], }), - commaChoosesOption: false, freeForm: true, } as ControlConfig<'SelectControl', ColumnMeta>, }, diff --git a/superset-frontend/src/explore/components/controls/SelectControl.jsx b/superset-frontend/src/explore/components/controls/SelectControl.jsx index 6bfcecec78fe5..08cf387814c0f 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.jsx @@ -19,7 +19,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import { t, css } from '@superset-ui/core'; -import { Select, CreatableSelect, OnPasteSelect } from 'src/components/Select'; +import { Select } from 'src/components/Select'; import ControlHeader from 'src/explore/components/ControlHeader'; const propTypes = { @@ -33,7 +33,6 @@ const propTypes = { label: PropTypes.string, multi: PropTypes.bool, isMulti: PropTypes.bool, - allowAll: PropTypes.bool, name: PropTypes.string.isRequired, onChange: PropTypes.func, onFocus: PropTypes.func, @@ -48,15 +47,18 @@ const propTypes = { valueKey: PropTypes.string, options: PropTypes.array, placeholder: PropTypes.string, - noResultsText: PropTypes.string, - selectRef: PropTypes.func, filterOption: PropTypes.func, - promptTextCreator: PropTypes.func, - commaChoosesOption: PropTypes.bool, - menuPortalTarget: PropTypes.element, - menuPosition: PropTypes.string, - menuPlacement: PropTypes.string, - forceOverflow: PropTypes.bool, + + // ControlHeader props + renderTrigger: PropTypes.bool, + validationErrors: PropTypes.array, + rightNode: PropTypes.node, + leftNode: PropTypes.node, + onClick: PropTypes.func, + hovered: PropTypes.bool, + tooltipOnClick: PropTypes.func, + warning: PropTypes.string, + danger: PropTypes.string, }; const defaultProps = { @@ -73,10 +75,6 @@ const defaultProps = { onFocus: () => {}, showHeader: true, valueKey: 'value', - noResultsText: t('No results found'), - promptTextCreator: label => `Create Option ${label}`, - commaChoosesOption: true, - allowAll: false, }; export default class SelectControl extends React.PureComponent { @@ -87,10 +85,6 @@ export default class SelectControl extends React.PureComponent { value: this.props.value, }; this.onChange = this.onChange.bind(this); - this.createMetaSelectAllOption = this.createMetaSelectAllOption.bind(this); - this.select = null; // pointer to the react-select instance - this.getSelectRef = this.getSelectRef.bind(this); - this.handleKeyDownForCreate = this.handleKeyDownForCreate.bind(this); } UNSAFE_componentWillReceiveProps(nextProps) { @@ -103,39 +97,6 @@ export default class SelectControl extends React.PureComponent { } } - // Beware: This is acting like an on-click instead of an on-change - // (firing every time user chooses vs firing only if a new option is chosen). - onChange(opt, actionMeta) { - let optionValue = this.props.multi ? [] : null; - if (opt) { - if (this.props.multi) { - opt.forEach(o => { - // select all options - if (o.meta === true) { - optionValue = this.getOptions(this.props) - .filter(x => !x.meta) - .map(x => x[this.props.valueKey]); - return; - } - optionValue.push(o[this.props.valueKey] || o); - }); - } else if (opt.meta === true) { - return; - } else { - optionValue = opt[this.props.valueKey]; - } - } - // will eventually call `exploreReducer`: SET_FIELD_VALUE - this.props.onChange(optionValue, [], actionMeta); - } - - getSelectRef(instance) { - this.select = instance; - if (this.props.selectRef) { - this.props.selectRef(instance); - } - } - getOptions(props) { let options = []; if (props.options) { @@ -153,66 +114,9 @@ export default class SelectControl extends React.PureComponent { return { label: c, [props.valueKey]: c }; }); } - // For FreeFormSelect, insert newly created values into options - if (props.freeForm && props.value) { - const existingOptionValues = new Set(options.map(c => c[props.valueKey])); - const selectedValues = Array.isArray(props.value) - ? props.value - : [props.value]; - selectedValues.forEach(v => { - if (!existingOptionValues.has(v)) { - // place the newly created options at the top - options.unshift({ label: v, [props.valueKey]: v }); - } - }); - } - if (props.allowAll === true && props.multi === true) { - if (!this.optionsIncludesSelectAll(options)) { - options.unshift(this.createMetaSelectAllOption()); - } - } else { - options = options.filter(o => !this.isMetaSelectAllOption(o)); - } return options; } - handleKeyDownForCreate(event) { - const { key } = event; - if (key === 'Tab' || (this.props.commaChoosesOption && key === ',')) { - // simulate an Enter event - if (this.select) { - this.select.onKeyDown({ ...event, key: 'Enter' }); - } - } - } - - isMetaSelectAllOption(o) { - return o.meta && o.meta === true && o.label === 'Select all'; - } - - optionsIncludesSelectAll(o) { - return o.findIndex(o => this.isMetaSelectAllOption(o)) >= 0; - } - - optionsRemaining() { - const { options } = this.state; - const { value } = this.props; - // if select is multi/value is array, we show the options not selected - let remainingOptions = Array.isArray(value) - ? options.length - value.length - : options.length; - if (this.optionsIncludesSelectAll(options)) { - remainingOptions -= 1; - } - return remainingOptions < 0 ? 0 : remainingOptions; - } - - createMetaSelectAllOption() { - const option = { label: 'Select all', meta: true }; - option[this.props.valueKey] = 'Select all'; - return option; - } - render() { // Tab, comma or Enter will trigger a new option created for FreeFormSelect const { @@ -221,78 +125,67 @@ export default class SelectControl extends React.PureComponent { disabled, filterOption, isLoading, + isMulti, label, - menuPlacement, + multi, name, - noResultsText, + placeholder, + onChange, onFocus, optionRenderer, - promptTextCreator, + showHeader, value, valueKey, valueRenderer, - forceOverflow, - menuPortalTarget, - menuPosition, + // ControlHeader props + description, + renderTrigger, + rightNode, + leftNode, + validationErrors, + onClick, + hovered, + tooltipOnClick, + warning, + danger, } = this.props; - const optionsRemaining = this.optionsRemaining(); - const optionRemaingText = optionsRemaining - ? t('%s option(s)', optionsRemaining) - : ''; - const placeholder = this.props.placeholder || optionRemaingText; - const isMulti = this.props.isMulti || this.props.multi; - - let assistiveText; - if ( - isMulti && - optionsRemaining && - Array.isArray(this.state.value) && - Array.isArray(value) && - !!value.length - ) { - assistiveText = optionRemaingText; - } + const headerProps = { + name, + label, + description, + renderTrigger, + rightNode, + leftNode, + validationErrors, + onClick, + hovered, + tooltipOnClick, + warning, + danger, + }; const selectProps = { + allowNewOptions: this.props.freeForm, autoFocus, - 'aria-label': label, - clearable, + ariaLabel: label, + allowClear: clearable, disabled, filterOption, - ignoreAccents: false, - isLoading, - isMulti, - labelKey: 'label', - menuPlacement, - forceOverflow, - menuPortalTarget, - menuPosition, + header: showHeader && , + loading: isLoading, + mode: isMulti || multi ? 'multiple' : 'single', name: `select-${name}`, - noResultsText, - onChange: this.onChange, + onChange, onFocus, optionRenderer, value, options: this.state.options, placeholder, - assistiveText, - promptTextCreator, - selectRef: this.getSelectRef, valueKey, valueRenderer, }; - let SelectComponent; - if (this.props.freeForm) { - SelectComponent = CreatableSelect; - // Don't create functions in `render` because React relies on shallow - // compare to decide weathere to rerender child components. - selectProps.onKeyDown = this.handleKeyDownForCreate; - } else { - SelectComponent = Select; - } - return (
css` @@ -301,12 +194,7 @@ export default class SelectControl extends React.PureComponent { } `} > - {this.props.showHeader && } - {isMulti ? ( - - ) : ( - - )} + - } - loading={isLoadingOptions} name="annotation-layer-value" - onChange={value => this.handleOnChange(value, this.handleValue)} - onClear={this.handleOnClear} - options={valueOptions.map(o => ({ - value: o.value, - label: this.renderOption(o), - }))} + showHeader + hovered + description={description} + label={label} + placeholder="" + options={valueOptions} + isLoading={isLoadingOptions} value={value} - allowClear - showSearch + onChange={value => this.popoverClearWrapper(value, this.handleValue)} + validationErrors={!value ? ['Mandatory'] : []} + optionRenderer={this.renderOption} /> ); } @@ -470,7 +461,6 @@ export default class AnnotationLayer extends React.PureComponent { intervalEndColumn, descriptionColumns, } = this.state; - const { slice } = valueOptions.find(x => x.value === value) || {}; if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE && slice) { const columns = (slice.data.groupby || []) @@ -489,99 +479,75 @@ export default class AnnotationLayer extends React.PureComponent { > {(annotationType === ANNOTATION_TYPES.EVENT || annotationType === ANNOTATION_TYPES.INTERVAL) && ( - - } + hovered name="annotation-layer-intervalEnd" + label={t('Interval End column')} + description={t( + 'This column must contain date/time information.', + )} + validationErrors={!intervalEndColumn ? ['Mandatory'] : []} + options={columns} + value={intervalEndColumn} onChange={value => - this.handleOnChange(value, v => + this.popoverClearWrapper(value, v => this.setState({ intervalEndColumn: v }), ) } - onClear={this.handleOnClear} - options={columns} - value={intervalEndColumn} - allowClear - showSearch /> )} - - } + hovered name="annotation-layer-title" - mode="multiple" + label={t('Description Columns')} + description={t( + "Pick one or more columns that should be shown in the annotation. If you don't select a column all of them will be shown.", + )} + multi + options={columns} + value={descriptionColumns} onChange={value => - this.handleOnChange(value, v => + this.popoverClearWrapper(value, v => this.setState({ descriptionColumns: v }), ) } - onClear={this.handleOnClear} - options={columns} - value={descriptionColumns} - allowClear - showSearch /> )}
@@ -672,10 +638,10 @@ export default class AnnotationLayer extends React.PureComponent { title={t('Display configuration')} info={t('Configure your how you overlay is displayed here.')} > - } name="annotation-layer-opacity" + label={t('Opacity')} // see '../../../visualizations/nvd3_vis.css' options={[ { value: '', label: 'Solid' }, @@ -697,12 +664,10 @@ export default class AnnotationLayer extends React.PureComponent { { value: 'opacityMedium', label: '0.5' }, { value: 'opacityHigh', label: '0.8' }, ]} + value={opacity} onChange={value => - this.handleOnChange(value, v => this.setState({ opacity: v })) + this.popoverClearWrapper(value, v => this.setState({ opacity: v })) } - onClear={this.handleOnClear} - value={opacity} - allowClear />
@@ -790,41 +755,33 @@ export default class AnnotationLayer extends React.PureComponent { value={!show} onChange={v => this.setState({ show: !v })} /> - - } + hovered + description={t('Choose the source of your annotations')} + label={t('Annotation Source')} name="annotation-source-type" options={supportedSourceTypes} value={sourceType} onChange={value => - this.handleOnChange(value, this.handleAnnotationSourceType) + this.popoverClearWrapper( + value, + this.handleAnnotationSourceType, + ) } - onClear={this.handleOnClear} - allowClear - showSearch + validationErrors={!sourceType ? [t('Mandatory')] : []} /> )} {this.renderValueConfiguration()} diff --git a/superset-frontend/src/explore/components/controls/SelectControl.jsx b/superset-frontend/src/explore/components/controls/SelectControl.jsx index dbcb970e05614..e01bf405e151b 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.jsx @@ -23,6 +23,7 @@ import { Select } from 'src/components'; import ControlHeader from 'src/explore/components/ControlHeader'; const propTypes = { + ariaLabel: PropTypes.string, autoFocus: PropTypes.bool, choices: PropTypes.array, clearable: PropTypes.bool, @@ -144,6 +145,7 @@ export default class SelectControl extends React.PureComponent { render() { const { + ariaLabel, autoFocus, clearable, disabled, @@ -190,7 +192,7 @@ export default class SelectControl extends React.PureComponent { const selectProps = { allowNewOptions: freeForm, autoFocus, - ariaLabel: label, + ariaLabel: ariaLabel || label, allowClear: clearable, defaultValue: this.props.default || undefined, disabled, From 3118a55a90b807e47ee8ec7711910e1044a62b60 Mon Sep 17 00:00:00 2001 From: geido Date: Tue, 31 Aug 2021 17:21:11 +0300 Subject: [PATCH 17/31] Use SelectControl SpatialControl --- .../src/explore/components/controls/SelectControl.jsx | 2 +- .../explore/components/controls/SpatialControl.jsx | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/superset-frontend/src/explore/components/controls/SelectControl.jsx b/superset-frontend/src/explore/components/controls/SelectControl.jsx index e01bf405e151b..f694606a8fb98 100644 --- a/superset-frontend/src/explore/components/controls/SelectControl.jsx +++ b/superset-frontend/src/explore/components/controls/SelectControl.jsx @@ -192,7 +192,7 @@ export default class SelectControl extends React.PureComponent { const selectProps = { allowNewOptions: freeForm, autoFocus, - ariaLabel: ariaLabel || label, + ariaLabel: ariaLabel || label || name, allowClear: clearable, defaultValue: this.props.default || undefined, disabled, diff --git a/superset-frontend/src/explore/components/controls/SpatialControl.jsx b/superset-frontend/src/explore/components/controls/SpatialControl.jsx index e75ac6dda03d6..23456db8b0f54 100644 --- a/superset-frontend/src/explore/components/controls/SpatialControl.jsx +++ b/superset-frontend/src/explore/components/controls/SpatialControl.jsx @@ -25,8 +25,8 @@ import Label from 'src/components/Label'; import Popover from 'src/components/Popover'; import PopoverSection from 'src/components/PopoverSection'; import Checkbox from 'src/components/Checkbox'; -import { Select } from 'src/components'; import ControlHeader from '../ControlHeader'; +import SelectControl from './SelectControl'; const spatialTypes = { latlong: 'latlong', @@ -133,21 +133,18 @@ export default class SpatialControl extends React.Component { renderSelect(name, type) { return ( -