/** * 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 { ControlPanelConfig, D3_TIME_FORMAT_OPTIONS, Dataset, getStandardizedControls, sharedControls, } from '@superset-ui/chart-controls'; import { ensureIsArray, isAdhocColumn, isPhysicalColumn, QueryFormMetric, SMART_DATE_ID, t, validateNonEmpty, } from '@superset-ui/core'; import { MetricsLayoutEnum } from '../types'; const config: ControlPanelConfig = { controlPanelSections: [ { label: t('Query'), expanded: true, controlSetRows: [ [ { name: 'groupbyColumns', config: { ...sharedControls.groupby, label: t('Columns'), description: t('Columns to group by on the columns'), }, }, ], [ { name: 'groupbyRows', config: { ...sharedControls.groupby, label: t('Rows'), description: t('Columns to group by on the rows'), }, }, ], [ { name: 'time_grain_sqla', config: { ...sharedControls.time_grain_sqla, visibility: ({ controls }) => { const dttmLookup = Object.fromEntries( ensureIsArray(controls?.groupbyColumns?.options).map( option => [option.column_name, option.is_dttm], ), ); return [ ...ensureIsArray(controls?.groupbyColumns.value), ...ensureIsArray(controls?.groupbyRows.value), ] .map(selection => { if (isAdhocColumn(selection)) { return true; } if (isPhysicalColumn(selection)) { return !!dttmLookup[selection]; } return false; }) .some(Boolean); }, }, }, 'temporal_columns_lookup', ], [ { name: 'metrics', config: { ...sharedControls.metrics, validators: [validateNonEmpty], rerender: ['conditional_formatting'], }, }, ], [ { name: 'metricsLayout', config: { type: 'RadioButtonControl', renderTrigger: true, label: t('Apply metrics on'), default: MetricsLayoutEnum.COLUMNS, options: [ [MetricsLayoutEnum.COLUMNS, t('Columns')], [MetricsLayoutEnum.ROWS, t('Rows')], ], description: t( 'Use metrics as a top level group for columns or for rows', ), }, }, ], ['adhoc_filters'], ['series_limit'], [ { name: 'row_limit', config: { ...sharedControls.row_limit, label: t('Cell limit'), description: t('Limits the number of cells that get retrieved.'), }, }, ], // TODO(kgabryje): add series_columns control after control panel is redesigned to avoid clutter [ { name: 'series_limit_metric', config: { ...sharedControls.series_limit_metric, description: t( 'Metric used to define how the top series are sorted if a series or cell limit is present. ' + 'If undefined reverts to the first metric (where appropriate).', ), }, }, ], [ { name: 'order_desc', config: { type: 'CheckboxControl', label: t('Sort Descending'), default: true, description: t('Whether to sort descending or ascending'), }, }, ], ], }, { label: t('Options'), expanded: true, tabOverride: 'data', controlSetRows: [ [ { name: 'aggregateFunction', config: { type: 'SelectControl', label: t('Aggregation function'), clearable: false, choices: [ ['Count', t('Count')], ['Count Unique Values', t('Count Unique Values')], ['List Unique Values', t('List Unique Values')], ['Sum', t('Sum')], ['Average', t('Average')], ['Median', t('Median')], ['Sample Variance', t('Sample Variance')], ['Sample Standard Deviation', t('Sample Standard Deviation')], ['Minimum', t('Minimum')], ['Maximum', t('Maximum')], ['First', t('First')], ['Last', t('Last')], ['Sum as Fraction of Total', t('Sum as Fraction of Total')], ['Sum as Fraction of Rows', t('Sum as Fraction of Rows')], ['Sum as Fraction of Columns', t('Sum as Fraction of Columns')], ['Count as Fraction of Total', t('Count as Fraction of Total')], ['Count as Fraction of Rows', t('Count as Fraction of Rows')], [ 'Count as Fraction of Columns', t('Count as Fraction of Columns'), ], ], default: 'Sum', description: t( 'Aggregate function to apply when pivoting and computing the total rows and columns', ), renderTrigger: true, }, }, ], [ { name: 'rowTotals', config: { type: 'CheckboxControl', label: t('Show rows total'), default: false, renderTrigger: true, description: t('Display row level total'), }, }, ], [ { name: 'rowSubTotals', config: { type: 'CheckboxControl', label: t('Show rows subtotal'), default: false, renderTrigger: true, description: t('Display row level subtotal'), }, }, ], [ { name: 'colTotals', config: { type: 'CheckboxControl', label: t('Show columns total'), default: false, renderTrigger: true, description: t('Display column level total'), }, }, ], [ { name: 'colSubTotals', config: { type: 'CheckboxControl', label: t('Show columns subtotal'), default: false, renderTrigger: true, description: t('Display column level subtotal'), }, }, ], [ { name: 'transposePivot', config: { type: 'CheckboxControl', label: t('Transpose pivot'), default: false, description: t('Swap rows and columns'), renderTrigger: true, }, }, ], [ { name: 'combineMetric', config: { type: 'CheckboxControl', label: t('Combine metrics'), default: false, description: t( 'Display metrics side by side within each column, as ' + 'opposed to each column being displayed side by side for each metric.', ), renderTrigger: true, }, }, ], ], }, { label: t('Options'), expanded: true, controlSetRows: [ [ { name: 'valueFormat', config: { ...sharedControls.y_axis_format, label: t('Value format'), }, }, ], ['currency_format'], [ { name: 'date_format', config: { type: 'SelectControl', freeForm: true, label: t('Date format'), default: SMART_DATE_ID, renderTrigger: true, choices: D3_TIME_FORMAT_OPTIONS, description: t('D3 time format for datetime columns'), }, }, ], [ { name: 'rowOrder', config: { type: 'SelectControl', label: t('Sort rows by'), default: 'key_a_to_z', choices: [ // [value, label] ['key_a_to_z', t('key a-z')], ['key_z_to_a', t('key z-a')], ['value_a_to_z', t('value ascending')], ['value_z_to_a', t('value descending')], ], renderTrigger: true, description: ( <>
{t('Change order of rows.')}
{t('Available sorting modes:')}
), }, }, ], [ { name: 'colOrder', config: { type: 'SelectControl', label: t('Sort columns by'), default: 'key_a_to_z', choices: [ // [value, label] ['key_a_to_z', t('key a-z')], ['key_z_to_a', t('key z-a')], ['value_a_to_z', t('value ascending')], ['value_z_to_a', t('value descending')], ], renderTrigger: true, description: ( <>
{t('Change order of columns.')}
{t('Available sorting modes:')}
), }, }, ], [ { name: 'rowSubtotalPosition', config: { type: 'SelectControl', label: t('Rows subtotal position'), default: false, choices: [ // [value, label] [true, t('Top')], [false, t('Bottom')], ], renderTrigger: true, description: t('Position of row level subtotal'), }, }, ], [ { name: 'colSubtotalPosition', config: { type: 'SelectControl', label: t('Columns subtotal position'), default: false, choices: [ // [value, label] [true, t('Left')], [false, t('Right')], ], renderTrigger: true, description: t('Position of column level subtotal'), }, }, ], [ { name: 'conditional_formatting', config: { type: 'ConditionalFormattingControl', renderTrigger: true, label: t('Conditional formatting'), description: t('Apply conditional color formatting to metrics'), mapStateToProps(explore, _, chart) { const values = (explore?.controls?.metrics?.value as QueryFormMetric[]) ?? []; const verboseMap = explore?.datasource?.hasOwnProperty( 'verbose_map', ) ? (explore?.datasource as Dataset)?.verbose_map : (explore?.datasource?.columns ?? {}); const chartStatus = chart?.chartStatus; const metricColumn = values.map(value => { if (typeof value === 'string') { return { value, label: Array.isArray(verboseMap) ? value : verboseMap[value], }; } return { value: value.label, label: value.label }; }); return { removeIrrelevantConditions: chartStatus === 'success', columnOptions: metricColumn, verboseMap, }; }, }, }, ], [ { name: 'allow_render_html', config: { type: 'CheckboxControl', label: t('Render columns in HTML format'), renderTrigger: true, default: true, description: t( 'Renders table cells as HTML when applicable. For example, HTML tags will be rendered as hyperlinks.', ), }, }, ], ], }, ], formDataOverrides: formData => { const groupbyColumns = getStandardizedControls().controls.columns.filter( col => !ensureIsArray(formData.groupbyRows).includes(col), ); getStandardizedControls().controls.columns = getStandardizedControls().controls.columns.filter( col => !groupbyColumns.includes(col), ); return { ...formData, metrics: getStandardizedControls().popAllMetrics(), groupbyColumns, }; }, }; export default config;