| /** |
| * 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 { ensureIsArray, t } from '@superset-ui/core'; |
| import { cloneDeep } from 'lodash'; |
| import { |
| ControlPanelsContainerProps, |
| ControlPanelConfig, |
| ControlPanelSectionConfig, |
| ControlSetRow, |
| ControlSubSectionHeader, |
| CustomControlItem, |
| getStandardizedControls, |
| sections, |
| sharedControls, |
| DEFAULT_SORT_SERIES_DATA, |
| SORT_SERIES_CHOICES, |
| } from '@superset-ui/chart-controls'; |
| |
| import { DEFAULT_FORM_DATA } from './types'; |
| import { EchartsTimeseriesSeriesType } from '../Timeseries/types'; |
| import { |
| legendSection, |
| minorTicks, |
| richTooltipSection, |
| truncateXAxis, |
| xAxisBounds, |
| xAxisLabelRotation, |
| xAxisLabelInterval, |
| forceMaxInterval, |
| } from '../controls'; |
| |
| const { |
| area, |
| logAxis, |
| markerEnabled, |
| markerSize, |
| minorSplitLine, |
| opacity, |
| orderDesc, |
| rowLimit, |
| seriesType, |
| showValues, |
| stack, |
| truncateYAxis, |
| yAxisBounds, |
| yAxisIndex, |
| } = DEFAULT_FORM_DATA; |
| |
| function createQuerySection( |
| label: string, |
| controlSuffix: string, |
| ): ControlPanelSectionConfig { |
| return { |
| label, |
| expanded: true, |
| controlSetRows: [ |
| [ |
| { |
| name: `metrics${controlSuffix}`, |
| config: sharedControls.metrics, |
| }, |
| ], |
| [ |
| { |
| name: `groupby${controlSuffix}`, |
| config: sharedControls.groupby, |
| }, |
| ], |
| [ |
| { |
| name: `adhoc_filters${controlSuffix}`, |
| config: sharedControls.adhoc_filters, |
| }, |
| ], |
| [ |
| { |
| name: `limit${controlSuffix}`, |
| config: sharedControls.limit, |
| }, |
| ], |
| [ |
| { |
| name: `timeseries_limit_metric${controlSuffix}`, |
| config: sharedControls.timeseries_limit_metric, |
| }, |
| ], |
| [ |
| { |
| name: `order_desc${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Sort Descending'), |
| default: orderDesc, |
| description: t('Whether to sort descending or ascending'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `row_limit${controlSuffix}`, |
| config: { |
| ...sharedControls.row_limit, |
| default: rowLimit, |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `truncate_metric${controlSuffix}`, |
| config: { |
| ...sharedControls.truncate_metric, |
| default: sharedControls.truncate_metric.default, |
| }, |
| }, |
| ], |
| ], |
| }; |
| } |
| |
| function createCustomizeSection( |
| label: string, |
| controlSuffix: string, |
| ): ControlSetRow[] { |
| return [ |
| [<ControlSubSectionHeader>{label}</ControlSubSectionHeader>], |
| [ |
| { |
| name: `seriesType${controlSuffix}`, |
| config: { |
| type: 'SelectControl', |
| label: t('Series type'), |
| renderTrigger: true, |
| default: seriesType, |
| choices: [ |
| [EchartsTimeseriesSeriesType.Line, t('Line')], |
| [EchartsTimeseriesSeriesType.Scatter, t('Scatter')], |
| [EchartsTimeseriesSeriesType.Smooth, t('Smooth Line')], |
| [EchartsTimeseriesSeriesType.Bar, t('Bar')], |
| [EchartsTimeseriesSeriesType.Start, t('Step - start')], |
| [EchartsTimeseriesSeriesType.Middle, t('Step - middle')], |
| [EchartsTimeseriesSeriesType.End, t('Step - end')], |
| ], |
| description: t('Series chart type (line, bar etc)'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `stack${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Stack series'), |
| renderTrigger: true, |
| default: stack, |
| description: t('Stack series on top of each other'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `area${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Area chart'), |
| renderTrigger: true, |
| default: area, |
| description: t( |
| 'Draw area under curves. Only applicable for line types.', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `show_value${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Show Values'), |
| renderTrigger: true, |
| default: showValues, |
| description: t( |
| 'Whether to display the numerical values within the cells', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `only_total${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Only Total'), |
| default: true, |
| renderTrigger: true, |
| description: t( |
| 'Only show the total value on the stacked chart, and not show on the selected category', |
| ), |
| visibility: ({ controls }: ControlPanelsContainerProps) => |
| Boolean(controls?.show_value?.value) && |
| Boolean(controls?.stack?.value), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `opacity${controlSuffix}`, |
| config: { |
| type: 'SliderControl', |
| label: t('Opacity'), |
| renderTrigger: true, |
| min: 0, |
| max: 1, |
| step: 0.1, |
| default: opacity, |
| description: t('Opacity of area chart.'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `markerEnabled${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Marker'), |
| renderTrigger: true, |
| default: markerEnabled, |
| description: t( |
| 'Draw a marker on data points. Only applicable for line types.', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `markerSize${controlSuffix}`, |
| config: { |
| type: 'SliderControl', |
| label: t('Marker size'), |
| renderTrigger: true, |
| min: 0, |
| max: 100, |
| default: markerSize, |
| description: t( |
| 'Size of marker. Also applies to forecast observations.', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `yAxisIndex${controlSuffix}`, |
| config: { |
| type: 'SelectControl', |
| label: t('Y Axis'), |
| choices: [ |
| [0, t('Primary')], |
| [1, t('Secondary')], |
| ], |
| default: yAxisIndex, |
| clearable: false, |
| renderTrigger: true, |
| description: t('Primary or secondary y-axis'), |
| }, |
| }, |
| ], |
| [<ControlSubSectionHeader>{t('Series Order')}</ControlSubSectionHeader>], |
| [ |
| { |
| name: `sort_series_type${controlSuffix}`, |
| config: { |
| type: 'SelectControl', |
| freeForm: false, |
| label: t('Sort Series By'), |
| choices: SORT_SERIES_CHOICES, |
| default: DEFAULT_SORT_SERIES_DATA.sort_series_type, |
| renderTrigger: true, |
| description: t( |
| 'Based on what should series be ordered on the chart and legend', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `sort_series_ascending${controlSuffix}`, |
| config: { |
| type: 'CheckboxControl', |
| label: t('Sort Series Ascending'), |
| default: DEFAULT_SORT_SERIES_DATA.sort_series_ascending, |
| renderTrigger: true, |
| description: t('Sort series in ascending order'), |
| }, |
| }, |
| ], |
| ]; |
| } |
| |
| function createAdvancedAnalyticsSection( |
| label: string, |
| controlSuffix: string, |
| ): ControlPanelSectionConfig { |
| const aaWithSuffix = cloneDeep(sections.advancedAnalyticsControls); |
| aaWithSuffix.label = label; |
| if (!controlSuffix) { |
| return aaWithSuffix; |
| } |
| aaWithSuffix.controlSetRows.forEach(row => |
| row.forEach((control: CustomControlItem) => { |
| if (control?.name) { |
| // eslint-disable-next-line no-param-reassign |
| control.name = `${control.name}${controlSuffix}`; |
| } |
| }), |
| ); |
| return aaWithSuffix; |
| } |
| |
| const config: ControlPanelConfig = { |
| controlPanelSections: [ |
| { |
| label: t('Shared query fields'), |
| expanded: true, |
| controlSetRows: [['x_axis'], ['time_grain_sqla']], |
| }, |
| createQuerySection(t('Query A'), ''), |
| createAdvancedAnalyticsSection(t('Advanced analytics Query A'), ''), |
| createQuerySection(t('Query B'), '_b'), |
| createAdvancedAnalyticsSection(t('Advanced analytics Query B'), '_b'), |
| sections.annotationsAndLayersControls, |
| sections.titleControls, |
| { |
| label: t('Chart Options'), |
| expanded: true, |
| controlSetRows: [ |
| ['color_scheme'], |
| ['time_shift_color'], |
| ...createCustomizeSection(t('Query A'), ''), |
| ...createCustomizeSection(t('Query B'), 'B'), |
| ['zoomable'], |
| [minorTicks], |
| ...legendSection, |
| [<ControlSubSectionHeader>{t('X Axis')}</ControlSubSectionHeader>], |
| ['x_axis_time_format'], |
| [xAxisLabelRotation], |
| [xAxisLabelInterval], |
| [forceMaxInterval], |
| [<ControlSubSectionHeader>{t('Tooltip')}</ControlSubSectionHeader>], |
| [ |
| { |
| name: 'show_query_identifiers', |
| config: { |
| type: 'CheckboxControl', |
| label: t('Show query identifiers'), |
| description: t( |
| 'Add Query A and Query B identifiers to tooltips to help differentiate series', |
| ), |
| default: false, |
| renderTrigger: true, |
| }, |
| }, |
| ], |
| ...richTooltipSection.slice(1), // Skip the tooltip header since we added our own |
| // eslint-disable-next-line react/jsx-key |
| [<ControlSubSectionHeader>{t('Y Axis')}</ControlSubSectionHeader>], |
| [ |
| { |
| name: 'minorSplitLine', |
| config: { |
| type: 'CheckboxControl', |
| label: t('Minor Split Line'), |
| renderTrigger: true, |
| default: minorSplitLine, |
| description: t('Draw split lines for minor y-axis ticks'), |
| }, |
| }, |
| ], |
| [truncateXAxis], |
| [xAxisBounds], |
| [ |
| { |
| name: 'truncateYAxis', |
| config: { |
| type: 'CheckboxControl', |
| label: t('Truncate Y Axis'), |
| default: truncateYAxis, |
| renderTrigger: true, |
| description: t( |
| 'Truncate Y Axis. Can be overridden by specifying a min or max bound.', |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: 'y_axis_bounds', |
| config: { |
| type: 'BoundsControl', |
| label: t('Primary y-axis Bounds'), |
| renderTrigger: true, |
| default: yAxisBounds, |
| description: t( |
| 'Bounds for the primary Y-axis. When left empty, the bounds are ' + |
| 'dynamically defined based on the min/max of the data. Note that ' + |
| "this feature will only expand the axis range. It won't " + |
| "narrow the data's extent.", |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `y_axis_format`, |
| config: { |
| ...sharedControls.y_axis_format, |
| label: t('Primary y-axis format'), |
| }, |
| }, |
| ], |
| ['currency_format'], |
| [ |
| { |
| name: 'logAxis', |
| config: { |
| type: 'CheckboxControl', |
| label: t('Logarithmic y-axis'), |
| renderTrigger: true, |
| default: logAxis, |
| description: t('Logarithmic scale on primary y-axis'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: 'y_axis_bounds_secondary', |
| config: { |
| type: 'BoundsControl', |
| label: t('Secondary y-axis Bounds'), |
| renderTrigger: true, |
| default: yAxisBounds, |
| description: t( |
| `Bounds for the secondary Y-axis. Only works when Independent Y-axis |
| bounds are enabled. When left empty, the bounds are dynamically defined |
| based on the min/max of the data. Note that this feature will only expand |
| the axis range. It won't narrow the data's extent.`, |
| ), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: `y_axis_format_secondary`, |
| config: { |
| ...sharedControls.y_axis_format, |
| label: t('Secondary y-axis format'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: 'currency_format_secondary', |
| config: { |
| ...sharedControls.currency_format, |
| label: t('Secondary currency format'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: 'yAxisTitleSecondary', |
| config: { |
| type: 'TextControl', |
| label: t('Secondary y-axis title'), |
| renderTrigger: true, |
| default: '', |
| description: t('Logarithmic y-axis'), |
| }, |
| }, |
| ], |
| [ |
| { |
| name: 'logAxisSecondary', |
| config: { |
| type: 'CheckboxControl', |
| label: t('Logarithmic y-axis'), |
| renderTrigger: true, |
| default: logAxis, |
| description: t('Logarithmic scale on secondary y-axis'), |
| }, |
| }, |
| ], |
| ], |
| }, |
| ], |
| formDataOverrides: formData => { |
| const groupby = getStandardizedControls().controls.columns.filter( |
| col => !ensureIsArray(formData.groupby_b).includes(col), |
| ); |
| getStandardizedControls().controls.columns = |
| getStandardizedControls().controls.columns.filter( |
| col => !groupby.includes(col), |
| ); |
| |
| const metrics = getStandardizedControls().controls.metrics.filter( |
| metric => !ensureIsArray(formData.metrics_b).includes(metric), |
| ); |
| getStandardizedControls().controls.metrics = |
| getStandardizedControls().controls.metrics.filter( |
| col => !metrics.includes(col), |
| ); |
| |
| return { |
| ...formData, |
| metrics, |
| groupby, |
| }; |
| }, |
| }; |
| |
| export default config; |