From c461abbdeb780a0ba2aec338b2a8c1c9cf5eaced Mon Sep 17 00:00:00 2001 From: Kamil Gabryjelski Date: Mon, 24 May 2021 10:22:43 +0200 Subject: [PATCH] feat(chart-controls): implement drag&drop controls for all charts (#1127) * feat(chart-controls): implement drag&drop controls for all charts * Split stacked controls into separate rows --- .../src/shared-controls/dndControls.tsx | 25 ++++++++++ .../src/shared-controls/index.tsx | 13 +++-- .../src/utils/columnChoices.ts | 2 +- .../src/controlPanel.ts | 41 +++++++++------ .../src/controlPanel.ts | 40 ++++++++++----- .../src/controlPanel.ts | 30 +++++++---- .../src/Bubble/controlPanel.ts | 4 +- .../plugin-chart-table/src/controlPanel.tsx | 50 ++++++++++++++----- 8 files changed, 147 insertions(+), 58 deletions(-) diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx index 429b3401aab..5e49652fb86 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx @@ -124,3 +124,28 @@ export const dnd_sort_by: SharedControlConfig<'DndMetricSelect'> = { datasourceType: datasource?.type, }), }; + +export const dnd_size: SharedControlConfig<'DndMetricSelect'> = { + ...dnd_adhoc_metric, + label: t('Bubble Size'), + description: t('Metric used to calculate bubble size'), +}; + +export const dnd_x: SharedControlConfig<'DndMetricSelect'> = { + ...dnd_adhoc_metric, + label: t('X Axis'), + description: t('Metric assigned to the [X] axis'), +}; + +export const dnd_y: SharedControlConfig<'DndMetricSelect'> = { + ...dnd_adhoc_metric, + label: t('Y Axis'), + description: t('Metric assigned to the [Y] axis'), +}; + +export const dnd_secondary_metric: SharedControlConfig<'DndMetricSelect'> = { + ...dnd_adhoc_metric, + label: t('Color Metric'), + validators: [], + description: t('A metric to use for color'), +}; diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/index.tsx b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/index.tsx index b58af87b452..1dfd03ce949 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/index.tsx +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/shared-controls/index.tsx @@ -70,6 +70,10 @@ import { dnd_adhoc_metric, dnd_adhoc_metrics, dnd_sort_by, + dnd_secondary_metric, + dnd_size, + dnd_x, + dnd_y, dndColumnsControl, dndEntity, dndGroupByControl, @@ -389,6 +393,7 @@ const y: SharedControlConfig<'MetricsControl'> = { const size: SharedControlConfig<'MetricsControl'> = { ...metric, label: t('Bubble Size'), + description: t('Metric used to calculate bubble size'), default: null, }; @@ -471,7 +476,7 @@ const sharedControls = { color_picker, metric_2, linear_color_scheme, - secondary_metric, + secondary_metric: enableExploreDnd ? dnd_secondary_metric : secondary_metric, groupby: enableExploreDnd ? dndGroupByControl : groupByControl, columns: enableExploreDnd ? dndColumnsControl : columnsControl, druid_time_origin, @@ -485,9 +490,9 @@ const sharedControls = { orderby: enableExploreDnd ? dnd_sort_by : sort_by, series: enableExploreDnd ? dndSeries : series, entity: enableExploreDnd ? dndEntity : entity, - x, - y, - size, + x: enableExploreDnd ? dnd_x : x, + y: enableExploreDnd ? dnd_y : y, + size: enableExploreDnd ? dnd_size : size, y_axis_format, x_axis_time_format, adhoc_filters: enableExploreDnd ? dnd_adhoc_filters : adhoc_filters, diff --git a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts index 5cca2902478..fd8aa3c32de 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/packages/superset-ui-chart-controls/src/utils/columnChoices.ts @@ -19,7 +19,7 @@ import { DatasourceMeta } from '../types'; /** - * Convert Dataource columns to column choices + * Convert Datasource columns to column choices */ export default function columnChoices(datasource?: DatasourceMeta | null): [string, string][] { return ( diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts index 73ef67f7bb6..e50ea1e49ca 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-heatmap/src/controlPanel.ts @@ -16,14 +16,16 @@ * specific language governing permissions and limitations * under the License. */ -import { t, validateNonEmpty } from '@superset-ui/core'; +import { FeatureFlag, isFeatureEnabled, t, validateNonEmpty } from '@superset-ui/core'; import { columnChoices, ControlPanelConfig, + ControlPanelState, formatSelectOptions, formatSelectOptionsForRange, sections, } from '@superset-ui/chart-controls'; +import { dndEntity } from '@superset-ui/chart-controls/lib/shared-controls/dndControls'; const sortAxisChoices = [ ['alpha_asc', t('Axis ascending')], @@ -32,6 +34,25 @@ const sortAxisChoices = [ ['value_desc', t('Metric descending')], ]; +const allColumns = { + type: 'SelectControl', + default: null, + description: t('Columns to display'), + mapStateToProps: (state: ControlPanelState) => ({ + choices: columnChoices(state.datasource), + }), + validators: [validateNonEmpty], +}; + +const dndAllColumns = { + ...dndEntity, + description: t('Columns to display'), +}; + +const columnsConfig = isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) + ? dndAllColumns + : allColumns; + const config: ControlPanelConfig = { controlPanelSections: [ sections.legacyRegularTime, @@ -43,27 +64,17 @@ const config: ControlPanelConfig = { { name: 'all_columns_x', config: { - type: 'SelectControl', + ...columnsConfig, label: 'X Axis', - default: null, - description: t('Columns to display'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), - validators: [validateNonEmpty], }, }, + ], + [ { name: 'all_columns_y', config: { - type: 'SelectControl', + ...columnsConfig, label: 'Y Axis', - default: null, - description: t('Columns to display'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), - validators: [validateNonEmpty], }, }, ], diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts index 37c9cc9aaec..d2414b9c978 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-histogram/src/controlPanel.ts @@ -16,13 +16,37 @@ * specific language governing permissions and limitations * under the License. */ -import { t, validateNonEmpty } from '@superset-ui/core'; +import { FeatureFlag, isFeatureEnabled, t, validateNonEmpty } from '@superset-ui/core'; import { - ControlPanelConfig, columnChoices, + ControlPanelConfig, + ControlPanelState, formatSelectOptions, sections, } from '@superset-ui/chart-controls'; +import { dndColumnsControl } from '@superset-ui/chart-controls/lib/shared-controls/dndControls'; + +const allColumns = { + type: 'SelectControl', + label: t('Columns'), + default: null, + description: t('Select the numeric columns to draw the histogram'), + mapStateToProps: (state: ControlPanelState) => ({ + choices: columnChoices(state.datasource), + }), + multi: true, + validators: [validateNonEmpty], +}; + +const dndAllColumns = { + ...dndColumnsControl, + description: t('Select the numeric columns to draw the histogram'), + validators: [validateNonEmpty], +}; + +const columnsConfig = isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) + ? dndAllColumns + : allColumns; const config: ControlPanelConfig = { controlPanelSections: [ @@ -34,17 +58,7 @@ const config: ControlPanelConfig = { [ { name: 'all_columns_x', - config: { - type: 'SelectControl', - label: t('Columns'), - default: null, - description: t('Select the numeric columns to draw the histogram'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), - multi: true, - validators: [validateNonEmpty], - }, + config: columnsConfig, }, ], ['adhoc_filters'], diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts index 9a25c58ac14..c5b92e26843 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-plugin-chart-map-box/src/controlPanel.ts @@ -16,13 +16,27 @@ * specific language governing permissions and limitations * under the License. */ -import { t } from '@superset-ui/core'; +import { FeatureFlag, isFeatureEnabled, t } from '@superset-ui/core'; import { columnChoices, ControlPanelConfig, + ControlPanelState, formatSelectOptions, sections, } from '@superset-ui/chart-controls'; +import { dndEntity } from '@superset-ui/chart-controls/lib/shared-controls/dndControls'; + +const allColumns = { + type: 'SelectControl', + default: null, + mapStateToProps: (state: ControlPanelState) => ({ + choices: columnChoices(state.datasource), + }), +}; + +const columnsConfig = isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) + ? dndEntity + : allColumns; const config: ControlPanelConfig = { controlPanelSections: [ @@ -35,25 +49,19 @@ const config: ControlPanelConfig = { { name: 'all_columns_x', config: { - type: 'SelectControl', + ...columnsConfig, label: t('Longitude'), - default: null, description: t('Column containing longitude data'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), }, }, + ], + [ { name: 'all_columns_y', config: { - type: 'SelectControl', + ...columnsConfig, label: t('Latitude'), - default: null, description: t('Column containing latitude data'), - mapStateToProps: state => ({ - choices: columnChoices(state.datasource), - }), }, }, ], diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts index 5061038e3b9..71da011aedd 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/legacy-preset-chart-nvd3/src/Bubble/controlPanel.ts @@ -43,8 +43,8 @@ const config: ControlPanelConfig = { label: t('Query'), expanded: true, controlSetRows: [ - [], - ['series', 'entity'], + ['series'], + ['entity'], ['x'], ['y'], ['adhoc_filters'], diff --git a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-table/src/controlPanel.tsx b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-table/src/controlPanel.tsx index d8596ca3185..1a2b6d09f17 100644 --- a/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-table/src/controlPanel.tsx +++ b/superset-frontend/temporary_superset_ui/superset-ui/plugins/plugin-chart-table/src/controlPanel.tsx @@ -19,25 +19,27 @@ */ import React from 'react'; import { - t, addLocaleData, - smartDateFormatter, - QueryMode, - QueryFormColumn, ChartDataResponseResult, - isFeatureEnabled, + ensureIsArray, FeatureFlag, + isFeatureEnabled, + QueryFormColumn, + QueryMode, + smartDateFormatter, + t, } from '@superset-ui/core'; import { - D3_TIME_FORMAT_OPTIONS, - ControlConfig, ColumnOption, - ControlStateMapping, + ControlConfig, ControlPanelConfig, ControlPanelsContainerProps, - sharedControls, - sections, + ControlStateMapping, + D3_TIME_FORMAT_OPTIONS, + ExtraControlProps, QueryModeLabel, + sections, + sharedControls, } from '@superset-ui/chart-controls'; import i18n from './i18n'; @@ -59,7 +61,8 @@ function getQueryMode(controls: ControlStateMapping): QueryMode { * Visibility check */ function isQueryMode(mode: QueryMode) { - return ({ controls }: ControlPanelsContainerProps) => getQueryMode(controls) === mode; + return ({ controls }: Pick) => + getQueryMode(controls) === mode; } const isAggMode = isQueryMode(QueryMode.aggregate); @@ -95,6 +98,27 @@ const all_columns: typeof sharedControls.groupby = { visibility: isRawMode, }; +const dnd_all_columns: typeof sharedControls.groupby = { + type: 'DndColumnSelect', + label: t('Columns'), + description: t('Columns to display'), + default: [], + mapStateToProps({ datasource, controls }, controlState) { + const newState: ExtraControlProps = {}; + if (datasource) { + const options = datasource.columns; + newState.options = Object.fromEntries(options.map(option => [option.column_name, option])); + } + newState.queryMode = getQueryMode(controls); + newState.externalValidationErrors = + isRawMode({ controls }) && ensureIsArray(controlState.value).length === 0 + ? [t('must have a value')] + : []; + return newState; + }, + visibility: isRawMode, +}; + const percent_metrics: typeof sharedControls.metrics = { type: 'MetricsControl', label: t('Percentage metrics'), @@ -149,7 +173,9 @@ const config: ControlPanelConfig = { }, { name: 'all_columns', - config: all_columns, + config: isFeatureEnabled(FeatureFlag.ENABLE_EXPLORE_DRAG_AND_DROP) + ? dnd_all_columns + : all_columns, }, ], [