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
literal 0
HcmV?d00001
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/index.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/index.ts
new file mode 100644
index 0000000000000..aaa756b08cb8f
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/index.ts
@@ -0,0 +1 @@
+export { default as IFrameVisualizationChartPlugin } from './plugin';
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
new file mode 100644
index 0000000000000..9983dd5666a2e
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -0,0 +1,202 @@
+/**
+ * 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, validateNonEmpty } from '@superset-ui/core';
+import {
+ ControlPanelConfig,
+ ControlPanelState,
+ ControlState,
+ ControlStateMapping,
+ sharedControls,
+} from '@superset-ui/chart-controls';
+
+const validateAggControlValues = (
+ controls: ControlStateMapping,
+ values: any[],
+) => {
+ const areControlsEmpty = values.every(val => ensureIsArray(val).length === 0);
+ // @ts-ignore
+ return areControlsEmpty ? [t('Metrics must have a value')] : [];
+};
+
+const config: ControlPanelConfig = {
+ /**
+ * The control panel is split into two tabs: "Query" and
+ * "Chart Options". The controls that define the inputs to
+ * the chart data request, such as columns and metrics, usually
+ * reside within "Query", while controls that affect the visual
+ * appearance or functionality of the chart are under the
+ * "Chart Options" section.
+ *
+ * There are several predefined controls that can be used.
+ * Some examples:
+ * - groupby: columns to group by (tranlated to GROUP BY statement)
+ * - series: same as groupby, but single selection.
+ * - metrics: multiple metrics (translated to aggregate expression)
+ * - metric: sane as metrics, but single selection
+ * - adhoc_filters: filters (translated to WHERE or HAVING
+ * depending on filter type)
+ * - row_limit: maximum number of rows (translated to LIMIT statement)
+ *
+ * If a control panel has both a `series` and `groupby` control, and
+ * the user has chosen `col1` as the value for the `series` control,
+ * and `col2` and `col3` as values for the `groupby` control,
+ * the resulting query will contain three `groupby` columns. This is because
+ * we considered `series` control a `groupby` query field and its value
+ * will automatically append the `groupby` field when the query is generated.
+ *
+ * It is also possible to define custom controls by importing the
+ * necessary dependencies and overriding the default parameters, which
+ * can then be placed in the `controlSetRows` section
+ * of the `Query` section instead of a predefined control.
+ *
+ * import { validateNonEmpty } from '@superset-ui/core';
+ * import {
+ * sharedControls,
+ * ControlConfig,
+ * ControlPanelConfig,
+ * } from '@superset-ui/chart-controls';
+ *
+ * const myControl: ControlConfig<'SelectControl'> = {
+ * name: 'secondary_entity',
+ * config: {
+ * ...sharedControls.entity,
+ * type: 'SelectControl',
+ * label: t('Secondary Entity'),
+ * mapStateToProps: state => ({
+ * sharedControls.columnChoices(state.datasource)
+ * .columns.filter(c => c.groupby)
+ * })
+ * validators: [validateNonEmpty],
+ * },
+ * }
+ *
+ * In addition to the basic drop down control, there are several predefined
+ * control types (can be set via the `type` property) that can be used. Some
+ * commonly used examples:
+ * - SelectControl: Dropdown to select single or multiple values,
+ usually columns
+ * - MetricsControl: Dropdown to select metrics, triggering a modal
+ to define Metric details
+ * - AdhocFilterControl: Control to choose filters
+ * - CheckboxControl: A checkbox for choosing true/false values
+ * - SliderControl: A slider with min/max values
+ * - TextControl: Control for text data
+ *
+ * For more control input types, check out the `incubator-superset` repo
+ * and open this file: superset-frontend/src/explore/components/controls/index.js
+ *
+ * To ensure all controls have been filled out correctly, the following
+ * validators are provided
+ * by the `@superset-ui/core/lib/validator`:
+ * - validateNonEmpty: must have at least one value
+ * - validateInteger: must be an integer value
+ * - validateNumber: must be an intger or decimal value
+ */
+
+ // For control input types, see: superset-frontend/src/explore/components/controls/index.js
+ controlPanelSections: [
+ {
+ label: t('Query'),
+ expanded: true,
+ controlSetRows: [
+ ['adhoc_filters'],
+ [
+ {
+ name: 'metrics',
+ override: {
+ // visibility: () => true,
+ validators: [],
+ mapStateToProps: (
+ state: ControlPanelState,
+ controlState: ControlState,
+ ) => {
+ const { controls } = state;
+ const originalMapStateToProps =
+ sharedControls?.metrics?.mapStateToProps;
+ const newState =
+ originalMapStateToProps?.(state, controlState) ?? {};
+ newState.externalValidationErrors = validateAggControlValues(
+ controls,
+ [controlState.value],
+ );
+ return newState;
+ },
+ },
+ },
+ ],
+ [
+ {
+ name: 'row_limit',
+ override: {
+ default: 1,
+ },
+ },
+ ],
+ [
+ {
+ name: 'url',
+ config: {
+ type: 'TextControl',
+ label: t('URL'),
+ renderTrigger: true,
+ default: '',
+ description: t('The Base URL for the Iframe.'),
+ },
+ },
+ ],
+ [
+ {
+ name: 'parameter_column_name',
+ config: {
+ type: 'TextControl',
+ label: t('Parameter Column Name'),
+ renderTrigger: true,
+ default: '',
+ description: t('The Column name for the value that will populate the url parameter.'),
+ },
+ },
+ ],
+ [
+ {
+ name: 'parameter_name',
+ config: {
+ type: 'TextControl',
+ label: t('Parameter Name'),
+ renderTrigger: true,
+ default: '',
+ description: t('The name for the URL parameter.'),
+ },
+ },
+ ]
+ ],
+ },
+ ],
+
+ controlOverrides: {
+ series: {
+ validators: [validateNonEmpty],
+ clearable: false,
+ },
+ row_limit: {
+ default: 1,
+ },
+ },
+};
+
+export default config;
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts
new file mode 100644
index 0000000000000..42d621626fac2
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts
@@ -0,0 +1,49 @@
+/**
+ * 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 { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
+import controlPanel from './controlPanel';
+import transformProps from './transformProps';
+import thumbnail from '../images/thumbnail.png';
+
+export default class IFrameVisualizationChartPlugin extends ChartPlugin {
+ /**
+ * The constructor is used to pass relevant metadata and callbacks that get
+ * registered in respective registries that are used throughout the library
+ * and application. A more thorough description of each property is given in
+ * the respective imported file.
+ *
+ * It is worth noting that `buildQuery` and is optional, and only needed for
+ * advanced visualizations that require either post processing operations
+ * (pivoting, rolling aggregations, sorting etc) or submitting multiple queries.
+ */
+ constructor() {
+ const metadata = new ChartMetadata({
+ description: 'IFrame Visualization',
+ name: t('IFrame Visualization'),
+ thumbnail,
+ });
+
+ super({
+ controlPanel,
+ loadChart: () => import('../IFrameVisualization'),
+ metadata,
+ transformProps,
+ });
+ }
+}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
new file mode 100644
index 0000000000000..417479dc0fd17
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -0,0 +1,75 @@
+/**
+ * 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 { ChartProps, TimeseriesDataRecord } from '@superset-ui/core';
+
+export default function transformProps(chartProps: ChartProps) {
+ /**
+ * This function is called after a successful response has been
+ * received from the chart data endpoint, and is used to transform
+ * the incoming data prior to being sent to the Visualization.
+ *
+ * The transformProps function is also quite useful to return
+ * additional/modified props to your data viz component. The formData
+ * can also be accessed from your IframeDemo.tsx file, but
+ * doing supplying custom props here is often handy for integrating third
+ * party libraries that rely on specific props.
+ *
+ * A description of properties in `chartProps`:
+ * - `height`, `width`: the height/width of the DOM element in which
+ * the chart is located
+ * - `formData`: the chart data request payload that was sent to the
+ * backend.
+ * - `queriesData`: the chart data response payload that was received
+ * from the backend. Some notable properties of `queriesData`:
+ * - `data`: an array with data, each row with an object mapping
+ * the column/alias to its value. Example:
+ * `[{ col1: 'abc', metric1: 10 }, { col1: 'xyz', metric1: 20 }]`
+ * - `rowcount`: the number of rows in `data`
+ * - `query`: the query that was issued.
+ *
+ * Please note: the transformProps function gets cached when the
+ * application loads. When making changes to the `transformProps`
+ * function during development with hot reloading, changes won't
+ * be seen until restarting the development server.
+ */
+ const { formData, } = chartProps;
+
+ const { url, parameterColumnName, parameterName } = formData
+
+
+
+ let url_parameter_value = '';
+
+
+ // eslint-disable-next-line no-plusplus
+ for (let i = 0; i < formData?.adhocFilters?.length; i++) {
+
+ const adhocfilter = formData?.adhocFilters[i];
+ if (adhocfilter.subject === parameterColumnName) {
+ url_parameter_value = adhocfilter.comparator;
+ break;
+ }
+ }
+
+ return {
+ url_parameter_value,
+ parameter_name: parameterName,
+ url,
+ };
+}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/styles.js b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/styles.js
new file mode 100644
index 0000000000000..d7bb66e9bb356
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/styles.js
@@ -0,0 +1,22 @@
+const InlineBlock = {
+ display: 'inline-block',
+};
+
+const InlineImg = {
+ display: 'inline-block',
+ transform: 'translateY(-10%)',
+ '-ms-transform': 'translateY(-10%)',
+};
+
+const InlineText = {
+ display: 'inline-block',
+ 'text-align': 'center',
+};
+
+const styles = {
+ InlineBlock,
+ InlineImg,
+ InlineText,
+};
+
+export default styles;
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
new file mode 100644
index 0000000000000..0b20023c4870f
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
@@ -0,0 +1,7 @@
+import { QueryFormData, TimeseriesDataRecord } from '@superset-ui/core';
+
+export type IFrameVisualizationProps = QueryFormData & {
+ url_parameter_value: string;
+ parameter_name: string;
+ url: string;
+};
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts
new file mode 100644
index 0000000000000..0935dbbd8066c
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts
@@ -0,0 +1,4 @@
+declare module '*.png' {
+ const value: any;
+ export default value;
+}
diff --git a/superset-frontend/src/visualizations/presets/MainPreset.js b/superset-frontend/src/visualizations/presets/MainPreset.js
index 3382e1d0c4c8a..973bd8e5231c6 100644
--- a/superset-frontend/src/visualizations/presets/MainPreset.js
+++ b/superset-frontend/src/visualizations/presets/MainPreset.js
@@ -89,6 +89,7 @@ import {
AtAGlanceUserIdChartPlugin,
AtAGlanceUserIDSasChartPlugin,
ApplicationLinksChartPlugin,
+ IFrameVisualizationChartPlugin,
} from 'src/cccs-viz/plugins/';
import FilterBoxChartPlugin from '../FilterBox/FilterBoxChartPlugin';
import TimeTableChartPlugin from '../TimeTable';
@@ -116,6 +117,7 @@ export default class MainPreset extends Preset {
}),
new AtAGlanceChartIpPlugin().configure({ key: 'at_a_glance_ip' }),
new AtAGlanceChartDnsPlugin().configure({ key: 'at_a_glance_dns' }),
+ new IFrameVisualizationChartPlugin().configure({ key: 'i_frame' }),
new GwwkChartsChartPlugin().configure({ key: 'gwwk_charts' }),
new GwwkDatasetsChartPlugin().configure({ key: 'gwwk_datasets' }),
new GwwkDashboardsChartPlugin().configure({ key: 'gwwk_dashboards' }),
From 24d9090b70a224b5b2fecfe2a91206ab0cab3ea5 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Mon, 17 Oct 2022 10:29:47 -0400
Subject: [PATCH 02/31] chanigng to work with standard filters
---
.../plugin-chart-iframe/src/plugin/transformProps.ts | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 417479dc0fd17..55d0afa9cc12a 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -58,11 +58,11 @@ export default function transformProps(chartProps: ChartProps) {
// eslint-disable-next-line no-plusplus
- for (let i = 0; i < formData?.adhocFilters?.length; i++) {
+ for (let i = 0; i < formData?.extraFormData?.filters?.length; i++) {
- const adhocfilter = formData?.adhocFilters[i];
- if (adhocfilter.subject === parameterColumnName) {
- url_parameter_value = adhocfilter.comparator;
+ const adhocfilter = formData?.extraFormData?.filters[i];
+ if (adhocfilter.col === parameterColumnName) {
+ url_parameter_value = adhocfilter.val;
break;
}
}
From 02763ef9941f7ad3a9ecd8281abdb4187c689d1e Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Mon, 17 Oct 2022 15:40:54 -0400
Subject: [PATCH 03/31] Adding generic filter extraction
---
.../src/IFrameVisualization.tsx | 2 +-
.../src/plugin/transformProps.ts | 36 ++++++++++++++++++-
2 files changed, 36 insertions(+), 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
index 112275f501ac0..fa0e2edb134a8 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
@@ -6,6 +6,6 @@ export default function IFrameVisualization(props: IFrameVisualizationProps) {
const { url, url_parameter_value, parameter_name } = props
console.log(`${url}?${parameter_name}=${url_parameter_value}`)
return (
-
+
);
}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 55d0afa9cc12a..fbc9ab151c7de 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -16,7 +16,41 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ChartProps, TimeseriesDataRecord } from '@superset-ui/core';
+import { ChartProps, QueryFormData, TimeseriesDataRecord, AdhocFilter } from '@superset-ui/core';
+import { string } from 'yargs';
+
+
+const extractFiltersFromFormData = (formData: QueryFormData): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] } | null)[] | undefined => {
+
+ const adhoc = formData?.adhoc_filters?.map( (filter: AdhocFilter) => {
+ if ( ("subject" in filter) && ("comparator" in filter) ) {
+ return {columnName: filter.subject, value: filter.comparator}
+ }
+ else {
+ return null
+ }
+ }) || []
+
+ const adhocExtra = formData?.extra_form_data?.adhoc_filters?.map( (filter: AdhocFilter) => {
+ if ( ("subject" in filter) && ("comparator" in filter) ) {
+ return {columnName: filter.subject, value: filter.comparator}
+ }
+ else {
+ return null
+ }
+ }) || []
+
+ const simpleExtra = formData?.extra_form_data?.filters?.map( (filter) => {
+ if ( ("col" in filter) && ("val" in filter) ) {
+ return {columnName: filter.col.toString(), value: filter.val}
+ }
+ else {
+ return null
+ }
+ }) || []
+
+ return [...adhoc, ...adhocExtra, ...simpleExtra]
+}
export default function transformProps(chartProps: ChartProps) {
/**
From 3ed190ccaab2e2d6a58f581b5ef35843ead1f763 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Mon, 17 Oct 2022 15:42:37 -0400
Subject: [PATCH 04/31] Removing unused imports
---
.../plugins/plugin-chart-iframe/src/plugin/transformProps.ts | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index fbc9ab151c7de..e2feec013f954 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -16,8 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ChartProps, QueryFormData, TimeseriesDataRecord, AdhocFilter } from '@superset-ui/core';
-import { string } from 'yargs';
+import { ChartProps, QueryFormData, AdhocFilter } from '@superset-ui/core';
const extractFiltersFromFormData = (formData: QueryFormData): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] } | null)[] | undefined => {
@@ -93,7 +92,6 @@ export default function transformProps(chartProps: ChartProps) {
// eslint-disable-next-line no-plusplus
for (let i = 0; i < formData?.extraFormData?.filters?.length; i++) {
-
const adhocfilter = formData?.extraFormData?.filters[i];
if (adhocfilter.col === parameterColumnName) {
url_parameter_value = adhocfilter.val;
From 1dc2d51dd0d8499689071383a38534a3f6cbb2dc Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 18 Oct 2022 11:51:50 -0400
Subject: [PATCH 05/31] [CLDN-1749] Cleaning up code for reusablility
---
.../src/IFrameVisualization.tsx | 6 +-
.../src/plugin/transformProps.ts | 66 +++++++------------
.../plugins/plugin-chart-iframe/src/types.ts | 2 +-
3 files changed, 28 insertions(+), 46 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
index fa0e2edb134a8..659db9fa3ced8 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
@@ -4,8 +4,10 @@ import { IFrameVisualizationProps } from './types';
export default function IFrameVisualization(props: IFrameVisualizationProps) {
const { url, url_parameter_value, parameter_name } = props
- console.log(`${url}?${parameter_name}=${url_parameter_value}`)
+
+ const parserdUrlParameterName = parameter_name.includes('=') ? parameter_name : `${parameter_name}=`
+
return (
-
+
);
}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index e2feec013f954..8300534d6f7a2 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -16,39 +16,27 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ChartProps, QueryFormData, AdhocFilter } from '@superset-ui/core';
+import { ChartProps, PlainObject, } from '@superset-ui/core';
-const extractFiltersFromFormData = (formData: QueryFormData): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] } | null)[] | undefined => {
+const extractFiltersFromFormData = (formData: PlainObject): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] })[] => {
- const adhoc = formData?.adhoc_filters?.map( (filter: AdhocFilter) => {
- if ( ("subject" in filter) && ("comparator" in filter) ) {
- return {columnName: filter.subject, value: filter.comparator}
- }
- else {
- return null
- }
- }) || []
-
- const adhocExtra = formData?.extra_form_data?.adhoc_filters?.map( (filter: AdhocFilter) => {
- if ( ("subject" in filter) && ("comparator" in filter) ) {
- return {columnName: filter.subject, value: filter.comparator}
- }
- else {
- return null
- }
- }) || []
-
- const simpleExtra = formData?.extra_form_data?.filters?.map( (filter) => {
- if ( ("col" in filter) && ("val" in filter) ) {
- return {columnName: filter.col.toString(), value: filter.val}
- }
- else {
- return null
- }
- }) || []
+ const filters = [...(formData?.adhoc_filters || []), ...(formData?.extra_form_data?.adhoc_filters || []), ...(formData?.extra_form_data?.filters || [])]
- return [...adhoc, ...adhocExtra, ...simpleExtra]
+ const simpleAdhocFilters = filters.reduce(
+ (acc, filter) => {
+
+ if ( ("subject" in filter) && ("comparator" in filter) ) {
+ acc.push( {columnName: filter.subject, value: filter.comparator} )
+ }
+ else if ( ("col" in filter) && ("val" in filter) ) {
+ acc.push( {columnName: filter.col.toString(), value: filter.val} )
+ }
+ return acc
+ }, <({columnName: string, value: string | number | boolean | (string | number | boolean)[]})[]> []
+ )
+
+ return simpleAdhocFilters
}
export default function transformProps(chartProps: ChartProps) {
@@ -81,23 +69,15 @@ export default function transformProps(chartProps: ChartProps) {
* function during development with hot reloading, changes won't
* be seen until restarting the development server.
*/
- const { formData, } = chartProps;
+ const formData = chartProps.formData;
const { url, parameterColumnName, parameterName } = formData
-
-
- let url_parameter_value = '';
-
-
- // eslint-disable-next-line no-plusplus
- for (let i = 0; i < formData?.extraFormData?.filters?.length; i++) {
- const adhocfilter = formData?.extraFormData?.filters[i];
- if (adhocfilter.col === parameterColumnName) {
- url_parameter_value = adhocfilter.val;
- break;
- }
- }
+ const allFilters = extractFiltersFromFormData(formData);
+
+ const url_parameter_value = String(allFilters.find( e => {
+ return e.columnName == parameterColumnName
+ })?.value);
return {
url_parameter_value,
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
index 0b20023c4870f..0bbc30d050e49 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
@@ -1,4 +1,4 @@
-import { QueryFormData, TimeseriesDataRecord } from '@superset-ui/core';
+import { QueryFormData } from '@superset-ui/core';
export type IFrameVisualizationProps = QueryFormData & {
url_parameter_value: string;
From bc0419d91342e830338eebf01c60d7b455ef094f Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 18 Oct 2022 11:54:09 -0400
Subject: [PATCH 06/31] [CLDN-1749] removing unused files
---
.../plugin-chart-iframe/src/images/alfred.png | Bin 2753 -> 0 bytes
.../plugin-chart-iframe/src/images/thumbnail.png | Bin 5658 -> 0 bytes
.../plugin-chart-iframe/types/external.d.ts | 4 ----
3 files changed, 4 deletions(-)
delete mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/alfred.png
delete mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
delete mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/alfred.png b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/alfred.png
deleted file mode 100644
index ab1d3036b5f6f78d8974946c6bfe6c295edd48e4..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 2753
zcmV;y3O@CTP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D3RX!(K~#8N?V5W~
zRM#EHeU9Vf4@bwxf6Az{oxx#n*6QFeSrNgqsi;Uap=e^`1GHLUVlt-KZc2THR>An#
zifd#68^wqqM#IC`DpIY42yrXbfKWh1bVU&s!Eetw_nylIcdNqgI?27?nKSJDopaA#
z&gcAo=XcKDUQnedslXK`6}ZBr0#}$+;0lupTwzjyD@-bIg-HdjFsZ;5CKb5Cqykr%
z+zx!|)T!vzs~0OeosQX_KYz~ts`9+t0=&Jwo&7B;Dng$=ebBdWUsn3{>xXOCuCY25
z`kRqkfk#G0GSBYayEiNJb98hxtK)4{c~))<>9w`B7&2rC13h~5Xp9;)ihUkFd^jFF
zcp$b?I;n_qJ`@5FZ~eUGLt#o3&BB-1BmahuiITj2kzOdGvq*19125
zT~t(5ur-|8e0_a?Qfqj*Q4cRKFL=e~ik1#F-ORyXA_Cx}A@!t<_q%DhCDyrL^2^%*;&Y$rSFqdGnZ!Dkvz3*=XIlbLW^%?&WRmq(2XOy*)P;
z8VXVqg>0K>bReg|%S{LsL3??5L+kGkzsQuIFYvD7UORKW*Sj=SOB!|vki#JkVq?bH)^+x!he
zOvh36v<(Li96+z$eVF$yU%s5Rmxpu?JuEDY0jF*08h`aa^$1w?CEi-L2XFm$52k-;
zg7HuxT1l9vqMq*3tiCt_)9AqI5(#>u(nRR!wQn3O4#vAP@LHTsT95VXS7NrWFxa|C
zdQHn$py!BEd!0_`mlu&reeNgl<5|7dAO0lSKaI9$1{6PAPi^f$kT`-UVJ7_h%}mr
zbSa-GH-(CDLy=I_(cW(R4(7#L>3duToXSR$tuL-w5q`cHi%wc_vAT}gn~1l!JZr;$
zA2wp;*XJK{HKVZ0SB_GhgA
zl*J1D(qzn7WWwL}7U0q2W@hiPY}trn-lc;)g7Y<96O~Q!_s;4zaQ!aGomIXw2sb-O
z5$zVlF^}cXRtN*T){tF9J!{fQ_AA)T@(&jRzi{U+7N5O@1s994v&4!Xxr4ZLfGJr}WTvc32nT)DAApAocy
zbr*u!GcAMTU8D17aHjtYeC;{4v*{>;K0Snjk}4MZr%aiGh6bU3-lzNk=2G#G
zSQvc(0pWYGD0;tW?T&8494-vdiyr2@&Sk*MjnGs3D-=E5GUUbz*Ig&4B$orfg6(Bi
z61IgfOF7FumTtGGwr<_Z*5rX?Z(UMSg3AQzuamM6o^%W`2XYbo=Yt6PQyOBDPvTb_
z(lO_=!vuUi&YnGsK7ISLd-v}bK=MAR=y&mT`zguVKl|$m0{lyM-7QH29u7wlwKhFM
z7+{{viE=$~;Z%+$YtG7&v|FABE|;@>iH2i(Zccyirb$>4i3(J=?ljgWFiC_EHdw}B9pZPZ0D1B`!iy6fXX#!VANYmEz%27(Ne<7_6LGe}F74ah2Aq3ka&oe?_C`cRFq@;b
zR}Nafx8~x|XUv$v`l5a2$QP%Kw7O<0%WmRn5{d2_&pgJ8PWve*}kJ_
zp{i$kE#Mr^g$oxXIFlw#atWB`=4Ol;Glum^6TurdZZNwF-L>i#a2mq7cN>jHX6s3k
z#rxf`VFT-vmUZjaFMjslXK`6}ZBr0#}$+;0lupTwzjyD@-bIMG5#Hr<^cI(hX2P00000NkvXX
Hu0mjfpbJjG
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
deleted file mode 100644
index 7afef30bd4e6e4f85723208bf9f429647d03d3e5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 5658
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
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts
deleted file mode 100644
index 0935dbbd8066c..0000000000000
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/types/external.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module '*.png' {
- const value: any;
- export default value;
-}
From ae3aaa40ff312e8dcaf0f05c159d2f5f1146fcfd Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 18 Oct 2022 13:02:39 -0400
Subject: [PATCH 07/31] [CLDN-1746] fixing case
---
.../src/images/thumbnail.png | Bin 0 -> 5658 bytes
.../src/images/thumbnail.png:Zone.Identifier | 4 +
.../src/plugin/transformProps.ts | 2 +-
.../AnnotationLayer.jsx | 847 ++++++++++++++++++
.../AnnotationLayer.test.tsx | 240 +++++
.../DrillToDashboardLinkConfig/index.jsx | 258 ++++++
6 files changed, 1350 insertions(+), 1 deletion(-)
create mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
create mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png:Zone.Identifier
create mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
create mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
create mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
new file mode 100644
index 0000000000000000000000000000000000000000..7afef30bd4e6e4f85723208bf9f429647d03d3e5
GIT binary patch
literal 5658
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
literal 0
HcmV?d00001
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png:Zone.Identifier b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png:Zone.Identifier
new file mode 100644
index 0000000000000..33a7247de00d7
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png:Zone.Identifier
@@ -0,0 +1,4 @@
+[ZoneTransfer]
+ZoneId=3
+ReferrerUrl=https://github.com/CybercentreCanada/superset/blob/feature/CLDN-750-cccs-1.2/superset-frontend/src/cccs-viz/plugins/plugin-chart-at-a-glance/src/images/thumbnail.png
+HostUrl=https://raw.githubusercontent.com/CybercentreCanada/superset/feature/CLDN-750-cccs-1.2/superset-frontend/src/cccs-viz/plugins/plugin-chart-at-a-glance/src/images/thumbnail.png
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 8300534d6f7a2..b2c717fe55caa 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -21,7 +21,7 @@ import { ChartProps, PlainObject, } from '@superset-ui/core';
const extractFiltersFromFormData = (formData: PlainObject): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] })[] => {
- const filters = [...(formData?.adhoc_filters || []), ...(formData?.extra_form_data?.adhoc_filters || []), ...(formData?.extra_form_data?.filters || [])]
+ const filters = [...(formData?.adhocFilters || []), ...(formData?.extraFormData?.adhocFilters || []), ...(formData?.extraFormData?.filters || [])]
const simpleAdhocFilters = filters.reduce(
(acc, filter) => {
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
new file mode 100644
index 0000000000000..8df36c1291ac8
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
@@ -0,0 +1,847 @@
+/**
+ * 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 React from 'react';
+import PropTypes from 'prop-types';
+import { CompactPicker } from 'react-color';
+import Button from 'src/components/Button';
+import {
+ t,
+ SupersetClient,
+ getCategoricalSchemeRegistry,
+ getChartMetadataRegistry,
+ validateNonEmpty,
+ isValidExpression,
+ styled,
+ withTheme,
+} from '@superset-ui/core';
+
+import SelectControl from 'src/explore/components/controls/SelectControl';
+import TextControl from 'src/explore/components/controls/TextControl';
+import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
+import {
+ ANNOTATION_SOURCE_TYPES,
+ ANNOTATION_TYPES,
+ ANNOTATION_TYPES_METADATA,
+ DEFAULT_ANNOTATION_TYPE,
+ requiresQuery,
+ ANNOTATION_SOURCE_TYPES_METADATA,
+} from 'src/modules/AnnotationTypes';
+import PopoverSection from 'src/components/PopoverSection';
+import ControlHeader from 'src/explore/components/ControlHeader';
+import { EmptyStateSmall } from 'src/components/EmptyState';
+
+const AUTOMATIC_COLOR = '';
+
+const propTypes = {
+ name: PropTypes.string,
+ annotationType: PropTypes.string,
+ sourceType: PropTypes.string,
+ color: PropTypes.string,
+ opacity: PropTypes.string,
+ style: PropTypes.string,
+ width: PropTypes.number,
+ showMarkers: PropTypes.bool,
+ hideLine: PropTypes.bool,
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ overrides: PropTypes.object,
+ show: PropTypes.bool,
+ showLabel: PropTypes.bool,
+ titleColumn: PropTypes.string,
+ descriptionColumns: PropTypes.arrayOf(PropTypes.string),
+ timeColumn: PropTypes.string,
+ intervalEndColumn: PropTypes.string,
+ vizType: PropTypes.string,
+
+ error: PropTypes.string,
+ colorScheme: PropTypes.string,
+
+ addAnnotationLayer: PropTypes.func,
+ removeAnnotationLayer: PropTypes.func,
+ close: PropTypes.func,
+};
+
+const defaultProps = {
+ name: '',
+ annotationType: DEFAULT_ANNOTATION_TYPE,
+ sourceType: '',
+ color: AUTOMATIC_COLOR,
+ opacity: '',
+ style: 'solid',
+ width: 1,
+ showMarkers: false,
+ hideLine: false,
+ overrides: {},
+ colorScheme: 'd3Category10',
+ show: true,
+ showLabel: false,
+ titleColumn: '',
+ descriptionColumns: [],
+ timeColumn: '',
+ intervalEndColumn: '',
+
+ addAnnotationLayer: () => {},
+ removeAnnotationLayer: () => {},
+ close: () => {},
+};
+
+const NotFoundContentWrapper = styled.div`
+ && > div:first-child {
+ padding-left: 0;
+ padding-right: 0;
+ }
+`;
+
+const NotFoundContent = () => (
+
+
+ {t('Add an annotation layer')}{' '}
+
+ {t('here')}
+
+ .
+
+ }
+ image="empty.svg"
+ />
+
+);
+
+class AnnotationLayer extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ const {
+ name,
+ annotationType,
+ sourceType,
+ color,
+ opacity,
+ style,
+ width,
+ showMarkers,
+ hideLine,
+ value,
+ overrides,
+ show,
+ showLabel,
+ titleColumn,
+ descriptionColumns,
+ timeColumn,
+ intervalEndColumn,
+ vizType,
+ } = props;
+
+ // Only allow override whole time_range
+ if ('since' in overrides || 'until' in overrides) {
+ overrides.time_range = null;
+ delete overrides.since;
+ delete overrides.until;
+ }
+
+ // Check if annotationType is supported by this chart
+ const metadata = getChartMetadataRegistry().get(vizType);
+ const supportedAnnotationTypes = metadata?.supportedAnnotationTypes || [];
+ const validAnnotationType = supportedAnnotationTypes.includes(
+ annotationType,
+ )
+ ? annotationType
+ : supportedAnnotationTypes[0];
+
+ this.state = {
+ // base
+ name,
+ annotationType: validAnnotationType,
+ sourceType,
+ value,
+ overrides,
+ show,
+ showLabel,
+ // slice
+ titleColumn,
+ descriptionColumns,
+ timeColumn,
+ intervalEndColumn,
+ // display
+ color: color || AUTOMATIC_COLOR,
+ opacity,
+ style,
+ width,
+ showMarkers,
+ hideLine,
+ // refData
+ isNew: !name,
+ isLoadingOptions: true,
+ valueOptions: [],
+ };
+ this.submitAnnotation = this.submitAnnotation.bind(this);
+ this.deleteAnnotation = this.deleteAnnotation.bind(this);
+ this.applyAnnotation = this.applyAnnotation.bind(this);
+ this.fetchOptions = this.fetchOptions.bind(this);
+ this.handleAnnotationType = this.handleAnnotationType.bind(this);
+ this.handleAnnotationSourceType =
+ this.handleAnnotationSourceType.bind(this);
+ this.handleValue = this.handleValue.bind(this);
+ this.isValidForm = this.isValidForm.bind(this);
+ }
+
+ componentDidMount() {
+ const { annotationType, sourceType, isLoadingOptions } = this.state;
+ this.fetchOptions(annotationType, sourceType, isLoadingOptions);
+ }
+
+ componentDidUpdate(prevProps, prevState) {
+ if (prevState.sourceType !== this.state.sourceType) {
+ this.fetchOptions(this.state.annotationType, this.state.sourceType, true);
+ }
+ }
+
+ getSupportedSourceTypes(annotationType) {
+ // Get vis types that can be source.
+ const sources = getChartMetadataRegistry()
+ .entries()
+ .filter(({ value: chartMetadata }) =>
+ chartMetadata.canBeAnnotationType(annotationType),
+ )
+ .map(({ key, value: chartMetadata }) => ({
+ value: key,
+ label: chartMetadata.name,
+ }));
+ // Prepend native source if applicable
+ if (ANNOTATION_TYPES_METADATA[annotationType]?.supportNativeSource) {
+ sources.unshift(ANNOTATION_SOURCE_TYPES_METADATA.NATIVE);
+ }
+ return sources;
+ }
+
+ isValidFormulaAnnotation(expression, annotationType) {
+ if (annotationType === ANNOTATION_TYPES.FORMULA) {
+ return isValidExpression(expression);
+ }
+ return true;
+ }
+
+ isValidForm() {
+ const {
+ name,
+ annotationType,
+ sourceType,
+ value,
+ timeColumn,
+ intervalEndColumn,
+ } = this.state;
+ const errors = [
+ validateNonEmpty(name),
+ validateNonEmpty(annotationType),
+ validateNonEmpty(value),
+ ];
+ if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE) {
+ if (annotationType === ANNOTATION_TYPES.EVENT) {
+ errors.push(validateNonEmpty(timeColumn));
+ }
+ if (annotationType === ANNOTATION_TYPES.INTERVAL) {
+ errors.push(validateNonEmpty(timeColumn));
+ errors.push(validateNonEmpty(intervalEndColumn));
+ }
+ }
+ errors.push(!this.isValidFormulaAnnotation(value, annotationType));
+ return !errors.filter(x => x).length;
+ }
+
+ handleAnnotationType(annotationType) {
+ this.setState({
+ annotationType,
+ sourceType: null,
+ value: null,
+ });
+ }
+
+ handleAnnotationSourceType(sourceType) {
+ const { sourceType: prevSourceType } = this.state;
+
+ if (prevSourceType !== sourceType) {
+ this.setState({ sourceType, value: null, isLoadingOptions: true });
+ }
+ }
+
+ handleValue(value) {
+ this.setState({
+ value,
+ descriptionColumns: [],
+ intervalEndColumn: null,
+ timeColumn: null,
+ titleColumn: null,
+ overrides: { time_range: null },
+ });
+ }
+
+ fetchOptions(annotationType, sourceType, isLoadingOptions) {
+ if (isLoadingOptions) {
+ if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
+ SupersetClient.get({
+ endpoint: '/annotationlayermodelview/api/read?',
+ }).then(({ json }) => {
+ const layers = json
+ ? json.result.map(layer => ({
+ value: layer.id,
+ label: layer.name,
+ }))
+ : [];
+ this.setState({
+ isLoadingOptions: false,
+ valueOptions: layers,
+ });
+ });
+ } else if (requiresQuery(sourceType)) {
+ SupersetClient.get({ endpoint: '/superset/user_slices' }).then(
+ ({ json }) => {
+ const registry = getChartMetadataRegistry();
+ this.setState({
+ isLoadingOptions: false,
+ valueOptions: json
+ .filter(x => {
+ const metadata = registry.get(x.viz_type);
+ return (
+ metadata && metadata.canBeAnnotationType(annotationType)
+ );
+ })
+ .map(x => ({ value: x.id, label: x.title, slice: x })),
+ });
+ },
+ );
+ } else {
+ this.setState({
+ isLoadingOptions: false,
+ valueOptions: [],
+ });
+ }
+ }
+ }
+
+ deleteAnnotation() {
+ this.props.removeAnnotationLayer();
+ this.props.close();
+ }
+
+ applyAnnotation() {
+ if (this.isValidForm()) {
+ const annotationFields = [
+ 'name',
+ 'annotationType',
+ 'sourceType',
+ 'color',
+ 'opacity',
+ 'style',
+ 'width',
+ 'showMarkers',
+ 'hideLine',
+ 'value',
+ 'overrides',
+ 'show',
+ 'showLabel',
+ 'titleColumn',
+ 'descriptionColumns',
+ 'timeColumn',
+ 'intervalEndColumn',
+ ];
+ const newAnnotation = {};
+ annotationFields.forEach(field => {
+ if (this.state[field] !== null) {
+ newAnnotation[field] = this.state[field];
+ }
+ });
+
+ if (newAnnotation.color === AUTOMATIC_COLOR) {
+ newAnnotation.color = null;
+ }
+
+ this.props.addAnnotationLayer(newAnnotation);
+ this.setState({ isNew: false });
+ }
+ }
+
+ submitAnnotation() {
+ this.applyAnnotation();
+ this.props.close();
+ }
+
+ renderOption(option) {
+ return (
+
+ {option.label}
+
+ );
+ }
+
+ renderValueConfiguration() {
+ const {
+ annotationType,
+ sourceType,
+ value,
+ valueOptions,
+ isLoadingOptions,
+ } = this.state;
+ let label = '';
+ let description = '';
+ if (requiresQuery(sourceType)) {
+ if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
+ label = 'Annotation layer';
+ description = 'Select the Annotation Layer you would like to use.';
+ } else {
+ label = t('Chart');
+ description = t(
+ `Use another existing chart as a source for annotations and overlays.
+ Your chart must be one of these visualization types: [%s]`,
+ this.getSupportedSourceTypes(annotationType)
+ .map(x => x.label)
+ .join(', '),
+ );
+ }
+ } else if (annotationType === ANNOTATION_TYPES.FORMULA) {
+ label = 'Formula';
+ description = `Expects a formula with depending time parameter 'x'
+ in milliseconds since epoch. mathjs is used to evaluate the formulas.
+ Example: '2x+5'`;
+ }
+ if (requiresQuery(sourceType)) {
+ return (
+ }
+ />
+ );
+ }
+ if (annotationType === ANNOTATION_TYPES.FORMULA) {
+ return (
+
+ );
+ }
+ return '';
+ }
+
+ renderSliceConfiguration() {
+ const {
+ annotationType,
+ sourceType,
+ value,
+ valueOptions,
+ overrides,
+ titleColumn,
+ timeColumn,
+ intervalEndColumn,
+ descriptionColumns,
+ } = this.state;
+ const { slice } = valueOptions.find(x => x.value === value) || {};
+ if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE && slice) {
+ const columns = (slice.data.groupby || [])
+ .concat(slice.data.all_columns || [])
+ .map(x => ({ value: x, label: x }));
+ const timeColumnOptions = slice.data.include_time
+ ? [{ value: '__timestamp', label: '__timestamp' }].concat(columns)
+ : columns;
+ return (
+
+
+ {(annotationType === ANNOTATION_TYPES.EVENT ||
+ annotationType === ANNOTATION_TYPES.INTERVAL) && (
+ this.setState({ timeColumn: v })}
+ />
+ )}
+ {annotationType === ANNOTATION_TYPES.INTERVAL && (
+ this.setState({ intervalEndColumn: value })}
+ />
+ )}
+ this.setState({ titleColumn: value })}
+ />
+ {annotationType !== ANNOTATION_TYPES.TIME_SERIES && (
+ this.setState({ descriptionColumns: value })}
+ />
+ )}
+
+ {
+ delete overrides.time_range;
+ if (v) {
+ this.setState({
+ overrides: { ...overrides, time_range: null },
+ });
+ } else {
+ this.setState({ overrides: { ...overrides } });
+ }
+ }}
+ />
+ {
+ delete overrides.time_grain_sqla;
+ delete overrides.granularity;
+ if (v) {
+ this.setState({
+ overrides: {
+ ...overrides,
+ time_grain_sqla: null,
+ granularity: null,
+ },
+ });
+ } else {
+ this.setState({ overrides: { ...overrides } });
+ }
+ }}
+ />
+
+ this.setState({ overrides: { ...overrides, time_shift: v } })
+ }
+ />
+
+
+
+ );
+ }
+ return '';
+ }
+
+ renderDisplayConfiguration() {
+ const {
+ color,
+ opacity,
+ style,
+ width,
+ showMarkers,
+ hideLine,
+ annotationType,
+ } = this.state;
+ const colorScheme = getCategoricalSchemeRegistry()
+ .get(this.props.colorScheme)
+ .colors.concat();
+ if (
+ color &&
+ color !== AUTOMATIC_COLOR &&
+ !colorScheme.find(x => x.toLowerCase() === color.toLowerCase())
+ ) {
+ colorScheme.push(color);
+ }
+ return (
+
+ this.setState({ style: v })}
+ />
+ this.setState({ opacity: value })}
+ />
+
+
+
+ this.setState({ color: v.hex })}
+ />
+ this.setState({ color: AUTOMATIC_COLOR })}
+ >
+ Automatic Color
+
+
+
+ this.setState({ width: v })}
+ />
+ {annotationType === ANNOTATION_TYPES.TIME_SERIES && (
+ this.setState({ showMarkers: v })}
+ />
+ )}
+ {annotationType === ANNOTATION_TYPES.TIME_SERIES && (
+ this.setState({ hideLine: v })}
+ />
+ )}
+
+ );
+ }
+
+ render() {
+ const { isNew, name, annotationType, sourceType, show, showLabel } =
+ this.state;
+ const isValid = this.isValidForm();
+ const metadata = getChartMetadataRegistry().get(this.props.vizType);
+ const supportedAnnotationTypes = metadata
+ ? metadata.supportedAnnotationTypes.map(
+ type => ANNOTATION_TYPES_METADATA[type],
+ )
+ : [];
+ const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
+
+ return (
+ <>
+ {this.props.error && (
+
+ ERROR: {this.props.error}
+
+ )}
+
+
+
+ this.setState({ name: v })}
+ validationErrors={!name ? [t('Mandatory')] : []}
+ />
+ this.setState({ show: !v })}
+ />
+ this.setState({ showLabel: v })}
+ />
+
+ {supportedSourceTypes.length > 0 && (
+ }
+ value={sourceType}
+ onChange={this.handleAnnotationSourceType}
+ validationErrors={!sourceType ? [t('Mandatory')] : []}
+ />
+ )}
+ {this.renderValueConfiguration()}
+
+
+ {this.renderSliceConfiguration()}
+ {this.renderDisplayConfiguration()}
+
+
+ {isNew ? (
+
this.props.close()}>
+ {t('Cancel')}
+
+ ) : (
+
+ {t('Remove')}
+
+ )}
+
+
+ {t('Apply')}
+
+
+
+ {t('OK')}
+
+
+
+ >
+ );
+ }
+}
+
+AnnotationLayer.propTypes = propTypes;
+AnnotationLayer.defaultProps = defaultProps;
+
+export default withTheme(AnnotationLayer);
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
new file mode 100644
index 0000000000000..ed8ae44339b2e
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
@@ -0,0 +1,240 @@
+/**
+ * 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 React from 'react';
+import { render, screen, waitFor } from 'spec/helpers/testing-library';
+import userEvent from '@testing-library/user-event';
+import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core';
+import fetchMock from 'fetch-mock';
+import setupColors from 'src/setup/setupColors';
+import { ANNOTATION_TYPES_METADATA } from 'src/modules/AnnotationTypes';
+import AnnotationLayer from './AnnotationLayer';
+
+const defaultProps = {
+ value: '',
+ vizType: 'table',
+ annotationType: ANNOTATION_TYPES_METADATA.FORMULA.value,
+};
+
+beforeAll(() => {
+ const supportedAnnotationTypes = Object.values(ANNOTATION_TYPES_METADATA).map(
+ value => value.value,
+ );
+
+ fetchMock.get('glob:*/annotationlayermodelview/api/read?*', {
+ result: [{ label: 'Chart A', value: 'a' }],
+ });
+
+ fetchMock.get('glob:*/superset/user_slices*', [
+ { id: 'a', title: 'Chart A', viz_type: 'table', data: {} },
+ ]);
+
+ setupColors();
+
+ getChartMetadataRegistry().registerValue(
+ 'table',
+ new ChartMetadata({
+ name: 'Table',
+ thumbnail: '',
+ supportedAnnotationTypes,
+ canBeAnnotationTypes: ['EVENT'],
+ }),
+ );
+});
+
+const waitForRender = (props?: any) =>
+ waitFor(() => render( ));
+
+test('renders with default props', async () => {
+ await waitForRender();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
+ expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
+ expect(screen.getByRole('button', { name: 'Cancel' })).toBeEnabled();
+});
+
+test('renders extra checkboxes when type is time series', async () => {
+ await waitForRender();
+ expect(
+ screen.queryByRole('button', { name: 'Show Markers' }),
+ ).not.toBeInTheDocument();
+ expect(
+ screen.queryByRole('button', { name: 'Hide Line' }),
+ ).not.toBeInTheDocument();
+ userEvent.click(screen.getAllByText('Formula')[0]);
+ userEvent.click(screen.getByText('Time series'));
+ expect(
+ screen.getByRole('button', { name: 'Show Markers' }),
+ ).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'Hide Line' })).toBeInTheDocument();
+});
+
+test('enables apply and ok buttons', async () => {
+ const { container } = render( );
+
+ waitFor(() => {
+ expect(container).toBeInTheDocument();
+ });
+
+ const nameInput = screen.getByRole('textbox', { name: 'Name' });
+ const formulaInput = screen.getByRole('textbox', { name: 'Formula' });
+
+ expect(nameInput).toBeInTheDocument();
+ expect(formulaInput).toBeInTheDocument();
+
+ userEvent.type(nameInput, 'Name');
+ userEvent.type(formulaInput, '2x');
+
+ waitFor(() => {
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
+ expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
+ });
+});
+
+test('triggers addAnnotationLayer when apply button is clicked', async () => {
+ const addAnnotationLayer = jest.fn();
+ await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer });
+ userEvent.click(screen.getByRole('button', { name: 'Apply' }));
+ expect(addAnnotationLayer).toHaveBeenCalled();
+});
+
+test('triggers addAnnotationLayer and close when ok button is clicked', async () => {
+ const addAnnotationLayer = jest.fn();
+ const close = jest.fn();
+ await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer, close });
+ userEvent.click(screen.getByRole('button', { name: 'OK' }));
+ expect(addAnnotationLayer).toHaveBeenCalled();
+ expect(close).toHaveBeenCalled();
+});
+
+test('triggers close when cancel button is clicked', async () => {
+ const close = jest.fn();
+ await waitForRender({ close });
+ userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
+ expect(close).toHaveBeenCalled();
+});
+
+test('triggers removeAnnotationLayer and close when remove button is clicked', async () => {
+ const removeAnnotationLayer = jest.fn();
+ const close = jest.fn();
+ await waitForRender({
+ name: 'Test',
+ value: '2x',
+ removeAnnotationLayer,
+ close,
+ });
+ userEvent.click(screen.getByRole('button', { name: 'Remove' }));
+ expect(removeAnnotationLayer).toHaveBeenCalled();
+ expect(close).toHaveBeenCalled();
+});
+
+test('renders chart options', async () => {
+ await waitForRender({
+ annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
+ });
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation source type' }),
+ );
+ userEvent.click(screen.getByText('Superset annotation'));
+ expect(screen.getByText('Annotation layer')).toBeInTheDocument();
+
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation source type' }),
+ );
+ userEvent.click(screen.getByText('Table'));
+ expect(screen.getByText('Chart')).toBeInTheDocument();
+});
+
+test('keeps apply disabled when missing required fields', async () => {
+ await waitForRender({
+ annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
+ sourceType: 'Table',
+ });
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation layer value' }),
+ );
+ userEvent.click(await screen.findByText('Chart A'));
+ expect(
+ screen.getByText('Annotation Slice Configuration'),
+ ).toBeInTheDocument();
+
+ userEvent.click(screen.getByRole('button', { name: 'Automatic Color' }));
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation layer title column' }),
+ );
+ userEvent.click(screen.getByText('None'));
+ userEvent.click(screen.getByText('Style'));
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation layer stroke' }),
+ );
+ userEvent.click(screen.getByText('Dashed'));
+ userEvent.click(screen.getByText('Opacity'));
+ userEvent.click(
+ screen.getByRole('combobox', { name: 'Annotation layer opacity' }),
+ );
+ userEvent.click(screen.getByText('0.5'));
+
+ const checkboxes = screen.getAllByRole('checkbox');
+ checkboxes.forEach(checkbox => userEvent.click(checkbox));
+
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
+});
+
+test.skip('Disable apply button if formula is incorrect', async () => {
+ // TODO: fix flaky test that passes locally but fails on CI
+ await waitForRender({ name: 'test' });
+
+ userEvent.clear(screen.getByLabelText('Formula'));
+ userEvent.type(screen.getByLabelText('Formula'), 'x+1');
+ await waitFor(() => {
+ expect(screen.getByLabelText('Formula')).toHaveValue('x+1');
+ expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
+ });
+
+ userEvent.clear(screen.getByLabelText('Formula'));
+ userEvent.type(screen.getByLabelText('Formula'), 'y = x*2+1');
+ await waitFor(() => {
+ expect(screen.getByLabelText('Formula')).toHaveValue('y = x*2+1');
+ expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
+ });
+
+ userEvent.clear(screen.getByLabelText('Formula'));
+ userEvent.type(screen.getByLabelText('Formula'), 'y+1');
+ await waitFor(() => {
+ expect(screen.getByLabelText('Formula')).toHaveValue('y+1');
+ expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
+ });
+
+ userEvent.clear(screen.getByLabelText('Formula'));
+ userEvent.type(screen.getByLabelText('Formula'), 'x+');
+ await waitFor(() => {
+ expect(screen.getByLabelText('Formula')).toHaveValue('x+');
+ expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
+ });
+
+ userEvent.clear(screen.getByLabelText('Formula'));
+ userEvent.type(screen.getByLabelText('Formula'), 'y = z+1');
+ await waitFor(() => {
+ expect(screen.getByLabelText('Formula')).toHaveValue('y = z+1');
+ expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
+ expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
+ });
+});
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
new file mode 100644
index 0000000000000..f1381abee1aa4
--- /dev/null
+++ b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
@@ -0,0 +1,258 @@
+/**
+ * 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 React from 'react';
+import PropTypes from 'prop-types';
+import { List } from 'src/components';
+import { connect } from 'react-redux';
+import { t, withTheme } from '@superset-ui/core';
+import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
+import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
+import { getChartKey } from 'src/explore/exploreUtils';
+import { runAnnotationQuery } from 'src/components/Chart/chartAction';
+import CustomListItem from 'src/explore/components/controls/CustomListItem';
+import ControlPopover from '../ControlPopover/ControlPopover';
+
+const AnnotationLayer = AsyncEsmComponent(
+ () => import('./AnnotationLayer'),
+ // size of overlay inner content
+ () =>
,
+);
+
+const propTypes = {
+ colorScheme: PropTypes.string.isRequired,
+ annotationError: PropTypes.object,
+ annotationQuery: PropTypes.object,
+ vizType: PropTypes.string,
+
+ validationErrors: PropTypes.array,
+ name: PropTypes.string.isRequired,
+ actions: PropTypes.object,
+ value: PropTypes.arrayOf(PropTypes.object),
+ onChange: PropTypes.func,
+ refreshAnnotationData: PropTypes.func,
+};
+
+const defaultProps = {
+ vizType: '',
+ value: [],
+ annotationError: {},
+ annotationQuery: {},
+ onChange: () => {},
+};
+
+class AnnotationLayerControl extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ popoverVisible: {},
+ addedAnnotationIndex: null,
+ };
+ this.addAnnotationLayer = this.addAnnotationLayer.bind(this);
+ this.removeAnnotationLayer = this.removeAnnotationLayer.bind(this);
+ this.handleVisibleChange = this.handleVisibleChange.bind(this);
+ }
+
+ componentDidMount() {
+ // preload the AnotationLayer component and dependent libraries i.e. mathjs
+ AnnotationLayer.preload();
+ }
+
+ UNSAFE_componentWillReceiveProps(nextProps) {
+ const { name, annotationError, validationErrors, value } = nextProps;
+ if (Object.keys(annotationError).length && !validationErrors.length) {
+ this.props.actions.setControlValue(
+ name,
+ value,
+ Object.keys(annotationError),
+ );
+ }
+ if (!Object.keys(annotationError).length && validationErrors.length) {
+ this.props.actions.setControlValue(name, value, []);
+ }
+ }
+
+ addAnnotationLayer(originalAnnotation, newAnnotation) {
+ let annotations = this.props.value;
+ if (annotations.includes(originalAnnotation)) {
+ annotations = annotations.map(anno =>
+ anno === originalAnnotation ? newAnnotation : anno,
+ );
+ } else {
+ annotations = [...annotations, newAnnotation];
+ this.setState({ addedAnnotationIndex: annotations.length - 1 });
+ }
+
+ this.props.refreshAnnotationData({
+ annotation: newAnnotation,
+ force: true,
+ });
+
+ this.props.onChange(annotations);
+ }
+
+ handleVisibleChange(visible, popoverKey) {
+ this.setState(prevState => ({
+ popoverVisible: { ...prevState.popoverVisible, [popoverKey]: visible },
+ }));
+ }
+
+ removeAnnotationLayer(annotation) {
+ const annotations = this.props.value.filter(anno => anno !== annotation);
+ this.props.onChange(annotations);
+ }
+
+ renderPopover(popoverKey, annotation, error) {
+ const id = annotation?.name || '_new';
+
+ return (
+
+
+ this.addAnnotationLayer(annotation, newAnnotation)
+ }
+ removeAnnotationLayer={() => this.removeAnnotationLayer(annotation)}
+ close={() => {
+ this.handleVisibleChange(false, popoverKey);
+ this.setState({ addedAnnotationIndex: null });
+ }}
+ />
+
+ );
+ }
+
+ renderInfo(anno) {
+ const { annotationError, annotationQuery, theme } = this.props;
+ if (annotationQuery[anno.name]) {
+ return (
+
+ );
+ }
+ if (annotationError[anno.name]) {
+ return (
+
+ );
+ }
+ if (!anno.show) {
+ return Hidden ;
+ }
+ return '';
+ }
+
+ render() {
+ const { addedAnnotationIndex } = this.state;
+ const addedAnnotation = this.props.value[addedAnnotationIndex];
+
+ const annotations = this.props.value.map((anno, i) => (
+ ({
+ '&:hover': {
+ cursor: 'pointer',
+ backgroundColor: theme.colors.grayscale.light4,
+ },
+ })}
+ content={this.renderPopover(
+ i,
+ anno,
+ this.props.annotationError[anno.name],
+ )}
+ visible={this.state.popoverVisible[i]}
+ onVisibleChange={visible => this.handleVisibleChange(visible, i)}
+ >
+
+ {anno.name}
+ {this.renderInfo(anno)}
+
+
+ ));
+
+ const addLayerPopoverKey = 'add';
+ return (
+
+ ({ borderRadius: theme.gridUnit })}>
+ {annotations}
+
+ this.handleVisibleChange(visible, addLayerPopoverKey)
+ }
+ >
+
+ {' '}
+ {t('Add annotation layer')}
+
+
+
+
+ );
+ }
+}
+
+AnnotationLayerControl.propTypes = propTypes;
+AnnotationLayerControl.defaultProps = defaultProps;
+
+// Tried to hook this up through stores/control.jsx instead of using redux
+// directly, could not figure out how to get access to the color_scheme
+function mapStateToProps({ charts, explore }) {
+ const chartKey = getChartKey(explore);
+ const chart = charts[chartKey] || charts[0] || {};
+
+ return {
+ // eslint-disable-next-line camelcase
+ colorScheme: explore.controls?.color_scheme?.value,
+ annotationError: chart.annotationError,
+ annotationQuery: chart.annotationQuery,
+ vizType: explore.controls.viz_type.value,
+ };
+}
+
+function mapDispatchToProps(dispatch) {
+ return {
+ refreshAnnotationData: annotationObj =>
+ dispatch(runAnnotationQuery(annotationObj)),
+ };
+}
+
+const themedAnnotationLayerControl = withTheme(AnnotationLayerControl);
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(themedAnnotationLayerControl);
From 500a8995feac263be4e3ac2940584f83546ea818 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Wed, 26 Oct 2022 13:54:28 -0400
Subject: [PATCH 08/31] [CLDN-1749] adding parameter validation
---
.../plugin-chart-iframe/src/plugin/controlPanel.ts | 12 ++++++++++++
.../plugin-chart-iframe/src/plugin/transformProps.ts | 3 ++-
.../plugins/plugin-chart-iframe/src/types.ts | 1 +
3 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index 9983dd5666a2e..dda69f9c1ec07 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -183,6 +183,18 @@ const config: ControlPanelConfig = {
description: t('The name for the URL parameter.'),
},
},
+ ],
+ [
+ {
+ name: 'parameter_prefix',
+ config: {
+ type: 'TextControl',
+ label: t('Parameter Prefix'),
+ renderTrigger: true,
+ default: '',
+ description: t('A value that will be predened the parameter value.'),
+ },
+ },
]
],
},
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index b2c717fe55caa..6a654ab8b50c8 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -71,7 +71,7 @@ export default function transformProps(chartProps: ChartProps) {
*/
const formData = chartProps.formData;
- const { url, parameterColumnName, parameterName } = formData
+ const { url, parameterColumnName, parameterName, parameterPrefix } = formData
const allFilters = extractFiltersFromFormData(formData);
@@ -83,5 +83,6 @@ export default function transformProps(chartProps: ChartProps) {
url_parameter_value,
parameter_name: parameterName,
url,
+ parameter_prefix: parameterPrefix,
};
}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
index 0bbc30d050e49..bdf1feecb2fc0 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
@@ -4,4 +4,5 @@ export type IFrameVisualizationProps = QueryFormData & {
url_parameter_value: string;
parameter_name: string;
url: string;
+ parameter_prefix: string;
};
From 3ac453be23991469e5f8f2cb0540752eea923138 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 08:59:40 -0400
Subject: [PATCH 09/31] [CLDN-1749] adding error message and prefix parameter
---
.../src/IFrameVisualization.tsx | 10 +++++++---
.../src/plugin/transformProps.ts | 19 ++++++++++++++++++-
.../plugins/plugin-chart-iframe/src/types.ts | 1 +
3 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
index 659db9fa3ced8..fa1cec2d74420 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/IFrameVisualization.tsx
@@ -3,11 +3,15 @@ import { IFrameVisualizationProps } from './types';
export default function IFrameVisualization(props: IFrameVisualizationProps) {
- const { url, url_parameter_value, parameter_name } = props
+ const { url, url_parameter_value, parameter_name, parameter_prefix, errorMessage} = props
- const parserdUrlParameterName = parameter_name.includes('=') ? parameter_name : `${parameter_name}=`
+ const parserdUrlParameterName = parameter_name.includes('=') ? parameter_name : `${parameter_name}=${parameter_prefix}`
return (
-
+ <>
+ { errorMessage ?
+ <>{errorMessage}> :
+ }
+ >
);
}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 6a654ab8b50c8..5590634e664e9 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -75,14 +75,31 @@ export default function transformProps(chartProps: ChartProps) {
const allFilters = extractFiltersFromFormData(formData);
- const url_parameter_value = String(allFilters.find( e => {
+ const url_parameter_raw_value = String(allFilters.find( e => {
return e.columnName == parameterColumnName
})?.value);
+
+ let errorMessage = "";
+
+ if(Array.isArray(url_parameter_raw_value) && url_parameter_raw_value.length > 1) {
+ errorMessage = "More than one value received, please emit a single value."
+ }
+
+ if(Array.isArray(url_parameter_raw_value) && url_parameter_raw_value.length === 0) {
+ errorMessage = "No value received, please emit a single value."
+ }
+
+ if(url_parameter_raw_value === undefined || url_parameter_raw_value === "undefined") {
+ errorMessage = "No value received, please emit a single value."
+ }
+
+ const url_parameter_value = url_parameter_raw_value.toString()
return {
url_parameter_value,
parameter_name: parameterName,
url,
parameter_prefix: parameterPrefix,
+ errorMessage,
};
}
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
index bdf1feecb2fc0..bd24375ee377c 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/types.ts
@@ -5,4 +5,5 @@ export type IFrameVisualizationProps = QueryFormData & {
parameter_name: string;
url: string;
parameter_prefix: string;
+ errorMessage: string;
};
From 0e5d05be81d7d924e5cdd6aa0922dbda4521a1a7 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 09:04:55 -0400
Subject: [PATCH 10/31] [CLDN-1749] removing unused files
---
.../AnnotationLayer.jsx | 847 ------------------
.../AnnotationLayer.test.tsx | 240 -----
.../DrillToDashboardLinkConfig/index.jsx | 258 ------
3 files changed, 1345 deletions(-)
delete mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
delete mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
delete mode 100644 superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
deleted file mode 100644
index 8df36c1291ac8..0000000000000
--- a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.jsx
+++ /dev/null
@@ -1,847 +0,0 @@
-/**
- * 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 React from 'react';
-import PropTypes from 'prop-types';
-import { CompactPicker } from 'react-color';
-import Button from 'src/components/Button';
-import {
- t,
- SupersetClient,
- getCategoricalSchemeRegistry,
- getChartMetadataRegistry,
- validateNonEmpty,
- isValidExpression,
- styled,
- withTheme,
-} from '@superset-ui/core';
-
-import SelectControl from 'src/explore/components/controls/SelectControl';
-import TextControl from 'src/explore/components/controls/TextControl';
-import CheckboxControl from 'src/explore/components/controls/CheckboxControl';
-import {
- ANNOTATION_SOURCE_TYPES,
- ANNOTATION_TYPES,
- ANNOTATION_TYPES_METADATA,
- DEFAULT_ANNOTATION_TYPE,
- requiresQuery,
- ANNOTATION_SOURCE_TYPES_METADATA,
-} from 'src/modules/AnnotationTypes';
-import PopoverSection from 'src/components/PopoverSection';
-import ControlHeader from 'src/explore/components/ControlHeader';
-import { EmptyStateSmall } from 'src/components/EmptyState';
-
-const AUTOMATIC_COLOR = '';
-
-const propTypes = {
- name: PropTypes.string,
- annotationType: PropTypes.string,
- sourceType: PropTypes.string,
- color: PropTypes.string,
- opacity: PropTypes.string,
- style: PropTypes.string,
- width: PropTypes.number,
- showMarkers: PropTypes.bool,
- hideLine: PropTypes.bool,
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
- overrides: PropTypes.object,
- show: PropTypes.bool,
- showLabel: PropTypes.bool,
- titleColumn: PropTypes.string,
- descriptionColumns: PropTypes.arrayOf(PropTypes.string),
- timeColumn: PropTypes.string,
- intervalEndColumn: PropTypes.string,
- vizType: PropTypes.string,
-
- error: PropTypes.string,
- colorScheme: PropTypes.string,
-
- addAnnotationLayer: PropTypes.func,
- removeAnnotationLayer: PropTypes.func,
- close: PropTypes.func,
-};
-
-const defaultProps = {
- name: '',
- annotationType: DEFAULT_ANNOTATION_TYPE,
- sourceType: '',
- color: AUTOMATIC_COLOR,
- opacity: '',
- style: 'solid',
- width: 1,
- showMarkers: false,
- hideLine: false,
- overrides: {},
- colorScheme: 'd3Category10',
- show: true,
- showLabel: false,
- titleColumn: '',
- descriptionColumns: [],
- timeColumn: '',
- intervalEndColumn: '',
-
- addAnnotationLayer: () => {},
- removeAnnotationLayer: () => {},
- close: () => {},
-};
-
-const NotFoundContentWrapper = styled.div`
- && > div:first-child {
- padding-left: 0;
- padding-right: 0;
- }
-`;
-
-const NotFoundContent = () => (
-
-
- {t('Add an annotation layer')}{' '}
-
- {t('here')}
-
- .
-
- }
- image="empty.svg"
- />
-
-);
-
-class AnnotationLayer extends React.PureComponent {
- constructor(props) {
- super(props);
- const {
- name,
- annotationType,
- sourceType,
- color,
- opacity,
- style,
- width,
- showMarkers,
- hideLine,
- value,
- overrides,
- show,
- showLabel,
- titleColumn,
- descriptionColumns,
- timeColumn,
- intervalEndColumn,
- vizType,
- } = props;
-
- // Only allow override whole time_range
- if ('since' in overrides || 'until' in overrides) {
- overrides.time_range = null;
- delete overrides.since;
- delete overrides.until;
- }
-
- // Check if annotationType is supported by this chart
- const metadata = getChartMetadataRegistry().get(vizType);
- const supportedAnnotationTypes = metadata?.supportedAnnotationTypes || [];
- const validAnnotationType = supportedAnnotationTypes.includes(
- annotationType,
- )
- ? annotationType
- : supportedAnnotationTypes[0];
-
- this.state = {
- // base
- name,
- annotationType: validAnnotationType,
- sourceType,
- value,
- overrides,
- show,
- showLabel,
- // slice
- titleColumn,
- descriptionColumns,
- timeColumn,
- intervalEndColumn,
- // display
- color: color || AUTOMATIC_COLOR,
- opacity,
- style,
- width,
- showMarkers,
- hideLine,
- // refData
- isNew: !name,
- isLoadingOptions: true,
- valueOptions: [],
- };
- this.submitAnnotation = this.submitAnnotation.bind(this);
- this.deleteAnnotation = this.deleteAnnotation.bind(this);
- this.applyAnnotation = this.applyAnnotation.bind(this);
- this.fetchOptions = this.fetchOptions.bind(this);
- this.handleAnnotationType = this.handleAnnotationType.bind(this);
- this.handleAnnotationSourceType =
- this.handleAnnotationSourceType.bind(this);
- this.handleValue = this.handleValue.bind(this);
- this.isValidForm = this.isValidForm.bind(this);
- }
-
- componentDidMount() {
- const { annotationType, sourceType, isLoadingOptions } = this.state;
- this.fetchOptions(annotationType, sourceType, isLoadingOptions);
- }
-
- componentDidUpdate(prevProps, prevState) {
- if (prevState.sourceType !== this.state.sourceType) {
- this.fetchOptions(this.state.annotationType, this.state.sourceType, true);
- }
- }
-
- getSupportedSourceTypes(annotationType) {
- // Get vis types that can be source.
- const sources = getChartMetadataRegistry()
- .entries()
- .filter(({ value: chartMetadata }) =>
- chartMetadata.canBeAnnotationType(annotationType),
- )
- .map(({ key, value: chartMetadata }) => ({
- value: key,
- label: chartMetadata.name,
- }));
- // Prepend native source if applicable
- if (ANNOTATION_TYPES_METADATA[annotationType]?.supportNativeSource) {
- sources.unshift(ANNOTATION_SOURCE_TYPES_METADATA.NATIVE);
- }
- return sources;
- }
-
- isValidFormulaAnnotation(expression, annotationType) {
- if (annotationType === ANNOTATION_TYPES.FORMULA) {
- return isValidExpression(expression);
- }
- return true;
- }
-
- isValidForm() {
- const {
- name,
- annotationType,
- sourceType,
- value,
- timeColumn,
- intervalEndColumn,
- } = this.state;
- const errors = [
- validateNonEmpty(name),
- validateNonEmpty(annotationType),
- validateNonEmpty(value),
- ];
- if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE) {
- if (annotationType === ANNOTATION_TYPES.EVENT) {
- errors.push(validateNonEmpty(timeColumn));
- }
- if (annotationType === ANNOTATION_TYPES.INTERVAL) {
- errors.push(validateNonEmpty(timeColumn));
- errors.push(validateNonEmpty(intervalEndColumn));
- }
- }
- errors.push(!this.isValidFormulaAnnotation(value, annotationType));
- return !errors.filter(x => x).length;
- }
-
- handleAnnotationType(annotationType) {
- this.setState({
- annotationType,
- sourceType: null,
- value: null,
- });
- }
-
- handleAnnotationSourceType(sourceType) {
- const { sourceType: prevSourceType } = this.state;
-
- if (prevSourceType !== sourceType) {
- this.setState({ sourceType, value: null, isLoadingOptions: true });
- }
- }
-
- handleValue(value) {
- this.setState({
- value,
- descriptionColumns: [],
- intervalEndColumn: null,
- timeColumn: null,
- titleColumn: null,
- overrides: { time_range: null },
- });
- }
-
- fetchOptions(annotationType, sourceType, isLoadingOptions) {
- if (isLoadingOptions) {
- if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
- SupersetClient.get({
- endpoint: '/annotationlayermodelview/api/read?',
- }).then(({ json }) => {
- const layers = json
- ? json.result.map(layer => ({
- value: layer.id,
- label: layer.name,
- }))
- : [];
- this.setState({
- isLoadingOptions: false,
- valueOptions: layers,
- });
- });
- } else if (requiresQuery(sourceType)) {
- SupersetClient.get({ endpoint: '/superset/user_slices' }).then(
- ({ json }) => {
- const registry = getChartMetadataRegistry();
- this.setState({
- isLoadingOptions: false,
- valueOptions: json
- .filter(x => {
- const metadata = registry.get(x.viz_type);
- return (
- metadata && metadata.canBeAnnotationType(annotationType)
- );
- })
- .map(x => ({ value: x.id, label: x.title, slice: x })),
- });
- },
- );
- } else {
- this.setState({
- isLoadingOptions: false,
- valueOptions: [],
- });
- }
- }
- }
-
- deleteAnnotation() {
- this.props.removeAnnotationLayer();
- this.props.close();
- }
-
- applyAnnotation() {
- if (this.isValidForm()) {
- const annotationFields = [
- 'name',
- 'annotationType',
- 'sourceType',
- 'color',
- 'opacity',
- 'style',
- 'width',
- 'showMarkers',
- 'hideLine',
- 'value',
- 'overrides',
- 'show',
- 'showLabel',
- 'titleColumn',
- 'descriptionColumns',
- 'timeColumn',
- 'intervalEndColumn',
- ];
- const newAnnotation = {};
- annotationFields.forEach(field => {
- if (this.state[field] !== null) {
- newAnnotation[field] = this.state[field];
- }
- });
-
- if (newAnnotation.color === AUTOMATIC_COLOR) {
- newAnnotation.color = null;
- }
-
- this.props.addAnnotationLayer(newAnnotation);
- this.setState({ isNew: false });
- }
- }
-
- submitAnnotation() {
- this.applyAnnotation();
- this.props.close();
- }
-
- renderOption(option) {
- return (
-
- {option.label}
-
- );
- }
-
- renderValueConfiguration() {
- const {
- annotationType,
- sourceType,
- value,
- valueOptions,
- isLoadingOptions,
- } = this.state;
- let label = '';
- let description = '';
- if (requiresQuery(sourceType)) {
- if (sourceType === ANNOTATION_SOURCE_TYPES.NATIVE) {
- label = 'Annotation layer';
- description = 'Select the Annotation Layer you would like to use.';
- } else {
- label = t('Chart');
- description = t(
- `Use another existing chart as a source for annotations and overlays.
- Your chart must be one of these visualization types: [%s]`,
- this.getSupportedSourceTypes(annotationType)
- .map(x => x.label)
- .join(', '),
- );
- }
- } else if (annotationType === ANNOTATION_TYPES.FORMULA) {
- label = 'Formula';
- description = `Expects a formula with depending time parameter 'x'
- in milliseconds since epoch. mathjs is used to evaluate the formulas.
- Example: '2x+5'`;
- }
- if (requiresQuery(sourceType)) {
- return (
- }
- />
- );
- }
- if (annotationType === ANNOTATION_TYPES.FORMULA) {
- return (
-
- );
- }
- return '';
- }
-
- renderSliceConfiguration() {
- const {
- annotationType,
- sourceType,
- value,
- valueOptions,
- overrides,
- titleColumn,
- timeColumn,
- intervalEndColumn,
- descriptionColumns,
- } = this.state;
- const { slice } = valueOptions.find(x => x.value === value) || {};
- if (sourceType !== ANNOTATION_SOURCE_TYPES.NATIVE && slice) {
- const columns = (slice.data.groupby || [])
- .concat(slice.data.all_columns || [])
- .map(x => ({ value: x, label: x }));
- const timeColumnOptions = slice.data.include_time
- ? [{ value: '__timestamp', label: '__timestamp' }].concat(columns)
- : columns;
- return (
-
-
- {(annotationType === ANNOTATION_TYPES.EVENT ||
- annotationType === ANNOTATION_TYPES.INTERVAL) && (
- this.setState({ timeColumn: v })}
- />
- )}
- {annotationType === ANNOTATION_TYPES.INTERVAL && (
- this.setState({ intervalEndColumn: value })}
- />
- )}
- this.setState({ titleColumn: value })}
- />
- {annotationType !== ANNOTATION_TYPES.TIME_SERIES && (
- this.setState({ descriptionColumns: value })}
- />
- )}
-
- {
- delete overrides.time_range;
- if (v) {
- this.setState({
- overrides: { ...overrides, time_range: null },
- });
- } else {
- this.setState({ overrides: { ...overrides } });
- }
- }}
- />
- {
- delete overrides.time_grain_sqla;
- delete overrides.granularity;
- if (v) {
- this.setState({
- overrides: {
- ...overrides,
- time_grain_sqla: null,
- granularity: null,
- },
- });
- } else {
- this.setState({ overrides: { ...overrides } });
- }
- }}
- />
-
- this.setState({ overrides: { ...overrides, time_shift: v } })
- }
- />
-
-
-
- );
- }
- return '';
- }
-
- renderDisplayConfiguration() {
- const {
- color,
- opacity,
- style,
- width,
- showMarkers,
- hideLine,
- annotationType,
- } = this.state;
- const colorScheme = getCategoricalSchemeRegistry()
- .get(this.props.colorScheme)
- .colors.concat();
- if (
- color &&
- color !== AUTOMATIC_COLOR &&
- !colorScheme.find(x => x.toLowerCase() === color.toLowerCase())
- ) {
- colorScheme.push(color);
- }
- return (
-
- this.setState({ style: v })}
- />
- this.setState({ opacity: value })}
- />
-
-
-
- this.setState({ color: v.hex })}
- />
- this.setState({ color: AUTOMATIC_COLOR })}
- >
- Automatic Color
-
-
-
- this.setState({ width: v })}
- />
- {annotationType === ANNOTATION_TYPES.TIME_SERIES && (
- this.setState({ showMarkers: v })}
- />
- )}
- {annotationType === ANNOTATION_TYPES.TIME_SERIES && (
- this.setState({ hideLine: v })}
- />
- )}
-
- );
- }
-
- render() {
- const { isNew, name, annotationType, sourceType, show, showLabel } =
- this.state;
- const isValid = this.isValidForm();
- const metadata = getChartMetadataRegistry().get(this.props.vizType);
- const supportedAnnotationTypes = metadata
- ? metadata.supportedAnnotationTypes.map(
- type => ANNOTATION_TYPES_METADATA[type],
- )
- : [];
- const supportedSourceTypes = this.getSupportedSourceTypes(annotationType);
-
- return (
- <>
- {this.props.error && (
-
- ERROR: {this.props.error}
-
- )}
-
-
-
- this.setState({ name: v })}
- validationErrors={!name ? [t('Mandatory')] : []}
- />
- this.setState({ show: !v })}
- />
- this.setState({ showLabel: v })}
- />
-
- {supportedSourceTypes.length > 0 && (
- }
- value={sourceType}
- onChange={this.handleAnnotationSourceType}
- validationErrors={!sourceType ? [t('Mandatory')] : []}
- />
- )}
- {this.renderValueConfiguration()}
-
-
- {this.renderSliceConfiguration()}
- {this.renderDisplayConfiguration()}
-
-
- {isNew ? (
-
this.props.close()}>
- {t('Cancel')}
-
- ) : (
-
- {t('Remove')}
-
- )}
-
-
- {t('Apply')}
-
-
-
- {t('OK')}
-
-
-
- >
- );
- }
-}
-
-AnnotationLayer.propTypes = propTypes;
-AnnotationLayer.defaultProps = defaultProps;
-
-export default withTheme(AnnotationLayer);
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
deleted file mode 100644
index ed8ae44339b2e..0000000000000
--- a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/AnnotationLayer.test.tsx
+++ /dev/null
@@ -1,240 +0,0 @@
-/**
- * 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 React from 'react';
-import { render, screen, waitFor } from 'spec/helpers/testing-library';
-import userEvent from '@testing-library/user-event';
-import { getChartMetadataRegistry, ChartMetadata } from '@superset-ui/core';
-import fetchMock from 'fetch-mock';
-import setupColors from 'src/setup/setupColors';
-import { ANNOTATION_TYPES_METADATA } from 'src/modules/AnnotationTypes';
-import AnnotationLayer from './AnnotationLayer';
-
-const defaultProps = {
- value: '',
- vizType: 'table',
- annotationType: ANNOTATION_TYPES_METADATA.FORMULA.value,
-};
-
-beforeAll(() => {
- const supportedAnnotationTypes = Object.values(ANNOTATION_TYPES_METADATA).map(
- value => value.value,
- );
-
- fetchMock.get('glob:*/annotationlayermodelview/api/read?*', {
- result: [{ label: 'Chart A', value: 'a' }],
- });
-
- fetchMock.get('glob:*/superset/user_slices*', [
- { id: 'a', title: 'Chart A', viz_type: 'table', data: {} },
- ]);
-
- setupColors();
-
- getChartMetadataRegistry().registerValue(
- 'table',
- new ChartMetadata({
- name: 'Table',
- thumbnail: '',
- supportedAnnotationTypes,
- canBeAnnotationTypes: ['EVENT'],
- }),
- );
-});
-
-const waitForRender = (props?: any) =>
- waitFor(() => render( ));
-
-test('renders with default props', async () => {
- await waitForRender();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
- expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
- expect(screen.getByRole('button', { name: 'Cancel' })).toBeEnabled();
-});
-
-test('renders extra checkboxes when type is time series', async () => {
- await waitForRender();
- expect(
- screen.queryByRole('button', { name: 'Show Markers' }),
- ).not.toBeInTheDocument();
- expect(
- screen.queryByRole('button', { name: 'Hide Line' }),
- ).not.toBeInTheDocument();
- userEvent.click(screen.getAllByText('Formula')[0]);
- userEvent.click(screen.getByText('Time series'));
- expect(
- screen.getByRole('button', { name: 'Show Markers' }),
- ).toBeInTheDocument();
- expect(screen.getByRole('button', { name: 'Hide Line' })).toBeInTheDocument();
-});
-
-test('enables apply and ok buttons', async () => {
- const { container } = render( );
-
- waitFor(() => {
- expect(container).toBeInTheDocument();
- });
-
- const nameInput = screen.getByRole('textbox', { name: 'Name' });
- const formulaInput = screen.getByRole('textbox', { name: 'Formula' });
-
- expect(nameInput).toBeInTheDocument();
- expect(formulaInput).toBeInTheDocument();
-
- userEvent.type(nameInput, 'Name');
- userEvent.type(formulaInput, '2x');
-
- waitFor(() => {
- expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
- expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
- });
-});
-
-test('triggers addAnnotationLayer when apply button is clicked', async () => {
- const addAnnotationLayer = jest.fn();
- await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer });
- userEvent.click(screen.getByRole('button', { name: 'Apply' }));
- expect(addAnnotationLayer).toHaveBeenCalled();
-});
-
-test('triggers addAnnotationLayer and close when ok button is clicked', async () => {
- const addAnnotationLayer = jest.fn();
- const close = jest.fn();
- await waitForRender({ name: 'Test', value: '2x', addAnnotationLayer, close });
- userEvent.click(screen.getByRole('button', { name: 'OK' }));
- expect(addAnnotationLayer).toHaveBeenCalled();
- expect(close).toHaveBeenCalled();
-});
-
-test('triggers close when cancel button is clicked', async () => {
- const close = jest.fn();
- await waitForRender({ close });
- userEvent.click(screen.getByRole('button', { name: 'Cancel' }));
- expect(close).toHaveBeenCalled();
-});
-
-test('triggers removeAnnotationLayer and close when remove button is clicked', async () => {
- const removeAnnotationLayer = jest.fn();
- const close = jest.fn();
- await waitForRender({
- name: 'Test',
- value: '2x',
- removeAnnotationLayer,
- close,
- });
- userEvent.click(screen.getByRole('button', { name: 'Remove' }));
- expect(removeAnnotationLayer).toHaveBeenCalled();
- expect(close).toHaveBeenCalled();
-});
-
-test('renders chart options', async () => {
- await waitForRender({
- annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
- });
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation source type' }),
- );
- userEvent.click(screen.getByText('Superset annotation'));
- expect(screen.getByText('Annotation layer')).toBeInTheDocument();
-
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation source type' }),
- );
- userEvent.click(screen.getByText('Table'));
- expect(screen.getByText('Chart')).toBeInTheDocument();
-});
-
-test('keeps apply disabled when missing required fields', async () => {
- await waitForRender({
- annotationType: ANNOTATION_TYPES_METADATA.EVENT.value,
- sourceType: 'Table',
- });
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation layer value' }),
- );
- userEvent.click(await screen.findByText('Chart A'));
- expect(
- screen.getByText('Annotation Slice Configuration'),
- ).toBeInTheDocument();
-
- userEvent.click(screen.getByRole('button', { name: 'Automatic Color' }));
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation layer title column' }),
- );
- userEvent.click(screen.getByText('None'));
- userEvent.click(screen.getByText('Style'));
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation layer stroke' }),
- );
- userEvent.click(screen.getByText('Dashed'));
- userEvent.click(screen.getByText('Opacity'));
- userEvent.click(
- screen.getByRole('combobox', { name: 'Annotation layer opacity' }),
- );
- userEvent.click(screen.getByText('0.5'));
-
- const checkboxes = screen.getAllByRole('checkbox');
- checkboxes.forEach(checkbox => userEvent.click(checkbox));
-
- expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
-});
-
-test.skip('Disable apply button if formula is incorrect', async () => {
- // TODO: fix flaky test that passes locally but fails on CI
- await waitForRender({ name: 'test' });
-
- userEvent.clear(screen.getByLabelText('Formula'));
- userEvent.type(screen.getByLabelText('Formula'), 'x+1');
- await waitFor(() => {
- expect(screen.getByLabelText('Formula')).toHaveValue('x+1');
- expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
- });
-
- userEvent.clear(screen.getByLabelText('Formula'));
- userEvent.type(screen.getByLabelText('Formula'), 'y = x*2+1');
- await waitFor(() => {
- expect(screen.getByLabelText('Formula')).toHaveValue('y = x*2+1');
- expect(screen.getByRole('button', { name: 'OK' })).toBeEnabled();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeEnabled();
- });
-
- userEvent.clear(screen.getByLabelText('Formula'));
- userEvent.type(screen.getByLabelText('Formula'), 'y+1');
- await waitFor(() => {
- expect(screen.getByLabelText('Formula')).toHaveValue('y+1');
- expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
- });
-
- userEvent.clear(screen.getByLabelText('Formula'));
- userEvent.type(screen.getByLabelText('Formula'), 'x+');
- await waitFor(() => {
- expect(screen.getByLabelText('Formula')).toHaveValue('x+');
- expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
- });
-
- userEvent.clear(screen.getByLabelText('Formula'));
- userEvent.type(screen.getByLabelText('Formula'), 'y = z+1');
- await waitFor(() => {
- expect(screen.getByLabelText('Formula')).toHaveValue('y = z+1');
- expect(screen.getByRole('button', { name: 'OK' })).toBeDisabled();
- expect(screen.getByRole('button', { name: 'Apply' })).toBeDisabled();
- });
-});
diff --git a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx b/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
deleted file mode 100644
index f1381abee1aa4..0000000000000
--- a/superset-frontend/src/explore/components/controls/DrillToDashboardLinkConfig/index.jsx
+++ /dev/null
@@ -1,258 +0,0 @@
-/**
- * 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 React from 'react';
-import PropTypes from 'prop-types';
-import { List } from 'src/components';
-import { connect } from 'react-redux';
-import { t, withTheme } from '@superset-ui/core';
-import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
-import AsyncEsmComponent from 'src/components/AsyncEsmComponent';
-import { getChartKey } from 'src/explore/exploreUtils';
-import { runAnnotationQuery } from 'src/components/Chart/chartAction';
-import CustomListItem from 'src/explore/components/controls/CustomListItem';
-import ControlPopover from '../ControlPopover/ControlPopover';
-
-const AnnotationLayer = AsyncEsmComponent(
- () => import('./AnnotationLayer'),
- // size of overlay inner content
- () =>
,
-);
-
-const propTypes = {
- colorScheme: PropTypes.string.isRequired,
- annotationError: PropTypes.object,
- annotationQuery: PropTypes.object,
- vizType: PropTypes.string,
-
- validationErrors: PropTypes.array,
- name: PropTypes.string.isRequired,
- actions: PropTypes.object,
- value: PropTypes.arrayOf(PropTypes.object),
- onChange: PropTypes.func,
- refreshAnnotationData: PropTypes.func,
-};
-
-const defaultProps = {
- vizType: '',
- value: [],
- annotationError: {},
- annotationQuery: {},
- onChange: () => {},
-};
-
-class AnnotationLayerControl extends React.PureComponent {
- constructor(props) {
- super(props);
- this.state = {
- popoverVisible: {},
- addedAnnotationIndex: null,
- };
- this.addAnnotationLayer = this.addAnnotationLayer.bind(this);
- this.removeAnnotationLayer = this.removeAnnotationLayer.bind(this);
- this.handleVisibleChange = this.handleVisibleChange.bind(this);
- }
-
- componentDidMount() {
- // preload the AnotationLayer component and dependent libraries i.e. mathjs
- AnnotationLayer.preload();
- }
-
- UNSAFE_componentWillReceiveProps(nextProps) {
- const { name, annotationError, validationErrors, value } = nextProps;
- if (Object.keys(annotationError).length && !validationErrors.length) {
- this.props.actions.setControlValue(
- name,
- value,
- Object.keys(annotationError),
- );
- }
- if (!Object.keys(annotationError).length && validationErrors.length) {
- this.props.actions.setControlValue(name, value, []);
- }
- }
-
- addAnnotationLayer(originalAnnotation, newAnnotation) {
- let annotations = this.props.value;
- if (annotations.includes(originalAnnotation)) {
- annotations = annotations.map(anno =>
- anno === originalAnnotation ? newAnnotation : anno,
- );
- } else {
- annotations = [...annotations, newAnnotation];
- this.setState({ addedAnnotationIndex: annotations.length - 1 });
- }
-
- this.props.refreshAnnotationData({
- annotation: newAnnotation,
- force: true,
- });
-
- this.props.onChange(annotations);
- }
-
- handleVisibleChange(visible, popoverKey) {
- this.setState(prevState => ({
- popoverVisible: { ...prevState.popoverVisible, [popoverKey]: visible },
- }));
- }
-
- removeAnnotationLayer(annotation) {
- const annotations = this.props.value.filter(anno => anno !== annotation);
- this.props.onChange(annotations);
- }
-
- renderPopover(popoverKey, annotation, error) {
- const id = annotation?.name || '_new';
-
- return (
-
-
- this.addAnnotationLayer(annotation, newAnnotation)
- }
- removeAnnotationLayer={() => this.removeAnnotationLayer(annotation)}
- close={() => {
- this.handleVisibleChange(false, popoverKey);
- this.setState({ addedAnnotationIndex: null });
- }}
- />
-
- );
- }
-
- renderInfo(anno) {
- const { annotationError, annotationQuery, theme } = this.props;
- if (annotationQuery[anno.name]) {
- return (
-
- );
- }
- if (annotationError[anno.name]) {
- return (
-
- );
- }
- if (!anno.show) {
- return Hidden ;
- }
- return '';
- }
-
- render() {
- const { addedAnnotationIndex } = this.state;
- const addedAnnotation = this.props.value[addedAnnotationIndex];
-
- const annotations = this.props.value.map((anno, i) => (
- ({
- '&:hover': {
- cursor: 'pointer',
- backgroundColor: theme.colors.grayscale.light4,
- },
- })}
- content={this.renderPopover(
- i,
- anno,
- this.props.annotationError[anno.name],
- )}
- visible={this.state.popoverVisible[i]}
- onVisibleChange={visible => this.handleVisibleChange(visible, i)}
- >
-
- {anno.name}
- {this.renderInfo(anno)}
-
-
- ));
-
- const addLayerPopoverKey = 'add';
- return (
-
- ({ borderRadius: theme.gridUnit })}>
- {annotations}
-
- this.handleVisibleChange(visible, addLayerPopoverKey)
- }
- >
-
- {' '}
- {t('Add annotation layer')}
-
-
-
-
- );
- }
-}
-
-AnnotationLayerControl.propTypes = propTypes;
-AnnotationLayerControl.defaultProps = defaultProps;
-
-// Tried to hook this up through stores/control.jsx instead of using redux
-// directly, could not figure out how to get access to the color_scheme
-function mapStateToProps({ charts, explore }) {
- const chartKey = getChartKey(explore);
- const chart = charts[chartKey] || charts[0] || {};
-
- return {
- // eslint-disable-next-line camelcase
- colorScheme: explore.controls?.color_scheme?.value,
- annotationError: chart.annotationError,
- annotationQuery: chart.annotationQuery,
- vizType: explore.controls.viz_type.value,
- };
-}
-
-function mapDispatchToProps(dispatch) {
- return {
- refreshAnnotationData: annotationObj =>
- dispatch(runAnnotationQuery(annotationObj)),
- };
-}
-
-const themedAnnotationLayerControl = withTheme(AnnotationLayerControl);
-
-export default connect(
- mapStateToProps,
- mapDispatchToProps,
-)(themedAnnotationLayerControl);
From 8cafe2d75b00655cacb82d38a5f23912a1187c91 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 09:38:59 -0400
Subject: [PATCH 11/31] [CLDN-1749] adding temp base image for docker
deployment
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index 336d2e43b2c87..6ed31bef6f981 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:cccs-2.0_20221005132212_b5040
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221101132159_b5252
USER root
From 72157a39bf38c1235345b306376347935f2b43cb Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 10:56:00 -0400
Subject: [PATCH 12/31] [CLDN-1749] Better error handling and new icon
---
.../src/images/thumbnail.png | Bin 5658 -> 4545 bytes
.../src/plugin/controlPanel.ts | 58 ++++++++++--------
.../src/plugin/transformProps.ts | 6 +-
3 files changed, 36 insertions(+), 28 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
index 7afef30bd4e6e4f85723208bf9f429647d03d3e5..92214739762aa56018c2eca5bccc87133ba811fc 100644
GIT binary patch
literal 4545
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
literal 5658
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
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index dda69f9c1ec07..dc5c9e198483d 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -115,31 +115,6 @@ const config: ControlPanelConfig = {
label: t('Query'),
expanded: true,
controlSetRows: [
- ['adhoc_filters'],
- [
- {
- name: 'metrics',
- override: {
- // visibility: () => true,
- validators: [],
- mapStateToProps: (
- state: ControlPanelState,
- controlState: ControlState,
- ) => {
- const { controls } = state;
- const originalMapStateToProps =
- sharedControls?.metrics?.mapStateToProps;
- const newState =
- originalMapStateToProps?.(state, controlState) ?? {};
- newState.externalValidationErrors = validateAggControlValues(
- controls,
- [controlState.value],
- );
- return newState;
- },
- },
- },
- ],
[
{
name: 'row_limit',
@@ -154,6 +129,17 @@ const config: ControlPanelConfig = {
config: {
type: 'TextControl',
label: t('URL'),
+ mapStateToProps: (
+ state: ControlPanelState,
+ controlState: ControlState,
+ ) => {
+ const originalMapStateToProps =
+ sharedControls?.groupby?.mapStateToProps;
+ const newState =
+ originalMapStateToProps?.(state, controlState) ?? {};
+ newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for URL."]
+ return newState;
+ },
renderTrigger: true,
default: '',
description: t('The Base URL for the Iframe.'),
@@ -166,6 +152,17 @@ const config: ControlPanelConfig = {
config: {
type: 'TextControl',
label: t('Parameter Column Name'),
+ mapStateToProps: (
+ state: ControlPanelState,
+ controlState: ControlState,
+ ) => {
+ const originalMapStateToProps =
+ sharedControls?.groupby?.mapStateToProps;
+ const newState =
+ originalMapStateToProps?.(state, controlState) ?? {};
+ newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for Parameter Column Name."]
+ return newState;
+ },
renderTrigger: true,
default: '',
description: t('The Column name for the value that will populate the url parameter.'),
@@ -178,6 +175,17 @@ const config: ControlPanelConfig = {
config: {
type: 'TextControl',
label: t('Parameter Name'),
+ mapStateToProps: (
+ state: ControlPanelState,
+ controlState: ControlState,
+ ) => {
+ const originalMapStateToProps =
+ sharedControls?.groupby?.mapStateToProps;
+ const newState =
+ originalMapStateToProps?.(state, controlState) ?? {};
+ newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for Parameter Name."]
+ return newState;
+ },
renderTrigger: true,
default: '',
description: t('The name for the URL parameter.'),
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 5590634e664e9..15aa7fefeb9e8 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -75,9 +75,9 @@ export default function transformProps(chartProps: ChartProps) {
const allFilters = extractFiltersFromFormData(formData);
- const url_parameter_raw_value = String(allFilters.find( e => {
+ const url_parameter_raw_value = allFilters.find( e => {
return e.columnName == parameterColumnName
- })?.value);
+ })?.value;
let errorMessage = "";
@@ -93,7 +93,7 @@ export default function transformProps(chartProps: ChartProps) {
errorMessage = "No value received, please emit a single value."
}
- const url_parameter_value = url_parameter_raw_value.toString()
+ const url_parameter_value = String(url_parameter_raw_value)
return {
url_parameter_value,
From ff47239c01e40dae68340bfc237e3d0dbb619cec Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 11:44:25 -0400
Subject: [PATCH 13/31] [CLDN-1749] remove unused imports
---
.../plugin-chart-iframe/src/plugin/controlPanel.ts | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index dc5c9e198483d..b9d9324a81573 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -16,23 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core';
+import { t, validateNonEmpty } from '@superset-ui/core';
import {
ControlPanelConfig,
ControlPanelState,
ControlState,
- ControlStateMapping,
sharedControls,
} from '@superset-ui/chart-controls';
-const validateAggControlValues = (
- controls: ControlStateMapping,
- values: any[],
-) => {
- const areControlsEmpty = values.every(val => ensureIsArray(val).length === 0);
- // @ts-ignore
- return areControlsEmpty ? [t('Metrics must have a value')] : [];
-};
const config: ControlPanelConfig = {
/**
From 734a521c3a73b7a9adaa392b3c419f8f15fd3ed3 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 1 Nov 2022 12:34:28 -0400
Subject: [PATCH 14/31] temp dockerfile change
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index 94fe074fd06af..ee3218e704870 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221101132159_b5252
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221101154707_b5260
From 12371dabe4f6b16af9caa173075c331ad5690c76 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 08:04:33 -0500
Subject: [PATCH 15/31] [CLDN-1749] Adding the adhoc filters back in
---
.../src/plugin/controlPanel.ts | 40 ++++++++++++++++++-
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index b9d9324a81573..dd8513f57633d 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -16,16 +16,27 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { t, validateNonEmpty } from '@superset-ui/core';
+import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core';
import {
ControlPanelConfig,
ControlPanelState,
ControlState,
+ ControlStateMapping,
sharedControls,
} from '@superset-ui/chart-controls';
+const validateAggControlValues = (
+ controls: ControlStateMapping,
+ values: any[],
+) => {
+ const areControlsEmpty = values.every(val => ensureIsArray(val).length === 0);
+ // @ts-ignore
+ return areControlsEmpty ? [t('Metrics must have a value')] : [];
+};
+
const config: ControlPanelConfig = {
+
/**
* The control panel is split into two tabs: "Query" and
* "Chart Options". The controls that define the inputs to
@@ -99,13 +110,38 @@ const config: ControlPanelConfig = {
* - validateInteger: must be an integer value
* - validateNumber: must be an intger or decimal value
*/
-
+
// For control input types, see: superset-frontend/src/explore/components/controls/index.js
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
+ ['adhoc_filters'],
+ [
+ {
+ name: 'metrics',
+ override: {
+ // visibility: () => true,
+ validators: [],
+ mapStateToProps: (
+ state: ControlPanelState,
+ controlState: ControlState,
+ ) => {
+ const { controls } = state;
+ const originalMapStateToProps =
+ sharedControls?.metrics?.mapStateToProps;
+ const newState =
+ originalMapStateToProps?.(state, controlState) ?? {};
+ newState.externalValidationErrors = validateAggControlValues(
+ controls,
+ [controlState.value],
+ );
+ return newState;
+ },
+ },
+ },
+ ],
[
{
name: 'row_limit',
From 2f136526b40d596255924f409a3ad6b25fa5b6c5 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 08:59:12 -0500
Subject: [PATCH 16/31] [CLDN-1749] Updating image
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index ee3218e704870..04b412bed79db 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221101154707_b5260
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108131049_b5344
From 265268af171c388a4ab4b2c291025b1ef80b3ac6 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 09:32:42 -0500
Subject: [PATCH 17/31] [CLDN-1749] Adding new thumbnail
---
.../src/images/thumbnail.png | Bin 4545 -> 1547 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/images/thumbnail.png
index 92214739762aa56018c2eca5bccc87133ba811fc..b3c8eb2228ba700df9fdf3ddeab66af86d572d0f 100644
GIT binary patch
literal 1547
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
From d186cdac8a84e3c8aec49a91dfa38126ee18a0d4 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 10:02:04 -0500
Subject: [PATCH 18/31] Updating dockerfile
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index 04b412bed79db..1fb75991fd708 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108131049_b5344
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108143342_b5350
From 0d40c5e6d26697c1863f2e5e3ebc849ee77d370a Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 12:19:41 -0500
Subject: [PATCH 19/31] [CLDN-1749] Removing uneeded control panel elements
---
.../src/plugin/buildQuery.ts | 58 +++++++++++++++++++
.../src/plugin/controlPanel.ts | 32 ----------
.../plugin-chart-iframe/src/plugin/index.ts | 2 +
3 files changed, 60 insertions(+), 32 deletions(-)
create mode 100644 superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
new file mode 100644
index 0000000000000..f0eade2b4e34e
--- /dev/null
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
@@ -0,0 +1,58 @@
+/**
+ * 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 { buildQueryContext, QueryFormData } from '@superset-ui/core';
+
+ /**
+ * The buildQuery function is used to create an instance of QueryContext that's
+ * sent to the chart data endpoint. In addition to containing information of which
+ * datasource to use, it specifies the type (e.g. full payload, samples, query) and
+ * format (e.g. CSV or JSON) of the result and whether or not to force refresh the data from
+ * the datasource as opposed to using a cached copy of the data, if available.
+ *
+ * More importantly though, QueryContext contains a property `queries`, which is an array of
+ * QueryObjects specifying individual data requests to be made. A QueryObject specifies which
+ * columns, metrics and filters, among others, to use during the query. Usually it will be enough
+ * to specify just one query based on the baseQueryObject, but for some more advanced use cases
+ * it is possible to define post processing operations in the QueryObject, or multiple queries
+ * if a viz needs multiple different result sets.
+ */
+ export default function buildQuery(formData: QueryFormData) {
+ /*
+ We receive an ip as a filter, our job is to find everthing there is to know about that ip
+ We fire multiple queries to multiple data sets and collect the results here.
+ */
+
+ const formDataCopy = {
+ ...formData,
+ result_type: 'post_processed',
+ };
+
+ return buildQueryContext(formDataCopy, baseQueryObject => {
+ // RAW mode (not aggregated)
+ // eslint-disable-next-line no-param-reassign
+ baseQueryObject.metrics = ["count"];
+
+ return [
+ {
+ ...baseQueryObject,
+ },
+ ];
+ });
+ }
+
\ No newline at end of file
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index dd8513f57633d..0e48a381141fb 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -118,38 +118,6 @@ const config: ControlPanelConfig = {
expanded: true,
controlSetRows: [
['adhoc_filters'],
- [
- {
- name: 'metrics',
- override: {
- // visibility: () => true,
- validators: [],
- mapStateToProps: (
- state: ControlPanelState,
- controlState: ControlState,
- ) => {
- const { controls } = state;
- const originalMapStateToProps =
- sharedControls?.metrics?.mapStateToProps;
- const newState =
- originalMapStateToProps?.(state, controlState) ?? {};
- newState.externalValidationErrors = validateAggControlValues(
- controls,
- [controlState.value],
- );
- return newState;
- },
- },
- },
- ],
- [
- {
- name: 'row_limit',
- override: {
- default: 1,
- },
- },
- ],
[
{
name: 'url',
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts
index 42d621626fac2..0efe549552fcb 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/index.ts
@@ -19,6 +19,7 @@
import { t, ChartMetadata, ChartPlugin } from '@superset-ui/core';
import controlPanel from './controlPanel';
import transformProps from './transformProps';
+import buildQuery from './buildQuery';
import thumbnail from '../images/thumbnail.png';
export default class IFrameVisualizationChartPlugin extends ChartPlugin {
@@ -40,6 +41,7 @@ export default class IFrameVisualizationChartPlugin extends ChartPlugin {
});
super({
+ buildQuery,
controlPanel,
loadChart: () => import('../IFrameVisualization'),
metadata,
From 29753ce51b9a45c30d6f29f723f01517d4760dae Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 12:38:00 -0500
Subject: [PATCH 20/31] [CLDN-1749] Fixing build errors
---
.../plugin-chart-iframe/src/plugin/controlPanel.ts | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index 0e48a381141fb..a7f86d64d41e7 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -16,25 +16,14 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core';
+import { t, validateNonEmpty } from '@superset-ui/core';
import {
ControlPanelConfig,
ControlPanelState,
ControlState,
- ControlStateMapping,
sharedControls,
} from '@superset-ui/chart-controls';
-
-const validateAggControlValues = (
- controls: ControlStateMapping,
- values: any[],
-) => {
- const areControlsEmpty = values.every(val => ensureIsArray(val).length === 0);
- // @ts-ignore
- return areControlsEmpty ? [t('Metrics must have a value')] : [];
-};
-
const config: ControlPanelConfig = {
/**
From 7c212c9d6ae69e5658d317b225b10c34460118ec Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 12:51:53 -0500
Subject: [PATCH 21/31] [CLDN-1749] New image
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index 1fb75991fd708..dfd70644e528a 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108143342_b5350
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108173907_b5357
From 747b8f4a2668dbc78656ea28570e0d3b4284efc1 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 14:34:09 -0500
Subject: [PATCH 22/31] Change to use data from dataset
---
.../src/plugin/buildQuery.ts | 3 +-
.../src/plugin/controlPanel.ts | 19 ++++++++-----
.../src/plugin/transformProps.ts | 28 +++++++++----------
3 files changed, 27 insertions(+), 23 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
index f0eade2b4e34e..22405e6d1202f 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/buildQuery.ts
@@ -46,11 +46,10 @@
return buildQueryContext(formDataCopy, baseQueryObject => {
// RAW mode (not aggregated)
// eslint-disable-next-line no-param-reassign
- baseQueryObject.metrics = ["count"];
-
return [
{
...baseQueryObject,
+ row_limit: 10,
},
];
});
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index a7f86d64d41e7..8aacb844ea08c 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { t, validateNonEmpty } from '@superset-ui/core';
+import { ensureIsArray, t, validateNonEmpty } from '@superset-ui/core';
import {
ControlPanelConfig,
ControlPanelState,
@@ -24,6 +24,8 @@ import {
sharedControls,
} from '@superset-ui/chart-controls';
+import { StyledColumnOption } from 'src/explore/components/optionRenderers';
+
const config: ControlPanelConfig = {
/**
@@ -132,10 +134,16 @@ const config: ControlPanelConfig = {
],
[
{
- name: 'parameter_column_name',
+ name: 'groupby',
config: {
- type: 'TextControl',
+ type: 'SelectControl',
label: t('Parameter Column Name'),
+ description: sharedControls.groupby.description,
+ multi: false,
+ allowAll: false,
+ default: [],
+ valueKey: 'column_name',
+ includeTime: false,
mapStateToProps: (
state: ControlPanelState,
controlState: ControlState,
@@ -144,12 +152,9 @@ const config: ControlPanelConfig = {
sharedControls?.groupby?.mapStateToProps;
const newState =
originalMapStateToProps?.(state, controlState) ?? {};
- newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for Parameter Column Name."]
+ newState.externalValidationErrors = ensureIsArray(controlState.value).length > 0 ? [] : ["Please add a value for Parameter Column Name."]
return newState;
},
- renderTrigger: true,
- default: '',
- description: t('The Column name for the value that will populate the url parameter.'),
},
},
],
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 15aa7fefeb9e8..71bfddc20e814 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ChartProps, PlainObject, } from '@superset-ui/core';
+import { ChartProps, PlainObject, TimeseriesDataRecord, } from '@superset-ui/core';
const extractFiltersFromFormData = (formData: PlainObject): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] })[] => {
@@ -70,33 +70,33 @@ export default function transformProps(chartProps: ChartProps) {
* be seen until restarting the development server.
*/
const formData = chartProps.formData;
+ const queriesData = chartProps.queriesData;
+
- const { url, parameterColumnName, parameterName, parameterPrefix } = formData
- const allFilters = extractFiltersFromFormData(formData);
-
- const url_parameter_raw_value = allFilters.find( e => {
- return e.columnName == parameterColumnName
- })?.value;
-
+ const { url, parameterName, parameterPrefix, groupby } = formData
+
+ const data = queriesData[0]?.data as TimeseriesDataRecord[];
+
+ let value: string | number | true | Date = ""
let errorMessage = "";
- if(Array.isArray(url_parameter_raw_value) && url_parameter_raw_value.length > 1) {
+ if(Array.isArray(data) && data.length > 1) {
errorMessage = "More than one value received, please emit a single value."
}
- if(Array.isArray(url_parameter_raw_value) && url_parameter_raw_value.length === 0) {
+ if(Array.isArray(data) && data.length === 0) {
errorMessage = "No value received, please emit a single value."
}
- if(url_parameter_raw_value === undefined || url_parameter_raw_value === "undefined") {
- errorMessage = "No value received, please emit a single value."
+ if(Array.isArray(data) && data.length === 1) {
+ value = data[0][groupby] || ""
}
- const url_parameter_value = String(url_parameter_raw_value)
+
return {
- url_parameter_value,
+ url_parameter_value: value,
parameter_name: parameterName,
url,
parameter_prefix: parameterPrefix,
From 5fea9975dceed9c35e2e56cd53beb534a0e7e8ed Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 14:35:23 -0500
Subject: [PATCH 23/31] Removing unsed function
---
.../src/plugin/transformProps.ts | 23 +------------------
1 file changed, 1 insertion(+), 22 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index 71bfddc20e814..f2f8c955f0b55 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -16,28 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-import { ChartProps, PlainObject, TimeseriesDataRecord, } from '@superset-ui/core';
-
-
-const extractFiltersFromFormData = (formData: PlainObject): ({columnName: string, value: string | number | boolean | (string | number | boolean)[] })[] => {
-
- const filters = [...(formData?.adhocFilters || []), ...(formData?.extraFormData?.adhocFilters || []), ...(formData?.extraFormData?.filters || [])]
-
- const simpleAdhocFilters = filters.reduce(
- (acc, filter) => {
-
- if ( ("subject" in filter) && ("comparator" in filter) ) {
- acc.push( {columnName: filter.subject, value: filter.comparator} )
- }
- else if ( ("col" in filter) && ("val" in filter) ) {
- acc.push( {columnName: filter.col.toString(), value: filter.val} )
- }
- return acc
- }, <({columnName: string, value: string | number | boolean | (string | number | boolean)[]})[]> []
- )
-
- return simpleAdhocFilters
-}
+import { ChartProps, TimeseriesDataRecord, } from '@superset-ui/core';
export default function transformProps(chartProps: ChartProps) {
/**
From dc6f914a56bfc6ce06327f89216f8cabe558513a Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 14:37:34 -0500
Subject: [PATCH 24/31] Fixing typos
---
.../plugins/plugin-chart-iframe/src/plugin/controlPanel.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index 8aacb844ea08c..176fdfeb9cb1a 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -138,7 +138,7 @@ const config: ControlPanelConfig = {
config: {
type: 'SelectControl',
label: t('Parameter Column Name'),
- description: sharedControls.groupby.description,
+ description: "The name of the column that will populate the url parameter value.",
multi: false,
allowAll: false,
default: [],
@@ -189,7 +189,7 @@ const config: ControlPanelConfig = {
label: t('Parameter Prefix'),
renderTrigger: true,
default: '',
- description: t('A value that will be predened the parameter value.'),
+ description: t('A value that will be prefix the parameter value.'),
},
},
]
From 833e0da6019466023601f76b7b8ac16f7924a6b1 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 14:49:16 -0500
Subject: [PATCH 25/31] renove unused import
---
.../plugins/plugin-chart-iframe/src/plugin/controlPanel.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index 176fdfeb9cb1a..6298ba8b24170 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -24,8 +24,6 @@ import {
sharedControls,
} from '@superset-ui/chart-controls';
-import { StyledColumnOption } from 'src/explore/components/optionRenderers';
-
const config: ControlPanelConfig = {
/**
From cfc151f32efb78efa94fd7b766551aaeba8de340 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 8 Nov 2022 15:02:46 -0500
Subject: [PATCH 26/31] updating image
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index dfd70644e528a..896f0802edc32 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108173907_b5357
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108195038_b5370
From 6418431572b0338e51c7bc8bedbc4ca1470b37c7 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Mon, 14 Nov 2022 14:08:08 -0500
Subject: [PATCH 27/31] error message and label fixes
---
.../plugins/plugin-chart-iframe/src/plugin/controlPanel.ts | 6 +-----
.../plugin-chart-iframe/src/plugin/transformProps.ts | 4 ++--
2 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
index 6298ba8b24170..5c7a9df66fbce 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/controlPanel.ts
@@ -133,14 +133,12 @@ const config: ControlPanelConfig = {
[
{
name: 'groupby',
- config: {
- type: 'SelectControl',
+ override: {
label: t('Parameter Column Name'),
description: "The name of the column that will populate the url parameter value.",
multi: false,
allowAll: false,
default: [],
- valueKey: 'column_name',
includeTime: false,
mapStateToProps: (
state: ControlPanelState,
@@ -173,7 +171,6 @@ const config: ControlPanelConfig = {
newState.externalValidationErrors = controlState.value ? [] : ["Please add a value for Parameter Name."]
return newState;
},
- renderTrigger: true,
default: '',
description: t('The name for the URL parameter.'),
},
@@ -185,7 +182,6 @@ const config: ControlPanelConfig = {
config: {
type: 'TextControl',
label: t('Parameter Prefix'),
- renderTrigger: true,
default: '',
description: t('A value that will be prefix the parameter value.'),
},
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index f2f8c955f0b55..e851ad5d7ad0a 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -61,11 +61,11 @@ export default function transformProps(chartProps: ChartProps) {
let errorMessage = "";
if(Array.isArray(data) && data.length > 1) {
- errorMessage = "More than one value received, please emit a single value."
+ errorMessage = "The query returned too many rows when only one was expected."
}
if(Array.isArray(data) && data.length === 0) {
- errorMessage = "No value received, please emit a single value."
+ errorMessage = "The query returned no rows."
}
if(Array.isArray(data) && data.length === 1) {
From 23d1b54116be28694944e79c3959d0d4de13e928 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Mon, 14 Nov 2022 15:42:04 -0500
Subject: [PATCH 28/31] updating image
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index 896f0802edc32..ad8ff8deeb9c9 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221108195038_b5370
+FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221114192347_b5421
From 81b4f4177baaca79eb56851e2ca53614a8d01c45 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Tue, 15 Nov 2022 11:46:25 -0500
Subject: [PATCH 29/31] Update cccs-build/superset/Dockerfile
Co-authored-by: cccs-Dustin <96579982+cccs-Dustin@users.noreply.github.com>
---
cccs-build/superset/Dockerfile | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cccs-build/superset/Dockerfile b/cccs-build/superset/Dockerfile
index ad8ff8deeb9c9..6abb7e38ea3dd 100644
--- a/cccs-build/superset/Dockerfile
+++ b/cccs-build/superset/Dockerfile
@@ -1,7 +1,7 @@
# Vault CA container import
ARG VAULT_CA_CONTAINER=uchimera.azurecr.io/cccs/hogwarts/vault-ca:master_2921_22315d60
FROM $VAULT_CA_CONTAINER AS vault_ca
-FROM uchimera.azurecr.io/cccs/superset-base:feature_CLDN-1749_20221114192347_b5421
+FROM uchimera.azurecr.io/cccs/superset-base:cccs-2.0_20221014182839_b5135
From 3c433c25798efbf34cbd209de1ec7925978ad93c Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Thu, 1 Dec 2022 08:17:00 -0500
Subject: [PATCH 30/31] Update
superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
Co-authored-by: cccs-RyanK <102618419+cccs-RyanK@users.noreply.github.com>
---
.../plugins/plugin-chart-iframe/src/plugin/transformProps.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index e851ad5d7ad0a..d655ab5c61d3a 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -50,8 +50,6 @@ export default function transformProps(chartProps: ChartProps) {
*/
const formData = chartProps.formData;
const queriesData = chartProps.queriesData;
-
-
const { url, parameterName, parameterPrefix, groupby } = formData
From 31e83ac085adc4a8c453a4a5661f218f3c776693 Mon Sep 17 00:00:00 2001
From: cccs-RyanS <71385290+cccs-RyanS@users.noreply.github.com>
Date: Thu, 1 Dec 2022 08:17:10 -0500
Subject: [PATCH 31/31] Update
superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
Co-authored-by: cccs-RyanK <102618419+cccs-RyanK@users.noreply.github.com>
---
.../plugins/plugin-chart-iframe/src/plugin/transformProps.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
index d655ab5c61d3a..ee67ef9d2aff7 100644
--- a/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
+++ b/superset-frontend/src/cccs-viz/plugins/plugin-chart-iframe/src/plugin/transformProps.ts
@@ -69,8 +69,6 @@ export default function transformProps(chartProps: ChartProps) {
if(Array.isArray(data) && data.length === 1) {
value = data[0][groupby] || ""
}
-
-
return {
url_parameter_value: value,