You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by vi...@apache.org on 2024/02/05 19:35:38 UTC

(superset) branch cartodiagram-plugin-2023-11-03 updated: fix linting issues

This is an automated email from the ASF dual-hosted git repository.

villebro pushed a commit to branch cartodiagram-plugin-2023-11-03
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/cartodiagram-plugin-2023-11-03 by this push:
     new a9822702f7 fix linting issues
a9822702f7 is described below

commit a9822702f76313a6d5e065f776541da4191cc9ce
Author: Ville Brofeldt <vi...@apple.com>
AuthorDate: Mon Feb 5 11:35:27 2024 -0800

    fix linting issues
---
 .../src/operators/contributionOperator.ts          |  25 +-
 .../src/operators/timeCompareOperator.ts           |  41 +-
 .../src/operators/timeComparePivotOperator.ts      |  51 +-
 .../Chart/DrillBy/useDisplayModeToggle.tsx         |   4 +-
 .../src/components/TableSelector/index.tsx         |   5 +-
 .../src/components/UiConfigContext/index.tsx       |  31 +-
 .../LayerConfigsPopoverContent.tsx                 | 681 ++++++++++-----------
 .../MetricControl/AdhocMetricEditPopoverTitle.tsx  | 135 ++--
 .../alerts/components/AlertReportCronScheduler.tsx | 135 ++--
 .../features/queries/SavedQueryPreviewModal.tsx    | 133 ++--
 10 files changed, 615 insertions(+), 626 deletions(-)

diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/contributionOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/contributionOperator.ts
index a72a17be6b..39fa9c4433 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/contributionOperator.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/contributionOperator.ts
@@ -20,16 +20,15 @@ import { PostProcessingContribution } from '@superset-ui/core';
 import { PostProcessingFactory } from './types';
 
 /* eslint-disable @typescript-eslint/no-unused-vars */
-export const contributionOperator: PostProcessingFactory<
-  PostProcessingContribution
-> = (formData, queryObject) => {
-  if (formData.contributionMode) {
-    return {
-      operation: 'contribution',
-      options: {
-        orientation: formData.contributionMode,
-      },
-    };
-  }
-  return undefined;
-};
+export const contributionOperator: PostProcessingFactory<PostProcessingContribution> =
+  (formData, queryObject) => {
+    if (formData.contributionMode) {
+      return {
+        operation: 'contribution',
+        options: {
+          orientation: formData.contributionMode,
+        },
+      };
+    }
+    return undefined;
+  };
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts
index a0d028bfa2..da72c664c9 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeCompareOperator.ts
@@ -21,26 +21,25 @@ import { ComparisonType, PostProcessingCompare } from '@superset-ui/core';
 import { getMetricOffsetsMap, isTimeComparison } from './utils';
 import { PostProcessingFactory } from './types';
 
-export const timeCompareOperator: PostProcessingFactory<
-  PostProcessingCompare
-> = (formData, queryObject) => {
-  const comparisonType = formData.comparison_type;
-  const metricOffsetMap = getMetricOffsetsMap(formData, queryObject);
+export const timeCompareOperator: PostProcessingFactory<PostProcessingCompare> =
+  (formData, queryObject) => {
+    const comparisonType = formData.comparison_type;
+    const metricOffsetMap = getMetricOffsetsMap(formData, queryObject);
 
-  if (
-    isTimeComparison(formData, queryObject) &&
-    comparisonType !== ComparisonType.Values
-  ) {
-    return {
-      operation: 'compare',
-      options: {
-        source_columns: Array.from(metricOffsetMap.values()),
-        compare_columns: Array.from(metricOffsetMap.keys()),
-        compare_type: comparisonType,
-        drop_original_columns: true,
-      },
-    };
-  }
+    if (
+      isTimeComparison(formData, queryObject) &&
+      comparisonType !== ComparisonType.Values
+    ) {
+      return {
+        operation: 'compare',
+        options: {
+          source_columns: Array.from(metricOffsetMap.values()),
+          compare_columns: Array.from(metricOffsetMap.keys()),
+          compare_type: comparisonType,
+          drop_original_columns: true,
+        },
+      };
+    }
 
-  return undefined;
-};
+    return undefined;
+  };
diff --git a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts
index 33b821bc17..a6214901aa 100644
--- a/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts
+++ b/superset-frontend/packages/superset-ui-chart-controls/src/operators/timeComparePivotOperator.ts
@@ -27,32 +27,31 @@ import {
 import { getMetricOffsetsMap, isTimeComparison } from './utils';
 import { PostProcessingFactory } from './types';
 
-export const timeComparePivotOperator: PostProcessingFactory<
-  PostProcessingPivot
-> = (formData, queryObject) => {
-  const metricOffsetMap = getMetricOffsetsMap(formData, queryObject);
-  const xAxisLabel = getXAxisLabel(formData);
-  const columns = queryObject.series_columns || queryObject.columns;
+export const timeComparePivotOperator: PostProcessingFactory<PostProcessingPivot> =
+  (formData, queryObject) => {
+    const metricOffsetMap = getMetricOffsetsMap(formData, queryObject);
+    const xAxisLabel = getXAxisLabel(formData);
+    const columns = queryObject.series_columns || queryObject.columns;
 
-  if (isTimeComparison(formData, queryObject) && xAxisLabel) {
-    const aggregates = Object.fromEntries(
-      [...metricOffsetMap.values(), ...metricOffsetMap.keys()].map(metric => [
-        metric,
-        // use the 'mean' aggregates to avoid drop NaN
-        { operator: 'mean' as NumpyFunction },
-      ]),
-    );
+    if (isTimeComparison(formData, queryObject) && xAxisLabel) {
+      const aggregates = Object.fromEntries(
+        [...metricOffsetMap.values(), ...metricOffsetMap.keys()].map(metric => [
+          metric,
+          // use the 'mean' aggregates to avoid drop NaN
+          { operator: 'mean' as NumpyFunction },
+        ]),
+      );
 
-    return {
-      operation: 'pivot',
-      options: {
-        index: [xAxisLabel],
-        columns: ensureIsArray(columns).map(getColumnLabel),
-        drop_missing_columns: !formData?.show_empty_columns,
-        aggregates,
-      },
-    };
-  }
+      return {
+        operation: 'pivot',
+        options: {
+          index: [xAxisLabel],
+          columns: ensureIsArray(columns).map(getColumnLabel),
+          drop_missing_columns: !formData?.show_empty_columns,
+          aggregates,
+        },
+      };
+    }
 
-  return undefined;
-};
+    return undefined;
+  };
diff --git a/superset-frontend/src/components/Chart/DrillBy/useDisplayModeToggle.tsx b/superset-frontend/src/components/Chart/DrillBy/useDisplayModeToggle.tsx
index 4886437ab1..9ca1351544 100644
--- a/superset-frontend/src/components/Chart/DrillBy/useDisplayModeToggle.tsx
+++ b/superset-frontend/src/components/Chart/DrillBy/useDisplayModeToggle.tsx
@@ -32,9 +32,7 @@ export const useDisplayModeToggle = () => {
       <div
         css={(theme: SupersetTheme) => css`
           margin-bottom: ${theme.gridUnit * 6}px;
-          .ant-radio-button-wrapper-checked:not(
-              .ant-radio-button-wrapper-disabled
-            ):focus-within {
+          .ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):focus-within {
             box-shadow: none;
           }
         `}
diff --git a/superset-frontend/src/components/TableSelector/index.tsx b/superset-frontend/src/components/TableSelector/index.tsx
index 2598d4df23..f36056a4a2 100644
--- a/superset-frontend/src/components/TableSelector/index.tsx
+++ b/superset-frontend/src/components/TableSelector/index.tsx
@@ -339,8 +339,7 @@ const TableSelector: FunctionComponent<TableSelectorProps> = ({
   );
 };
 
-export const TableSelectorMultiple: FunctionComponent<
-  TableSelectorProps
-> = props => <TableSelector tableSelectMode="multiple" {...props} />;
+export const TableSelectorMultiple: FunctionComponent<TableSelectorProps> =
+  props => <TableSelector tableSelectMode="multiple" {...props} />;
 
 export default TableSelector;
diff --git a/superset-frontend/src/components/UiConfigContext/index.tsx b/superset-frontend/src/components/UiConfigContext/index.tsx
index 7e82ca7f08..3943cde46c 100644
--- a/superset-frontend/src/components/UiConfigContext/index.tsx
+++ b/superset-frontend/src/components/UiConfigContext/index.tsx
@@ -39,20 +39,19 @@ export const UiConfigContext = createContext<UiConfigType>({
 
 export const useUiConfig = () => useContext(UiConfigContext);
 
-export const EmbeddedUiConfigProvider: React.FC<
-  EmbeddedUiConfigProviderProps
-> = ({ children }) => {
-  const config = getUrlParam(URL_PARAMS.uiConfig) || 0;
-  const [embeddedConfig] = useState({
-    hideTitle: (config & 1) !== 0,
-    hideTab: (config & 2) !== 0,
-    hideNav: (config & 4) !== 0,
-    hideChartControls: (config & 8) !== 0,
-  });
+export const EmbeddedUiConfigProvider: React.FC<EmbeddedUiConfigProviderProps> =
+  ({ children }) => {
+    const config = getUrlParam(URL_PARAMS.uiConfig) || 0;
+    const [embeddedConfig] = useState({
+      hideTitle: (config & 1) !== 0,
+      hideTab: (config & 2) !== 0,
+      hideNav: (config & 4) !== 0,
+      hideChartControls: (config & 8) !== 0,
+    });
 
-  return (
-    <UiConfigContext.Provider value={embeddedConfig}>
-      {children}
-    </UiConfigContext.Provider>
-  );
-};
+    return (
+      <UiConfigContext.Provider value={embeddedConfig}>
+        {children}
+      </UiConfigContext.Provider>
+    );
+  };
diff --git a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsPopoverContent.tsx b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsPopoverContent.tsx
index 734c3c8847..c6e8bceef6 100644
--- a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsPopoverContent.tsx
+++ b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerConfigsPopoverContent.tsx
@@ -126,381 +126,380 @@ export const StyledSaveButton = styled(Button)`
   `}
 `;
 
-export const LayerConfigsPopoverContent: React.FC<
-  LayerConfigsPopoverContentProps
-> = ({ onClose = () => {}, onSave = () => {}, layerConf }) => {
-  const [currentLayerConf, setCurrentLayerConf] =
-    useState<LayerConf>(layerConf);
-  const initialWmsVersion =
-    layerConf.type === 'WMS' ? layerConf.version : undefined;
-  const [wmsVersion, setWmsVersion] = useState<string | undefined>(
-    initialWmsVersion,
-  );
-  const initialWfsVersion =
-    layerConf.type === 'WFS' ? layerConf.version : undefined;
-  const [wfsVersion, setWfsVersion] = useState<string | undefined>(
-    initialWfsVersion,
-  );
-  const [geostylerData, setGeoStylerData] = useState<GsData | undefined>(
-    undefined,
-  );
-
-  const serviceVersions = getServiceVersions();
-
-  // This is needed to force mounting the form every time
-  // we get a new layerConf prop. Otherwise the input fields
-  // will not be updated properly, since ControlFormItem only
-  // recognises the `value` property once and then handles the
-  // values in its on state. Remounting creates a new component
-  // and thereby starts with a fresh state.
-  const [formKey, setFormKey] = useState<number>(0);
-
-  useEffect(() => {
-    setCurrentLayerConf({ ...layerConf });
-    setFormKey(oldFormKey => oldFormKey + 1);
-  }, [layerConf]);
-
-  const onFieldValueChange = (value: JsonValue, key: string) => {
-    setCurrentLayerConf({
-      ...currentLayerConf,
-      [key]: value,
-    });
-  };
-
-  const onLayerTypeChange = (value: LayerConf['type']) => {
-    if (value === 'WFS') {
-      setCurrentLayerConf({
-        ...currentLayerConf,
-        type: value,
-        version: serviceVersions[value][0],
-        style: {
-          name: 'Default Style',
-          rules: [
-            {
-              name: 'Default Rule',
-              symbolizers: [
-                {
-                  kind: 'Line',
-                  // eslint-disable-next-line theme-colors/no-literal-colors
-                  color: '#000000',
-                  width: 2,
-                },
-                {
-                  kind: 'Mark',
-                  wellKnownName: 'circle',
-                  // eslint-disable-next-line theme-colors/no-literal-colors
-                  color: '#000000',
-                },
-                {
-                  kind: 'Fill',
-                  // eslint-disable-next-line theme-colors/no-literal-colors
-                  color: '#000000',
-                },
-              ],
-            },
-          ],
-        },
-      } as WfsLayerConf);
-    } else if (value === 'XYZ') {
+export const LayerConfigsPopoverContent: React.FC<LayerConfigsPopoverContentProps> =
+  ({ onClose = () => {}, onSave = () => {}, layerConf }) => {
+    const [currentLayerConf, setCurrentLayerConf] =
+      useState<LayerConf>(layerConf);
+    const initialWmsVersion =
+      layerConf.type === 'WMS' ? layerConf.version : undefined;
+    const [wmsVersion, setWmsVersion] = useState<string | undefined>(
+      initialWmsVersion,
+    );
+    const initialWfsVersion =
+      layerConf.type === 'WFS' ? layerConf.version : undefined;
+    const [wfsVersion, setWfsVersion] = useState<string | undefined>(
+      initialWfsVersion,
+    );
+    const [geostylerData, setGeoStylerData] = useState<GsData | undefined>(
+      undefined,
+    );
+
+    const serviceVersions = getServiceVersions();
+
+    // This is needed to force mounting the form every time
+    // we get a new layerConf prop. Otherwise the input fields
+    // will not be updated properly, since ControlFormItem only
+    // recognises the `value` property once and then handles the
+    // values in its on state. Remounting creates a new component
+    // and thereby starts with a fresh state.
+    const [formKey, setFormKey] = useState<number>(0);
+
+    useEffect(() => {
+      setCurrentLayerConf({ ...layerConf });
+      setFormKey(oldFormKey => oldFormKey + 1);
+    }, [layerConf]);
+
+    const onFieldValueChange = (value: JsonValue, key: string) => {
       setCurrentLayerConf({
         ...currentLayerConf,
-        type: value,
-      } as XyzLayerConf);
-    } else {
-      setCurrentLayerConf({
-        ...currentLayerConf,
-        type: value,
-        version: serviceVersions[value][0],
-      } as WmsLayerConf);
-    }
-  };
+        [key]: value,
+      });
+    };
 
-  const onLayerTitleChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'title');
-  };
+    const onLayerTypeChange = (value: LayerConf['type']) => {
+      if (value === 'WFS') {
+        setCurrentLayerConf({
+          ...currentLayerConf,
+          type: value,
+          version: serviceVersions[value][0],
+          style: {
+            name: 'Default Style',
+            rules: [
+              {
+                name: 'Default Rule',
+                symbolizers: [
+                  {
+                    kind: 'Line',
+                    // eslint-disable-next-line theme-colors/no-literal-colors
+                    color: '#000000',
+                    width: 2,
+                  },
+                  {
+                    kind: 'Mark',
+                    wellKnownName: 'circle',
+                    // eslint-disable-next-line theme-colors/no-literal-colors
+                    color: '#000000',
+                  },
+                  {
+                    kind: 'Fill',
+                    // eslint-disable-next-line theme-colors/no-literal-colors
+                    color: '#000000',
+                  },
+                ],
+              },
+            ],
+          },
+        } as WfsLayerConf);
+      } else if (value === 'XYZ') {
+        setCurrentLayerConf({
+          ...currentLayerConf,
+          type: value,
+        } as XyzLayerConf);
+      } else {
+        setCurrentLayerConf({
+          ...currentLayerConf,
+          type: value,
+          version: serviceVersions[value][0],
+        } as WmsLayerConf);
+      }
+    };
 
-  const onLayerUrlChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'url');
-  };
+    const onLayerTitleChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'title');
+    };
 
-  const onLayersParamChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'layersParam');
-  };
+    const onLayerUrlChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'url');
+    };
 
-  const onTypeNameChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'typeName');
-  };
+    const onLayersParamChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'layersParam');
+    };
 
-  const onWmsVersionChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'version');
-    setWmsVersion(fieldValue);
-  };
+    const onTypeNameChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'typeName');
+    };
 
-  const onWfsVersionChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'version');
-    setWfsVersion(fieldValue);
-  };
+    const onWmsVersionChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'version');
+      setWmsVersion(fieldValue);
+    };
 
-  const onMaxFeaturesChange = (fieldValue: number) => {
-    onFieldValueChange(fieldValue, 'maxFeatures');
-  };
+    const onWfsVersionChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'version');
+      setWfsVersion(fieldValue);
+    };
 
-  const onStyleChange = (fieldValue: GsStyle) => {
-    onFieldValueChange(fieldValue, 'style');
-  };
+    const onMaxFeaturesChange = (fieldValue: number) => {
+      onFieldValueChange(fieldValue, 'maxFeatures');
+    };
 
-  const onAttributionChange = (fieldValue: string) => {
-    onFieldValueChange(fieldValue, 'attribution');
-  };
+    const onStyleChange = (fieldValue: GsStyle) => {
+      onFieldValueChange(fieldValue, 'style');
+    };
 
-  const onCloseClick = () => {
-    onClose();
-  };
+    const onAttributionChange = (fieldValue: string) => {
+      onFieldValueChange(fieldValue, 'attribution');
+    };
 
-  const onSaveClick = () => {
-    const baseConfs: BaseLayerConf = {
-      title: currentLayerConf.title,
-      url: currentLayerConf.url,
-      type: currentLayerConf.type,
-      attribution: currentLayerConf.attribution,
+    const onCloseClick = () => {
+      onClose();
     };
 
-    let conf: LayerConf;
-    if (isWmsLayerConf(currentLayerConf)) {
-      conf = {
-        ...baseConfs,
-        version: currentLayerConf.version,
-        type: currentLayerConf.type,
-        layersParam: currentLayerConf.layersParam,
-      };
-    } else if (isXyzLayerConf(currentLayerConf)) {
-      conf = {
-        ...baseConfs,
-        type: currentLayerConf.type,
-      };
-    } else {
-      conf = {
-        ...baseConfs,
+    const onSaveClick = () => {
+      const baseConfs: BaseLayerConf = {
+        title: currentLayerConf.title,
+        url: currentLayerConf.url,
         type: currentLayerConf.type,
-        version: currentLayerConf.version,
-        typeName: currentLayerConf.typeName,
-        maxFeatures: currentLayerConf.maxFeatures,
-        style: currentLayerConf.style,
+        attribution: currentLayerConf.attribution,
       };
-    }
-
-    onSave(conf);
-  };
 
-  useEffect(() => {
-    if (
-      !isWfsLayerConf(currentLayerConf) ||
-      !hasAllRequiredWfsParams(currentLayerConf)
-    ) {
-      setGeoStylerData(undefined);
-      return undefined;
-    }
+      let conf: LayerConf;
+      if (isWmsLayerConf(currentLayerConf)) {
+        conf = {
+          ...baseConfs,
+          version: currentLayerConf.version,
+          type: currentLayerConf.type,
+          layersParam: currentLayerConf.layersParam,
+        };
+      } else if (isXyzLayerConf(currentLayerConf)) {
+        conf = {
+          ...baseConfs,
+          type: currentLayerConf.type,
+        };
+      } else {
+        conf = {
+          ...baseConfs,
+          type: currentLayerConf.type,
+          version: currentLayerConf.version,
+          typeName: currentLayerConf.typeName,
+          maxFeatures: currentLayerConf.maxFeatures,
+          style: currentLayerConf.style,
+        };
+      }
 
-    const readWfsData = async (conf: WfsLayerConf) => {
-      const wfsParser = new WfsDataParser();
-      try {
-        let requestParams: RequestParams1_1_0 | RequestParams2_0_0 = {} as
-          | RequestParams1_1_0
-          | RequestParams2_0_0;
-        if (conf.version.startsWith('1.')) {
-          requestParams = {
-            version: conf.version as RequestParams1_1_0['version'],
-            maxFeatures: conf.maxFeatures,
-            typeName: conf.typeName,
-          };
-        }
-        if (conf.version.startsWith('2.')) {
-          requestParams = {
-            version: conf.version as RequestParams2_0_0['version'],
-            count: conf.maxFeatures,
-            typeNames: conf.typeName,
-          };
-        }
+      onSave(conf);
+    };
 
-        const gsData = await wfsParser.readData({
-          url: conf.url,
-          requestParams,
-        });
-        setGeoStylerData(gsData);
-      } catch {
-        console.warn('Could not read geostyler data');
+    useEffect(() => {
+      if (
+        !isWfsLayerConf(currentLayerConf) ||
+        !hasAllRequiredWfsParams(currentLayerConf)
+      ) {
         setGeoStylerData(undefined);
+        return undefined;
       }
-    };
 
-    // debounce function
-    const timer = setTimeout(() => readWfsData(currentLayerConf), 500);
+      const readWfsData = async (conf: WfsLayerConf) => {
+        const wfsParser = new WfsDataParser();
+        try {
+          let requestParams: RequestParams1_1_0 | RequestParams2_0_0 = {} as
+            | RequestParams1_1_0
+            | RequestParams2_0_0;
+          if (conf.version.startsWith('1.')) {
+            requestParams = {
+              version: conf.version as RequestParams1_1_0['version'],
+              maxFeatures: conf.maxFeatures,
+              typeName: conf.typeName,
+            };
+          }
+          if (conf.version.startsWith('2.')) {
+            requestParams = {
+              version: conf.version as RequestParams2_0_0['version'],
+              count: conf.maxFeatures,
+              typeNames: conf.typeName,
+            };
+          }
+
+          const gsData = await wfsParser.readData({
+            url: conf.url,
+            requestParams,
+          });
+          setGeoStylerData(gsData);
+        } catch {
+          console.warn('Could not read geostyler data');
+          setGeoStylerData(undefined);
+        }
+      };
 
-    return () => {
-      clearTimeout(timer);
-    };
-  }, [currentLayerConf]);
-
-  const layerTabLabel = t('Layer');
-  const styleTabLabel = t('Style');
-  const layerTypeLabel = t('Layer type');
-  const layerTypeDescription = t('The type of the layer');
-  const serviceVersionLabel = t('Service version');
-  const serviceVersionDescription = t('The version of the service');
-  const layersParamLabel = t('Layer Name');
-  const layersParamDescription = t(
-    'The name of the layer as described in GetCapabilities',
-  );
-  const layersParamPlaceholder = t('Layer Name');
-  const layerTitleLabel = t('Layer title');
-  const layerTitleDescription = t('The visible title of the layer');
-  const layerTitlePlaceholder = t('Insert Layer title');
-  const layerUrlLabel = t('Layer URL');
-  const layerUrlDescription = t('The service url of the layer');
-  const layerUrlPlaceholder = t('Insert Layer URL');
-  const maxFeaturesLabel = t('Max. features');
-  const maxFeaturesDescription = t(
-    'Maximum number of features to fetch from service',
-  );
-  const maxFeaturesPlaceholder = t('10000');
-  const attributionLabel = t('Attribution');
-  const attributionDescription = t('The layer attribution');
-  const attributionPlaceholder = t('© Layer attribution');
-
-  const wmsVersionOptions: { value: any; label: string }[] =
-    serviceVersions.WMS.map(version => ({ value: version, label: version }));
-  const wfsVersionOptions: { value: any; label: string }[] =
-    serviceVersions.WFS.map(version => ({ value: version, label: version }));
-
-  return (
-    <div>
-      <Form key={JSON.stringify(formKey)}>
-        <Tabs defaultActiveKey={LAYER_CONFIG_TABS.LAYER}>
-          <Tabs.TabPane tab={layerTabLabel} key={LAYER_CONFIG_TABS.LAYER}>
-            <StyledControlFormItem
-              controlType="Input"
-              label={layerUrlLabel}
-              description={layerUrlDescription}
-              placeholder={layerUrlPlaceholder}
-              value={currentLayerConf.url}
-              name="url"
-              onChange={onLayerUrlChange}
-            />
-            <StyledControlFormItem
-              controlType="Select"
-              label={layerTypeLabel}
-              description={layerTypeDescription}
-              options={[
-                { value: 'WMS', label: t('WMS') },
-                { value: 'WFS', label: t('WFS') },
-                { value: 'XYZ', label: t('XYZ') },
-              ]}
-              value={currentLayerConf.type}
-              defaultValue={currentLayerConf.type}
-              name="type"
-              onChange={onLayerTypeChange}
-            />
-            {isWmsLayerConf(currentLayerConf) && (
+      // debounce function
+      const timer = setTimeout(() => readWfsData(currentLayerConf), 500);
+
+      return () => {
+        clearTimeout(timer);
+      };
+    }, [currentLayerConf]);
+
+    const layerTabLabel = t('Layer');
+    const styleTabLabel = t('Style');
+    const layerTypeLabel = t('Layer type');
+    const layerTypeDescription = t('The type of the layer');
+    const serviceVersionLabel = t('Service version');
+    const serviceVersionDescription = t('The version of the service');
+    const layersParamLabel = t('Layer Name');
+    const layersParamDescription = t(
+      'The name of the layer as described in GetCapabilities',
+    );
+    const layersParamPlaceholder = t('Layer Name');
+    const layerTitleLabel = t('Layer title');
+    const layerTitleDescription = t('The visible title of the layer');
+    const layerTitlePlaceholder = t('Insert Layer title');
+    const layerUrlLabel = t('Layer URL');
+    const layerUrlDescription = t('The service url of the layer');
+    const layerUrlPlaceholder = t('Insert Layer URL');
+    const maxFeaturesLabel = t('Max. features');
+    const maxFeaturesDescription = t(
+      'Maximum number of features to fetch from service',
+    );
+    const maxFeaturesPlaceholder = t('10000');
+    const attributionLabel = t('Attribution');
+    const attributionDescription = t('The layer attribution');
+    const attributionPlaceholder = t('© Layer attribution');
+
+    const wmsVersionOptions: { value: any; label: string }[] =
+      serviceVersions.WMS.map(version => ({ value: version, label: version }));
+    const wfsVersionOptions: { value: any; label: string }[] =
+      serviceVersions.WFS.map(version => ({ value: version, label: version }));
+
+    return (
+      <div>
+        <Form key={JSON.stringify(formKey)}>
+          <Tabs defaultActiveKey={LAYER_CONFIG_TABS.LAYER}>
+            <Tabs.TabPane tab={layerTabLabel} key={LAYER_CONFIG_TABS.LAYER}>
               <StyledControlFormItem
-                controlType="Select"
-                label={serviceVersionLabel}
-                description={serviceVersionDescription}
-                options={wmsVersionOptions}
-                value={wmsVersion}
-                defaultValue={wmsVersionOptions[0].value as string}
-                name="wmsVersion"
-                onChange={onWmsVersionChange}
+                controlType="Input"
+                label={layerUrlLabel}
+                description={layerUrlDescription}
+                placeholder={layerUrlPlaceholder}
+                value={currentLayerConf.url}
+                name="url"
+                onChange={onLayerUrlChange}
               />
-            )}
-            {isWfsLayerConf(currentLayerConf) && (
               <StyledControlFormItem
                 controlType="Select"
-                label={serviceVersionLabel}
-                description={serviceVersionDescription}
-                options={wfsVersionOptions}
-                value={wfsVersion}
-                defaultValue={wfsVersionOptions[0].value as string}
-                name="wfsVersion"
-                onChange={onWfsVersionChange}
+                label={layerTypeLabel}
+                description={layerTypeDescription}
+                options={[
+                  { value: 'WMS', label: t('WMS') },
+                  { value: 'WFS', label: t('WFS') },
+                  { value: 'XYZ', label: t('XYZ') },
+                ]}
+                value={currentLayerConf.type}
+                defaultValue={currentLayerConf.type}
+                name="type"
+                onChange={onLayerTypeChange}
               />
-            )}
-            {isWmsLayerConf(currentLayerConf) && (
+              {isWmsLayerConf(currentLayerConf) && (
+                <StyledControlFormItem
+                  controlType="Select"
+                  label={serviceVersionLabel}
+                  description={serviceVersionDescription}
+                  options={wmsVersionOptions}
+                  value={wmsVersion}
+                  defaultValue={wmsVersionOptions[0].value as string}
+                  name="wmsVersion"
+                  onChange={onWmsVersionChange}
+                />
+              )}
+              {isWfsLayerConf(currentLayerConf) && (
+                <StyledControlFormItem
+                  controlType="Select"
+                  label={serviceVersionLabel}
+                  description={serviceVersionDescription}
+                  options={wfsVersionOptions}
+                  value={wfsVersion}
+                  defaultValue={wfsVersionOptions[0].value as string}
+                  name="wfsVersion"
+                  onChange={onWfsVersionChange}
+                />
+              )}
+              {isWmsLayerConf(currentLayerConf) && (
+                <StyledControlFormItem
+                  controlType="Input"
+                  label={layersParamLabel}
+                  description={layersParamDescription}
+                  placeholder={layersParamPlaceholder}
+                  value={currentLayerConf.layersParam}
+                  name="layersParam"
+                  onChange={onLayersParamChange}
+                />
+              )}
+              {isWfsLayerConf(currentLayerConf) && (
+                <StyledControlFormItem
+                  controlType="Input"
+                  label={layersParamLabel}
+                  description={layersParamDescription}
+                  placeholder={layersParamPlaceholder}
+                  value={currentLayerConf.typeName}
+                  name="typeName"
+                  onChange={onTypeNameChange}
+                />
+              )}
               <StyledControlFormItem
                 controlType="Input"
-                label={layersParamLabel}
-                description={layersParamDescription}
-                placeholder={layersParamPlaceholder}
-                value={currentLayerConf.layersParam}
-                name="layersParam"
-                onChange={onLayersParamChange}
+                label={layerTitleLabel}
+                description={layerTitleDescription}
+                placeholder={layerTitlePlaceholder}
+                value={currentLayerConf.title}
+                name="title"
+                onChange={onLayerTitleChange}
               />
-            )}
-            {isWfsLayerConf(currentLayerConf) && (
+              {isWfsLayerConf(currentLayerConf) && (
+                <StyledControlNumberFormItem
+                  controlType="InputNumber"
+                  label={maxFeaturesLabel}
+                  description={maxFeaturesDescription}
+                  placeholder={maxFeaturesPlaceholder}
+                  value={currentLayerConf.maxFeatures}
+                  name="maxFeatures"
+                  onChange={onMaxFeaturesChange}
+                />
+              )}
               <StyledControlFormItem
                 controlType="Input"
-                label={layersParamLabel}
-                description={layersParamDescription}
-                placeholder={layersParamPlaceholder}
-                value={currentLayerConf.typeName}
-                name="typeName"
-                onChange={onTypeNameChange}
-              />
-            )}
-            <StyledControlFormItem
-              controlType="Input"
-              label={layerTitleLabel}
-              description={layerTitleDescription}
-              placeholder={layerTitlePlaceholder}
-              value={currentLayerConf.title}
-              name="title"
-              onChange={onLayerTitleChange}
-            />
-            {isWfsLayerConf(currentLayerConf) && (
-              <StyledControlNumberFormItem
-                controlType="InputNumber"
-                label={maxFeaturesLabel}
-                description={maxFeaturesDescription}
-                placeholder={maxFeaturesPlaceholder}
-                value={currentLayerConf.maxFeatures}
-                name="maxFeatures"
-                onChange={onMaxFeaturesChange}
+                label={attributionLabel}
+                description={attributionDescription}
+                placeholder={attributionPlaceholder}
+                value={currentLayerConf.attribution}
+                name="attribution"
+                onChange={onAttributionChange}
               />
-            )}
-            <StyledControlFormItem
-              controlType="Input"
-              label={attributionLabel}
-              description={attributionDescription}
-              placeholder={attributionPlaceholder}
-              value={currentLayerConf.attribution}
-              name="attribution"
-              onChange={onAttributionChange}
-            />
-          </Tabs.TabPane>
-          <Tabs.TabPane
-            tab={styleTabLabel}
-            key={LAYER_CONFIG_TABS.GEOSTYLER}
-            disabled={!isWfsLayerConf(currentLayerConf)}
-          >
-            {isWfsLayerConf(currentLayerConf) && (
-              <StyledGeoStyler
-                style={currentLayerConf.style}
-                onStyleChange={onStyleChange}
-                data={geostylerData}
-              />
-            )}
-          </Tabs.TabPane>
-        </Tabs>
-        <StyledButtonContainer>
-          <StyledCloseButton type="default" onClick={onCloseClick}>
-            {t('Close')}
-          </StyledCloseButton>
-          <StyledSaveButton type="primary" onClick={onSaveClick}>
-            {t('Save')}
-          </StyledSaveButton>
-        </StyledButtonContainer>
-      </Form>
-    </div>
-  );
-};
+            </Tabs.TabPane>
+            <Tabs.TabPane
+              tab={styleTabLabel}
+              key={LAYER_CONFIG_TABS.GEOSTYLER}
+              disabled={!isWfsLayerConf(currentLayerConf)}
+            >
+              {isWfsLayerConf(currentLayerConf) && (
+                <StyledGeoStyler
+                  style={currentLayerConf.style}
+                  onStyleChange={onStyleChange}
+                  data={geostylerData}
+                />
+              )}
+            </Tabs.TabPane>
+          </Tabs>
+          <StyledButtonContainer>
+            <StyledCloseButton type="default" onClick={onCloseClick}>
+              {t('Close')}
+            </StyledCloseButton>
+            <StyledSaveButton type="primary" onClick={onSaveClick}>
+              {t('Save')}
+            </StyledSaveButton>
+          </StyledButtonContainer>
+        </Form>
+      </div>
+    );
+  };
 
 export default LayerConfigsPopoverContent;
diff --git a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
index 3201675f03..5bc8e530fb 100644
--- a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
+++ b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
@@ -47,82 +47,81 @@ export interface AdhocMetricEditPopoverTitleProps {
   onChange: ChangeEventHandler<HTMLInputElement>;
 }
 
-const AdhocMetricEditPopoverTitle: React.FC<
-  AdhocMetricEditPopoverTitleProps
-> = ({ title, isEditDisabled, onChange }) => {
-  const [isHovered, setIsHovered] = useState(false);
-  const [isEditMode, setIsEditMode] = useState(false);
+const AdhocMetricEditPopoverTitle: React.FC<AdhocMetricEditPopoverTitleProps> =
+  ({ title, isEditDisabled, onChange }) => {
+    const [isHovered, setIsHovered] = useState(false);
+    const [isEditMode, setIsEditMode] = useState(false);
 
-  const defaultLabel = t('My metric');
+    const defaultLabel = t('My metric');
 
-  const handleMouseOver = useCallback(() => setIsHovered(true), []);
-  const handleMouseOut = useCallback(() => setIsHovered(false), []);
-  const handleClick = useCallback(() => setIsEditMode(true), []);
-  const handleBlur = useCallback(() => setIsEditMode(false), []);
+    const handleMouseOver = useCallback(() => setIsHovered(true), []);
+    const handleMouseOut = useCallback(() => setIsHovered(false), []);
+    const handleClick = useCallback(() => setIsEditMode(true), []);
+    const handleBlur = useCallback(() => setIsEditMode(false), []);
 
-  const handleKeyPress = useCallback(
-    (ev: KeyboardEvent<HTMLInputElement>) => {
-      if (ev.key === 'Enter') {
-        ev.preventDefault();
-        handleBlur();
-      }
-    },
-    [handleBlur],
-  );
-
-  const handleInputBlur = useCallback(
-    (e: FocusEvent<HTMLInputElement>) => {
-      if (e.target.value === '') {
-        onChange(e);
-      }
+    const handleKeyPress = useCallback(
+      (ev: KeyboardEvent<HTMLInputElement>) => {
+        if (ev.key === 'Enter') {
+          ev.preventDefault();
+          handleBlur();
+        }
+      },
+      [handleBlur],
+    );
 
-      handleBlur();
-    },
-    [onChange, handleBlur],
-  );
+    const handleInputBlur = useCallback(
+      (e: FocusEvent<HTMLInputElement>) => {
+        if (e.target.value === '') {
+          onChange(e);
+        }
 
-  if (isEditDisabled) {
-    return (
-      <span data-test="AdhocMetricTitle">{title?.label || defaultLabel}</span>
+        handleBlur();
+      },
+      [onChange, handleBlur],
     );
-  }
 
-  if (isEditMode) {
-    return (
-      <StyledInput
-        type="text"
-        placeholder={title?.label}
-        value={title?.hasCustomLabel ? title.label : ''}
-        autoFocus
-        onChange={onChange}
-        onBlur={handleInputBlur}
-        onKeyPress={handleKeyPress}
-        data-test="AdhocMetricEditTitle#input"
-      />
-    );
-  }
+    if (isEditDisabled) {
+      return (
+        <span data-test="AdhocMetricTitle">{title?.label || defaultLabel}</span>
+      );
+    }
 
-  return (
-    <Tooltip placement="top" title={t('Click to edit label')}>
-      <span
-        className="AdhocMetricEditPopoverTitle inline-editable"
-        data-test="AdhocMetricEditTitle#trigger"
-        onMouseOver={handleMouseOver}
-        onMouseOut={handleMouseOut}
-        onClick={handleClick}
-        onBlur={handleBlur}
-        role="button"
-        tabIndex={0}
-      >
-        <TitleLabel>{title?.label || defaultLabel}</TitleLabel>
-        &nbsp;
-        <i
-          className="fa fa-pencil"
-          style={{ color: isHovered ? 'black' : 'grey' }}
+    if (isEditMode) {
+      return (
+        <StyledInput
+          type="text"
+          placeholder={title?.label}
+          value={title?.hasCustomLabel ? title.label : ''}
+          autoFocus
+          onChange={onChange}
+          onBlur={handleInputBlur}
+          onKeyPress={handleKeyPress}
+          data-test="AdhocMetricEditTitle#input"
         />
-      </span>
-    </Tooltip>
-  );
-};
+      );
+    }
+
+    return (
+      <Tooltip placement="top" title={t('Click to edit label')}>
+        <span
+          className="AdhocMetricEditPopoverTitle inline-editable"
+          data-test="AdhocMetricEditTitle#trigger"
+          onMouseOver={handleMouseOver}
+          onMouseOut={handleMouseOut}
+          onClick={handleClick}
+          onBlur={handleBlur}
+          role="button"
+          tabIndex={0}
+        >
+          <TitleLabel>{title?.label || defaultLabel}</TitleLabel>
+          &nbsp;
+          <i
+            className="fa fa-pencil"
+            style={{ color: isHovered ? 'black' : 'grey' }}
+          />
+        </span>
+      </Tooltip>
+    );
+  };
 
 export default AdhocMetricEditPopoverTitle;
diff --git a/superset-frontend/src/features/alerts/components/AlertReportCronScheduler.tsx b/superset-frontend/src/features/alerts/components/AlertReportCronScheduler.tsx
index 17652af510..143d1e1fb1 100644
--- a/superset-frontend/src/features/alerts/components/AlertReportCronScheduler.tsx
+++ b/superset-frontend/src/features/alerts/components/AlertReportCronScheduler.tsx
@@ -30,77 +30,76 @@ export interface AlertReportCronSchedulerProps {
   onChange: (change: string) => any;
 }
 
-export const AlertReportCronScheduler: React.FC<
-  AlertReportCronSchedulerProps
-> = ({ value, onChange }) => {
-  const theme = useTheme();
-  const inputRef = useRef<AntdInput>(null);
-  const [scheduleFormat, setScheduleFormat] = useState<'picker' | 'input'>(
-    'picker',
-  );
+export const AlertReportCronScheduler: React.FC<AlertReportCronSchedulerProps> =
+  ({ value, onChange }) => {
+    const theme = useTheme();
+    const inputRef = useRef<AntdInput>(null);
+    const [scheduleFormat, setScheduleFormat] = useState<'picker' | 'input'>(
+      'picker',
+    );
 
-  const handleRadioButtonChange = useCallback(
-    (e: RadioChangeEvent) => setScheduleFormat(e.target.value),
-    [],
-  );
+    const handleRadioButtonChange = useCallback(
+      (e: RadioChangeEvent) => setScheduleFormat(e.target.value),
+      [],
+    );
 
-  const customSetValue = useCallback(
-    (newValue: string) => {
-      onChange(newValue);
-      inputRef.current?.setValue(newValue);
-    },
-    [inputRef, onChange],
-  );
+    const customSetValue = useCallback(
+      (newValue: string) => {
+        onChange(newValue);
+        inputRef.current?.setValue(newValue);
+      },
+      [inputRef, onChange],
+    );
 
-  const handleBlur = useCallback(
-    (event: FocusEvent<HTMLInputElement>) => {
-      onChange(event.target.value);
-    },
-    [onChange],
-  );
+    const handleBlur = useCallback(
+      (event: FocusEvent<HTMLInputElement>) => {
+        onChange(event.target.value);
+      },
+      [onChange],
+    );
 
-  const handlePressEnter = useCallback(() => {
-    onChange(inputRef.current?.input.value || '');
-  }, [onChange]);
+    const handlePressEnter = useCallback(() => {
+      onChange(inputRef.current?.input.value || '');
+    }, [onChange]);
 
-  const [error, onError] = useState<CronError>();
+    const [error, onError] = useState<CronError>();
 
-  return (
-    <>
-      <Radio.Group onChange={handleRadioButtonChange} value={scheduleFormat}>
-        <div className="inline-container add-margin">
-          <Radio data-test="picker" value="picker" />
-          <CronPicker
-            clearButton={false}
-            value={value}
-            setValue={customSetValue}
-            disabled={scheduleFormat !== 'picker'}
-            displayError={scheduleFormat === 'picker'}
-            onError={onError}
-          />
-        </div>
-        <div className="inline-container add-margin">
-          <Radio data-test="input" value="input" />
-          <span className="input-label">{t('CRON Schedule')}</span>
-          <StyledInputContainer
-            data-test="input-content"
-            className="styled-input"
-          >
-            <div className="input-container">
-              <Input
-                type="text"
-                name="crontab"
-                ref={inputRef}
-                style={error ? { borderColor: theme.colors.error.base } : {}}
-                placeholder={t('CRON expression')}
-                disabled={scheduleFormat !== 'input'}
-                onBlur={handleBlur}
-                onPressEnter={handlePressEnter}
-              />
-            </div>
-          </StyledInputContainer>
-        </div>
-      </Radio.Group>
-    </>
-  );
-};
+    return (
+      <>
+        <Radio.Group onChange={handleRadioButtonChange} value={scheduleFormat}>
+          <div className="inline-container add-margin">
+            <Radio data-test="picker" value="picker" />
+            <CronPicker
+              clearButton={false}
+              value={value}
+              setValue={customSetValue}
+              disabled={scheduleFormat !== 'picker'}
+              displayError={scheduleFormat === 'picker'}
+              onError={onError}
+            />
+          </div>
+          <div className="inline-container add-margin">
+            <Radio data-test="input" value="input" />
+            <span className="input-label">{t('CRON Schedule')}</span>
+            <StyledInputContainer
+              data-test="input-content"
+              className="styled-input"
+            >
+              <div className="input-container">
+                <Input
+                  type="text"
+                  name="crontab"
+                  ref={inputRef}
+                  style={error ? { borderColor: theme.colors.error.base } : {}}
+                  placeholder={t('CRON expression')}
+                  disabled={scheduleFormat !== 'input'}
+                  onBlur={handleBlur}
+                  onPressEnter={handlePressEnter}
+                />
+              </div>
+            </StyledInputContainer>
+          </div>
+        </Radio.Group>
+      </>
+    );
+  };
diff --git a/superset-frontend/src/features/queries/SavedQueryPreviewModal.tsx b/superset-frontend/src/features/queries/SavedQueryPreviewModal.tsx
index 684eabb029..0db06f91cf 100644
--- a/superset-frontend/src/features/queries/SavedQueryPreviewModal.tsx
+++ b/superset-frontend/src/features/queries/SavedQueryPreviewModal.tsx
@@ -71,74 +71,73 @@ interface SavedQueryPreviewModalProps extends ToastProps {
   show: boolean;
 }
 
-const SavedQueryPreviewModal: FunctionComponent<
-  SavedQueryPreviewModalProps
-> = ({
-  fetchData,
-  onHide,
-  openInSqlLab,
-  queries,
-  savedQuery,
-  show,
-  addDangerToast,
-  addSuccessToast,
-}) => {
-  const { handleKeyPress, handleDataChange, disablePrevious, disableNext } =
-    useQueryPreviewState<SavedQueryObject>({
-      queries,
-      currentQueryId: savedQuery.id,
-      fetchData,
-    });
+const SavedQueryPreviewModal: FunctionComponent<SavedQueryPreviewModalProps> =
+  ({
+    fetchData,
+    onHide,
+    openInSqlLab,
+    queries,
+    savedQuery,
+    show,
+    addDangerToast,
+    addSuccessToast,
+  }) => {
+    const { handleKeyPress, handleDataChange, disablePrevious, disableNext } =
+      useQueryPreviewState<SavedQueryObject>({
+        queries,
+        currentQueryId: savedQuery.id,
+        fetchData,
+      });
 
-  return (
-    <div role="none" onKeyUp={handleKeyPress}>
-      <StyledModal
-        onHide={onHide}
-        show={show}
-        title={t('Query preview')}
-        footer={
-          <>
-            <Button
-              data-test="previous-saved-query"
-              key="previous-saved-query"
-              disabled={disablePrevious}
-              onClick={() => handleDataChange(true)}
-            >
-              {t('Previous')}
-            </Button>
-            <Button
-              data-test="next-saved-query"
-              key="next-saved-query"
-              disabled={disableNext}
-              onClick={() => handleDataChange(false)}
-            >
-              {t('Next')}
-            </Button>
-            <Button
-              data-test="open-in-sql-lab"
-              key="open-in-sql-lab"
-              buttonStyle="primary"
-              onClick={({ metaKey }) =>
-                openInSqlLab(savedQuery.id, Boolean(metaKey))
-              }
-            >
-              {t('Open in SQL Lab')}
-            </Button>
-          </>
-        }
-      >
-        <QueryTitle>{t('Query name')}</QueryTitle>
-        <QueryLabel>{savedQuery.label}</QueryLabel>
-        <SyntaxHighlighterCopy
-          language="sql"
-          addDangerToast={addDangerToast}
-          addSuccessToast={addSuccessToast}
+    return (
+      <div role="none" onKeyUp={handleKeyPress}>
+        <StyledModal
+          onHide={onHide}
+          show={show}
+          title={t('Query preview')}
+          footer={
+            <>
+              <Button
+                data-test="previous-saved-query"
+                key="previous-saved-query"
+                disabled={disablePrevious}
+                onClick={() => handleDataChange(true)}
+              >
+                {t('Previous')}
+              </Button>
+              <Button
+                data-test="next-saved-query"
+                key="next-saved-query"
+                disabled={disableNext}
+                onClick={() => handleDataChange(false)}
+              >
+                {t('Next')}
+              </Button>
+              <Button
+                data-test="open-in-sql-lab"
+                key="open-in-sql-lab"
+                buttonStyle="primary"
+                onClick={({ metaKey }) =>
+                  openInSqlLab(savedQuery.id, Boolean(metaKey))
+                }
+              >
+                {t('Open in SQL Lab')}
+              </Button>
+            </>
+          }
         >
-          {savedQuery.sql || ''}
-        </SyntaxHighlighterCopy>
-      </StyledModal>
-    </div>
-  );
-};
+          <QueryTitle>{t('Query name')}</QueryTitle>
+          <QueryLabel>{savedQuery.label}</QueryLabel>
+          <SyntaxHighlighterCopy
+            language="sql"
+            addDangerToast={addDangerToast}
+            addSuccessToast={addSuccessToast}
+          >
+            {savedQuery.sql || ''}
+          </SyntaxHighlighterCopy>
+        </StyledModal>
+      </div>
+    );
+  };
 
 export default withToasts(SavedQueryPreviewModal);