Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion superset-frontend/src/explore/components/Control.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import React, { ReactNode } from 'react';
import { ControlType } from '@superset-ui/chart-controls';
import { JsonValue, QueryFormData } from '@superset-ui/core';
import { ExploreActions } from '../actions/exploreActions';
import { ExploreActions } from 'src/explore/actions/exploreActions';
import controlMap from './controls';

import './Control.less';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,22 @@ import Collapse from 'src/common/components/Collapse';
import { PluginContext } from 'src/components/DynamicPlugins';
import Loading from 'src/components/Loading';

import { sectionsToRender } from 'src/explore/controlUtils';
import { getSectionsToRender } from 'src/explore/controlUtils';
import {
ExploreActions,
exploreActions,
} from 'src/explore/actions/exploreActions';
import { ExplorePageState } from 'src/explore/reducers/getInitialState';
import { ChartState } from 'src/explore/types';

import ControlRow from './ControlRow';
import Control from './Control';

export type ControlPanelsContainerProps = {
actions: ExploreActions;
datasource_type: DatasourceType;
exploreState: Record<string, any>;
exploreState: ExplorePageState['explore'];
chart: ChartState;
controls: Record<string, ControlState>;
form_data: QueryFormData;
isDatasourceMetaLoading: boolean;
Expand Down Expand Up @@ -100,7 +102,7 @@ const ControlPanelsTabs = styled(Tabs)`
}
`;

class ControlPanelsContainer extends React.Component<ControlPanelsContainerProps> {
export class ControlPanelsContainer extends React.Component<ControlPanelsContainerProps> {
// trigger updates to the component when async plugins load
static contextType = PluginContext;

Expand All @@ -111,7 +113,7 @@ class ControlPanelsContainer extends React.Component<ControlPanelsContainerProps
}

sectionsToRender(): ExpandedControlPanelSectionConfig[] {
return sectionsToRender(
return getSectionsToRender(
this.props.form_data.viz_type,
this.props.datasource_type,
);
Expand Down Expand Up @@ -314,8 +316,6 @@ class ControlPanelsContainer extends React.Component<ControlPanelsContainerProps
}
}

export { ControlPanelsContainer };

export default connect(
function mapStateToProps(state: ExplorePageState) {
const { explore, charts } = state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,17 @@
*/
import React from 'react';
import { t } from '@superset-ui/core';
import { ControlPanelSectionConfig } from '@superset-ui/chart-controls';
import { formatSelectOptions } from 'src/modules/utils';

export const druidTimeSeries = {
export const druidTimeSeries: ControlPanelSectionConfig = {
label: t('Time'),
expanded: true,
description: t('Time related form attributes'),
controlSetRows: [['time_range']],
};

export const datasourceAndVizType = {
export const datasourceAndVizType: ControlPanelSectionConfig = {
label: t('Chart type'),
expanded: true,
controlSetRows: [
Expand Down Expand Up @@ -74,19 +75,19 @@ export const datasourceAndVizType = {
],
};

export const colorScheme = {
export const colorScheme: ControlPanelSectionConfig = {
label: t('Color scheme'),
controlSetRows: [['color_scheme', 'label_colors']],
};

export const sqlaTimeSeries = {
export const sqlaTimeSeries: ControlPanelSectionConfig = {
label: t('Time'),
description: t('Time related form attributes'),
expanded: true,
controlSetRows: [['granularity_sqla'], ['time_range']],
};

export const annotations = {
export const annotations: ControlPanelSectionConfig = {
label: t('Annotations and layers'),
tabOverride: 'data',
expanded: true,
Expand All @@ -107,7 +108,7 @@ export const annotations = {
],
};

export const NVD3TimeSeries = [
export const NVD3TimeSeries: ControlPanelSectionConfig[] = [
{
label: t('Query'),
expanded: true,
Expand Down
68 changes: 68 additions & 0 deletions superset-frontend/src/explore/controlUtils/getControlConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* 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 memoizeOne from 'memoize-one';
import { getChartControlPanelRegistry } from '@superset-ui/core';
import {
ControlPanelSectionConfig,
expandControlConfig,
} from '@superset-ui/chart-controls';

const getMemoizedControlConfig = memoizeOne(
(controlKey, controlPanelConfig) => {
const {
controlOverrides = {},
controlPanelSections = [],
} = controlPanelConfig;
const control = expandControlConfig(
findControlItem(controlPanelSections, controlKey),
controlOverrides,
);
return control && 'config' in control ? control.config : control;
},
);

/**
* Find control item from control panel config.
*/
export function findControlItem(
controlPanelSections: ControlPanelSectionConfig[],
controlKey: string,
) {
return (
controlPanelSections
.map(section => section.controlSetRows)
.flat(2)
.find(
control =>
controlKey === control ||
(control !== null &&
typeof control === 'object' &&
'name' in control &&
control.name === controlKey),
) ?? null
);
}

export const getControlConfig = function getControlConfig(
controlKey: string,
vizType: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we not have a type for vizType yet? Seems like it should exist...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately it doesn't. I've thought about creating a VizType and actually did create a temporary type in an earlier iteration:

// TODO: replace this with string literals of actual supported viz types
type VizType = string;

But decided against it because it may not work well with dynamic plugins where viz types could be anything. If we do still find value in restricting viz types, we can do that while we convert MainPreset.js to TS.

) {
const controlPanelConfig = getChartControlPanelRegistry().get(vizType) || {};
return getMemoizedControlConfig(controlKey, controlPanelConfig);
};
95 changes: 95 additions & 0 deletions superset-frontend/src/explore/controlUtils/getSectionsToRender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* 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 memoizeOne from 'memoize-one';
import {
DatasourceType,
getChartControlPanelRegistry,
} from '@superset-ui/core';
import {
ControlPanelConfig,
expandControlConfig,
} from '@superset-ui/chart-controls';

import * as SECTIONS from 'src/explore/controlPanels/sections';

const getMemoizedSectionsToRender = memoizeOne(
(datasourceType: DatasourceType, controlPanelConfig: ControlPanelConfig) => {
const {
sectionOverrides = {},
controlOverrides,
controlPanelSections = [],
} = controlPanelConfig;

// default control panel sections
const sections = { ...SECTIONS };

// apply section overrides
Object.entries(sectionOverrides).forEach(([section, overrides]) => {
if (typeof overrides === 'object' && overrides.constructor === Object) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need these safeguards still now that there's typing here? or is there a better way to do this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all controlPanel configs are TypeScript so I'd rather keep the same logic. We can do the cleanups after all plugins are migrated to TypeScript.

sections[section] = {
...sections[section],
...overrides,
};
} else {
sections[section] = overrides;
}
});

const { datasourceAndVizType } = sections;

// list of datasource-specific controls that should be removed
const invalidControls =
datasourceType === 'table'
? ['granularity', 'druid_time_origin']
: ['granularity_sqla', 'time_grain_sqla'];

return [datasourceAndVizType]
.concat(controlPanelSections)
.filter(section => !!section)
.map(section => {
const { controlSetRows } = section;
return {
...section,
controlSetRows:
controlSetRows?.map(row =>
row
.filter(
control =>
typeof control !== 'string' ||
!invalidControls.includes(control),
)
.map(item => expandControlConfig(item, controlOverrides)),
) || [],
};
});
},
);

/**
* Get the clean and processed control panel sections
*/
export function getSectionsToRender(
vizType: string,
datasourceType: DatasourceType,
) {
const controlPanelConfig =
// TODO: update `chartControlPanelRegistry` type to use ControlPanelConfig
(getChartControlPanelRegistry().get(vizType) as ControlPanelConfig) || {};
return getMemoizedSectionsToRender(datasourceType, controlPanelConfig);
}
Loading