| /* eslint-disable camelcase */ |
| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| import { |
| GenericDataType, |
| QueryColumn, |
| t, |
| validateNonEmpty, |
| } from '@superset-ui/core'; |
| import { |
| ExtraControlProps, |
| SharedControlConfig, |
| Dataset, |
| Metric, |
| isDataset, |
| } from '../types'; |
| import { DATASET_TIME_COLUMN_OPTION, TIME_FILTER_LABELS } from '../constants'; |
| import { |
| QUERY_TIME_COLUMN_OPTION, |
| defineSavedMetrics, |
| ColumnOption, |
| ColumnMeta, |
| FilterOption, |
| temporalColumnMixin, |
| datePickerInAdhocFilterMixin, |
| xAxisMixin, |
| } from '..'; |
| |
| type Control = { |
| savedMetrics?: Metric[] | null; |
| default?: unknown; |
| }; |
| |
| /* |
| * Note: Previous to the commit that introduced this comment, the shared controls module |
| * would check feature flags at module execution time and expose a different control |
| * configuration (component + props) depending on the status of drag-and-drop feature |
| * flags. This commit combines those configs, merging the required props for both the |
| * drag-and-drop and non-drag-and-drop components, and renders a wrapper component that |
| * checks feature flags at component render time to avoid race conditions between when |
| * feature flags are set and when they're checked. |
| */ |
| |
| function filterOptions( |
| options: (ColumnMeta | QueryColumn)[], |
| allowedDataTypes?: GenericDataType[], |
| ) { |
| if (!allowedDataTypes) { |
| return options; |
| } |
| return options.filter( |
| o => |
| o.type_generic !== undefined && allowedDataTypes.includes(o.type_generic), |
| ); |
| } |
| |
| export const dndGroupByControl: SharedControlConfig< |
| 'DndColumnSelect' | 'SelectControl', |
| ColumnMeta |
| > = { |
| type: 'DndColumnSelect', |
| label: t('Dimensions'), |
| multi: true, |
| freeForm: true, |
| clearable: true, |
| default: [], |
| includeTime: false, |
| description: t( |
| 'Dimensions contain qualitative values such as names, dates, or geographical data. ' + |
| 'Use dimensions to categorize, segment, and reveal the details in your data. ' + |
| 'Dimensions affect the level of detail in the view.', |
| ), |
| optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />, |
| valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />, |
| valueKey: 'column_name', |
| allowAll: true, |
| filterOption: ({ data: opt }: FilterOption<ColumnMeta>, text: string) => |
| opt.column_name?.toLowerCase().includes(text.toLowerCase()) || |
| opt.verbose_name?.toLowerCase().includes(text.toLowerCase()) || |
| false, |
| promptTextCreator: (label: unknown) => label, |
| mapStateToProps(state, controlState) { |
| const newState: ExtraControlProps = {}; |
| const { datasource } = state; |
| if (datasource?.columns[0]?.hasOwnProperty('groupby')) { |
| const options = filterOptions( |
| (datasource as Dataset).columns.filter(c => c.groupby), |
| controlState?.allowedDataTypes, |
| ); |
| if (controlState?.includeTime) { |
| options.unshift(DATASET_TIME_COLUMN_OPTION); |
| } |
| newState.options = options; |
| newState.savedMetrics = (datasource as Dataset).metrics || []; |
| } else { |
| const options = filterOptions( |
| (datasource?.columns as QueryColumn[]) || [], |
| controlState?.allowedDataTypes, |
| ); |
| if (controlState?.includeTime) { |
| options.unshift(QUERY_TIME_COLUMN_OPTION); |
| } |
| newState.options = options; |
| } |
| return newState; |
| }, |
| commaChoosesOption: false, |
| }; |
| |
| export const dndColumnsControl: typeof dndGroupByControl = { |
| ...dndGroupByControl, |
| label: t('Columns'), |
| description: t('Add dataset columns here to group the pivot table columns.'), |
| }; |
| |
| export const dndSeriesControl: typeof dndGroupByControl = { |
| ...dndGroupByControl, |
| label: t('Dimension'), |
| multi: false, |
| default: null, |
| description: t( |
| 'Defines the grouping of entities. ' + |
| 'Each series is represented by a specific color in the chart.', |
| ), |
| }; |
| |
| export const dndEntityControl: typeof dndGroupByControl = { |
| ...dndGroupByControl, |
| label: t('Entity'), |
| default: null, |
| multi: false, |
| validators: [validateNonEmpty], |
| description: t('This defines the element to be plotted on the chart'), |
| }; |
| |
| export const dndAdhocFilterControl: SharedControlConfig< |
| 'DndFilterSelect' | 'AdhocFilterControl' |
| > = { |
| type: 'DndFilterSelect', |
| label: t('Filters'), |
| default: [], |
| description: '', |
| mapStateToProps: ({ datasource, form_data }) => ({ |
| columns: isDataset(datasource) |
| ? datasource.columns.filter(c => c.filterable) |
| : datasource?.columns || [], |
| savedMetrics: defineSavedMetrics(datasource), |
| // current active adhoc metrics |
| selectedMetrics: |
| form_data.metrics || (form_data.metric ? [form_data.metric] : []), |
| datasource, |
| }), |
| provideFormDataToProps: true, |
| ...datePickerInAdhocFilterMixin, |
| }; |
| |
| export const dndAdhocMetricsControl: SharedControlConfig< |
| 'DndMetricSelect' | 'MetricsControl' |
| > = { |
| type: 'DndMetricSelect', |
| multi: true, |
| label: t('Metrics'), |
| validators: [validateNonEmpty], |
| mapStateToProps: ({ datasource }) => ({ |
| columns: datasource?.columns || [], |
| savedMetrics: defineSavedMetrics(datasource), |
| datasource, |
| datasourceType: datasource?.type, |
| }), |
| description: t( |
| 'Select one or many metrics to display. ' + |
| 'You can use an aggregation function on a column ' + |
| 'or write custom SQL to create a metric.', |
| ), |
| }; |
| |
| export const dndAdhocMetricControl: typeof dndAdhocMetricsControl = { |
| ...dndAdhocMetricsControl, |
| multi: false, |
| label: t('Metric'), |
| description: t( |
| 'Select a metric to display. ' + |
| 'You can use an aggregation function on a column ' + |
| 'or write custom SQL to create a metric.', |
| ), |
| }; |
| |
| export const dndTooltipColumnsControl: typeof dndColumnsControl = { |
| ...dndColumnsControl, |
| label: t('Tooltip (columns)'), |
| description: t('Columns to show in the tooltip.'), |
| }; |
| |
| export const dndTooltipMetricsControl: typeof dndAdhocMetricsControl = { |
| ...dndAdhocMetricsControl, |
| label: t('Tooltip (metrics)'), |
| description: t('Metrics to show in the tooltip.'), |
| validators: [], |
| }; |
| |
| export const dndAdhocMetricControl2: typeof dndAdhocMetricControl = { |
| ...dndAdhocMetricControl, |
| label: t('Right Axis Metric'), |
| clearable: true, |
| description: t('Select a metric to display on the right axis'), |
| }; |
| |
| export const dndSortByControl: SharedControlConfig< |
| 'DndMetricSelect' | 'MetricsControl' |
| > = { |
| type: 'DndMetricSelect', |
| label: t('Sort query by'), |
| default: null, |
| description: t( |
| 'Orders the query result that generates the source data for this chart. ' + |
| 'If a series or row limit is reached, this determines what data are truncated. ' + |
| 'If undefined, defaults to the first metric (where appropriate).', |
| ), |
| mapStateToProps: ({ datasource }) => ({ |
| columns: datasource?.columns || [], |
| savedMetrics: defineSavedMetrics(datasource), |
| datasource, |
| datasourceType: datasource?.type, |
| }), |
| }; |
| |
| export const dndSizeControl: typeof dndAdhocMetricControl = { |
| ...dndAdhocMetricControl, |
| label: t('Bubble Size'), |
| description: t('Metric used to calculate bubble size'), |
| default: null, |
| }; |
| |
| export const dndXControl: typeof dndAdhocMetricControl = { |
| ...dndAdhocMetricControl, |
| label: t('X Axis'), |
| description: t( |
| "The dataset column/metric that returns the values on your chart's x-axis.", |
| ), |
| default: null, |
| }; |
| |
| export const dndYControl: typeof dndAdhocMetricControl = { |
| ...dndAdhocMetricControl, |
| label: t('Y Axis'), |
| description: t( |
| "The dataset column/metric that returns the values on your chart's y-axis.", |
| ), |
| default: null, |
| }; |
| |
| export const dndSecondaryMetricControl: typeof dndAdhocMetricControl = { |
| ...dndAdhocMetricControl, |
| label: t('Color Metric'), |
| default: null, |
| validators: [], |
| description: t('A metric to use for color'), |
| }; |
| |
| export const dndGranularitySqlaControl: typeof dndSeriesControl = { |
| ...dndSeriesControl, |
| ...temporalColumnMixin, |
| label: TIME_FILTER_LABELS.granularity_sqla, |
| description: t( |
| 'The time column for the visualization. Note that you ' + |
| 'can define arbitrary expression that return a DATETIME ' + |
| 'column in the table. Also note that the ' + |
| 'filter below is applied against this column or ' + |
| 'expression', |
| ), |
| default: (c: Control) => c.default, |
| clearable: false, |
| canDelete: false, |
| ghostButtonText: t('Drop a temporal column here or click'), |
| optionRenderer: (c: ColumnMeta) => <ColumnOption showType column={c} />, |
| valueRenderer: (c: ColumnMeta) => <ColumnOption column={c} />, |
| valueKey: 'column_name', |
| }; |
| |
| export const dndXAxisControl: typeof dndGroupByControl = { |
| ...dndGroupByControl, |
| ...xAxisMixin, |
| }; |