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

beto pushed a commit to branch dbt-metricflow
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/dbt-metricflow by this push:
     new 83c8c4d7e5 Works
83c8c4d7e5 is described below

commit 83c8c4d7e5d9252212e3d0b0ee1e73d8271ce65f
Author: Beto Dealmeida <robe...@dealmeida.net>
AuthorDate: Thu Jul 17 12:02:48 2025 -0400

    Works
---
 .../src/shared-controls/dndControls.tsx            |  57 ++--
 .../src/shared-controls/semanticLayerControls.tsx  |  99 +++++++
 .../components/controls/SemanticLayerControls.tsx  | 225 +++++++++++++++
 .../controls/SemanticLayerVerification.tsx         | 308 +++++++++++++++++++++
 superset-frontend/src/setup/setupSemanticLayer.ts  |  41 +++
 5 files changed, 707 insertions(+), 23 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
index 9d199f1edd..03cb0fefbd 100644
--- 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
+++ 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/dndControls.tsx
@@ -85,43 +85,54 @@ function needsSemanticLayerVerification(datasource: 
Dataset): boolean {
 
 /**
  * Enhance a control with semantic layer verification if available
+ * This creates a lazy-enhanced control that checks for utilities at runtime
  */
 function enhanceControlWithSemanticLayer(
   baseControl: any,
   controlName: string,
   verificationType: 'metrics' | 'columns',
 ) {
-  if (!withAsyncVerification) {
-    return baseControl;
-  }
-
-  const verificationFn =
-    verificationType === 'metrics'
-      ? createMetricsVerification()
-      : createColumnsVerification();
-
+  // Return a control that will be enhanced at runtime if utilities are 
available
   return {
     ...baseControl,
-    type: withAsyncVerification({
-      baseControl: baseControl.type,
-      verify: verificationFn,
-      onChange: createSemanticLayerOnChange(
-        controlName,
-        SEMANTIC_LAYER_CONTROL_FIELDS,
-      ),
-      showLoadingState: true,
-    }),
+    // Override the type to use a function that checks for enhancement at 
runtime
+    get type() {
+      if (withAsyncVerification) {
+        const verificationFn =
+          verificationType === 'metrics'
+            ? createMetricsVerification()
+            : createColumnsVerification();
+
+        return withAsyncVerification({
+          baseControl: baseControl.type,
+          verify: verificationFn,
+          onChange: createSemanticLayerOnChange(
+            controlName,
+            SEMANTIC_LAYER_CONTROL_FIELDS,
+          ),
+          showLoadingState: true,
+        });
+      }
+      return baseControl.type;
+    },
     mapStateToProps: (state: any, controlState: any) => {
       // Call the original mapStateToProps if it exists
       const originalProps = baseControl.mapStateToProps
         ? baseControl.mapStateToProps(state, controlState)
         : {};
 
-      return {
-        ...originalProps,
-        needAsyncVerification: 
needsSemanticLayerVerification(state.datasource),
-        form_data: state.form_data,
-      };
+      // Only add semantic layer props if utilities are available
+      if (withAsyncVerification) {
+        const needsVerification = 
needsSemanticLayerVerification(state.datasource);
+
+        return {
+          ...originalProps,
+          needAsyncVerification: needsVerification,
+          form_data: state.form_data,
+        };
+      }
+
+      return originalProps;
     },
   };
 }
diff --git 
a/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/semanticLayerControls.tsx
 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/semanticLayerControls.tsx
new file mode 100644
index 0000000000..2ef130c870
--- /dev/null
+++ 
b/superset-frontend/packages/superset-ui-chart-controls/src/shared-controls/semanticLayerControls.tsx
@@ -0,0 +1,99 @@
+/**
+ * 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 {
+  dndAdhocMetricsControl,
+  dndAdhocMetricControl,
+  dndAdhocMetricControl2,
+  dndGroupByControl,
+  dndColumnsControl,
+} from './dndControls';
+// Placeholder for semantic layer controls - these would be imported from the 
main app
+const semanticLayerDndAdhocMetricsControl = null;
+const semanticLayerDndAdhocMetricControl = null;
+const semanticLayerDndAdhocMetricControl2 = null;
+const semanticLayerDndGroupByControl = null;
+const semanticLayerDndColumnsControl = null;
+
+/**
+ * Enhanced shared controls that include semantic layer verification
+ * when using compatible datasources.
+ */
+export const enhancedSharedControls = {
+  // Original controls
+  dndAdhocMetricsControl,
+  dndAdhocMetricControl,
+  dndAdhocMetricControl2,
+  dndGroupByControl,
+  dndColumnsControl,
+
+  // Enhanced controls with semantic layer verification
+  semanticLayerDndAdhocMetricsControl,
+  semanticLayerDndAdhocMetricControl,
+  semanticLayerDndAdhocMetricControl2,
+  semanticLayerDndGroupByControl,
+  semanticLayerDndColumnsControl,
+};
+
+/**
+ * Get the appropriate control based on datasource capabilities
+ */
+export function getSemanticLayerControl(
+  controlName: string,
+  datasource?: any,
+): any {
+  // Check if datasource supports semantic layer verification
+  const supportsSemanticLayer =
+    datasource &&
+    'database' in datasource &&
+    datasource.database?.engine_information?.supports_dynamic_columns;
+
+  if (supportsSemanticLayer) {
+    switch (controlName) {
+      case 'dndAdhocMetricsControl':
+        return semanticLayerDndAdhocMetricsControl;
+      case 'dndAdhocMetricControl':
+        return semanticLayerDndAdhocMetricControl;
+      case 'dndAdhocMetricControl2':
+        return semanticLayerDndAdhocMetricControl2;
+      case 'dndGroupByControl':
+        return semanticLayerDndGroupByControl;
+      case 'dndColumnsControl':
+        return semanticLayerDndColumnsControl;
+      default:
+        break;
+    }
+  }
+
+  // Return original control for non-semantic layer datasources
+  switch (controlName) {
+    case 'dndAdhocMetricsControl':
+      return dndAdhocMetricsControl;
+    case 'dndAdhocMetricControl':
+      return dndAdhocMetricControl;
+    case 'dndAdhocMetricControl2':
+      return dndAdhocMetricControl2;
+    case 'dndGroupByControl':
+      return dndGroupByControl;
+    case 'dndColumnsControl':
+      return dndColumnsControl;
+    default:
+      return null;
+  }
+}
diff --git 
a/superset-frontend/src/explore/components/controls/SemanticLayerControls.tsx 
b/superset-frontend/src/explore/components/controls/SemanticLayerControls.tsx
new file mode 100644
index 0000000000..15d659486d
--- /dev/null
+++ 
b/superset-frontend/src/explore/components/controls/SemanticLayerControls.tsx
@@ -0,0 +1,225 @@
+/**
+ * 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 {
+  dndAdhocMetricsControl,
+  dndAdhocMetricControl,
+  dndAdhocMetricControl2,
+  dndGroupByControl,
+  dndColumnsControl,
+  Dataset,
+} from '@superset-ui/chart-controls';
+import withAsyncVerification from './withAsyncVerification';
+import {
+  createMetricsVerification,
+  createColumnsVerification,
+  createSemanticLayerOnChange,
+  SEMANTIC_LAYER_CONTROL_FIELDS,
+} from './SemanticLayerVerification';
+
+/**
+ * Check if a datasource supports semantic layer verification
+ */
+function needsSemanticLayerVerification(datasource: Dataset): boolean {
+  if (!datasource || !('database' in datasource) || !datasource.database) {
+    return false;
+  }
+
+  const database = datasource.database as any;
+  return Boolean(database.engine_information?.supports_dynamic_columns);
+}
+
+/**
+ * Enhanced metrics control with semantic layer verification
+ */
+export const semanticLayerDndAdhocMetricsControl = {
+  ...dndAdhocMetricsControl,
+  type: withAsyncVerification({
+    baseControl: 'DndMetricSelect',
+    verify: createMetricsVerification(),
+    onChange: createSemanticLayerOnChange(
+      'metrics',
+      SEMANTIC_LAYER_CONTROL_FIELDS,
+    ),
+    showLoadingState: true,
+  }),
+  mapStateToProps: (state: any, controlState: any) => {
+    // Call the original mapStateToProps if it exists
+    const originalProps = dndAdhocMetricsControl.mapStateToProps
+      ? dndAdhocMetricsControl.mapStateToProps(state, controlState)
+      : {};
+
+    return {
+      ...originalProps,
+      needAsyncVerification: needsSemanticLayerVerification(state.datasource),
+      form_data: state.form_data,
+    };
+  },
+};
+
+/**
+ * Enhanced single metric control with semantic layer verification
+ */
+export const semanticLayerDndAdhocMetricControl = {
+  ...dndAdhocMetricControl,
+  type: withAsyncVerification({
+    baseControl: 'DndMetricSelect',
+    verify: createMetricsVerification(),
+    onChange: createSemanticLayerOnChange(
+      'metric',
+      SEMANTIC_LAYER_CONTROL_FIELDS,
+    ),
+    showLoadingState: true,
+  }),
+  mapStateToProps: (state: any, controlState: any) => {
+    // Call the original mapStateToProps if it exists
+    const originalProps = dndAdhocMetricControl.mapStateToProps
+      ? dndAdhocMetricControl.mapStateToProps(state, controlState)
+      : {};
+
+    return {
+      ...originalProps,
+      needAsyncVerification: needsSemanticLayerVerification(state.datasource),
+      form_data: state.form_data,
+    };
+  },
+};
+
+/**
+ * Enhanced secondary metric control with semantic layer verification
+ */
+export const semanticLayerDndAdhocMetricControl2 = {
+  ...dndAdhocMetricControl2,
+  type: withAsyncVerification({
+    baseControl: 'DndMetricSelect',
+    verify: createMetricsVerification(),
+    onChange: createSemanticLayerOnChange(
+      'metric_2',
+      SEMANTIC_LAYER_CONTROL_FIELDS,
+    ),
+    showLoadingState: true,
+  }),
+  mapStateToProps: (state: any, controlState: any) => {
+    // Call the original mapStateToProps if it exists
+    const originalProps = dndAdhocMetricControl2.mapStateToProps
+      ? dndAdhocMetricControl2.mapStateToProps(state, controlState)
+      : {};
+
+    return {
+      ...originalProps,
+      needAsyncVerification: needsSemanticLayerVerification(state.datasource),
+      form_data: state.form_data,
+    };
+  },
+};
+
+/**
+ * Enhanced group by control with semantic layer verification
+ */
+export const semanticLayerDndGroupByControl = {
+  ...dndGroupByControl,
+  type: withAsyncVerification({
+    baseControl: 'DndColumnSelect',
+    verify: createColumnsVerification(),
+    onChange: createSemanticLayerOnChange(
+      'groupby',
+      SEMANTIC_LAYER_CONTROL_FIELDS,
+    ),
+    showLoadingState: true,
+  }),
+  mapStateToProps: (state: any, controlState: any) => {
+    // Call the original mapStateToProps if it exists
+    const originalProps = dndGroupByControl.mapStateToProps
+      ? dndGroupByControl.mapStateToProps(state, controlState)
+      : {};
+
+    return {
+      ...originalProps,
+      needAsyncVerification: needsSemanticLayerVerification(state.datasource),
+      form_data: state.form_data,
+    };
+  },
+};
+
+/**
+ * Enhanced columns control with semantic layer verification
+ */
+export const semanticLayerDndColumnsControl = {
+  ...dndColumnsControl,
+  type: withAsyncVerification({
+    baseControl: 'DndColumnSelect',
+    verify: createColumnsVerification(),
+    onChange: createSemanticLayerOnChange(
+      'columns',
+      SEMANTIC_LAYER_CONTROL_FIELDS,
+    ),
+    showLoadingState: true,
+  }),
+  mapStateToProps: (state: any, controlState: any) => {
+    // Call the original mapStateToProps if it exists
+    const originalProps = dndColumnsControl.mapStateToProps
+      ? dndColumnsControl.mapStateToProps(state, controlState)
+      : {};
+
+    return {
+      ...originalProps,
+      needAsyncVerification: needsSemanticLayerVerification(state.datasource),
+      form_data: state.form_data,
+    };
+  },
+};
+
+/**
+ * Create override function for semantic layer controls
+ */
+function createSemanticLayerControlOverride(enhancedControl: any) {
+  return (originalConfig: any) =>
+    // For semantic layer datasources, use the enhanced control
+    // For regular datasources, use the original control
+    ({
+      ...originalConfig,
+      ...enhancedControl,
+    });
+}
+
+/**
+ * Control overrides mapping
+ */
+export const semanticLayerControlOverrides = {
+  metrics: createSemanticLayerControlOverride(
+    semanticLayerDndAdhocMetricsControl,
+  ),
+  metric: createSemanticLayerControlOverride(
+    semanticLayerDndAdhocMetricControl,
+  ),
+  metric_2: createSemanticLayerControlOverride(
+    semanticLayerDndAdhocMetricControl2,
+  ),
+  percent_metrics: createSemanticLayerControlOverride(
+    semanticLayerDndAdhocMetricsControl,
+  ),
+  timeseries_limit_metric: createSemanticLayerControlOverride(
+    semanticLayerDndAdhocMetricControl,
+  ),
+  groupby: createSemanticLayerControlOverride(semanticLayerDndGroupByControl),
+  columns: createSemanticLayerControlOverride(semanticLayerDndColumnsControl),
+  series_columns: createSemanticLayerControlOverride(
+    semanticLayerDndColumnsControl,
+  ),
+};
diff --git 
a/superset-frontend/src/explore/components/controls/SemanticLayerVerification.tsx
 
b/superset-frontend/src/explore/components/controls/SemanticLayerVerification.tsx
new file mode 100644
index 0000000000..e618ee8f92
--- /dev/null
+++ 
b/superset-frontend/src/explore/components/controls/SemanticLayerVerification.tsx
@@ -0,0 +1,308 @@
+/**
+ * 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 { SupersetClient, JsonValue } from '@superset-ui/core';
+import { Dataset } from '@superset-ui/chart-controls';
+import { AsyncVerify, ControlPropsWithExtras } from './withAsyncVerification';
+
+/**
+ * Utility to extract current form fields from form data
+ */
+export function collectQueryFields(formData: any): {
+  dimensions: string[];
+  metrics: string[];
+} {
+  const dimensions: string[] = [];
+  const metrics: string[] = [];
+
+  // Extract dimensions from various field types
+  if (formData.groupby) {
+    dimensions.push(
+      ...(Array.isArray(formData.groupby)
+        ? formData.groupby
+        : [formData.groupby]),
+    );
+  }
+  if (formData.columns) {
+    dimensions.push(
+      ...(Array.isArray(formData.columns)
+        ? formData.columns
+        : [formData.columns]),
+    );
+  }
+
+  // Extract metrics from various field types
+  if (formData.metrics) {
+    metrics.push(
+      ...(Array.isArray(formData.metrics)
+        ? formData.metrics
+        : [formData.metrics]),
+    );
+  }
+  if (formData.metric) {
+    metrics.push(formData.metric);
+  }
+  if (formData.percent_metrics) {
+    metrics.push(
+      ...(Array.isArray(formData.percent_metrics)
+        ? formData.percent_metrics
+        : [formData.percent_metrics]),
+    );
+  }
+
+  // Filter out null/undefined values and convert objects to strings if needed
+  const cleanDimensions = dimensions
+    .filter(dim => dim != null)
+    .map(dim =>
+      typeof dim === 'string' ? dim : (dim as any)?.column_name || String(dim),
+    );
+
+  const cleanMetrics = metrics
+    .filter(metric => metric != null)
+    .map(metric =>
+      typeof metric === 'string'
+        ? metric
+        : (metric as any)?.metric_name || String(metric),
+    );
+
+  return {
+    dimensions: [...new Set(cleanDimensions)], // Remove duplicates
+    metrics: [...new Set(cleanMetrics)], // Remove duplicates
+  };
+}
+
+/**
+ * Check if a datasource supports semantic layer verification
+ */
+function supportsSemanticLayerVerification(datasource: Dataset): boolean {
+  if (!datasource || !('database' in datasource) || !datasource.database) {
+    return false;
+  }
+  
+  const database = datasource.database as any;
+  return Boolean(database.engine_information?.supports_dynamic_columns);
+}
+
+/**
+ * Call the validation API
+ */
+async function callValidationAPI(
+  datasource: Dataset,
+  selectedDimensions: string[],
+  selectedMetrics: string[],
+): Promise<{ dimensions: string[]; metrics: string[] } | null> {
+  const databaseId = (datasource.database as any)?.id;
+  if (!datasource?.id || !databaseId) {
+    return null;
+  }
+
+  try {
+    const response = await SupersetClient.post({
+      endpoint: `/api/v1/database/${databaseId}/valid_metrics_and_dimensions/`,
+      jsonPayload: {
+        datasource_id: datasource.id,
+        dimensions: selectedDimensions,
+        metrics: selectedMetrics,
+      },
+    });
+
+    return response.json as { dimensions: string[]; metrics: string[] };
+  } catch (error) {
+    console.warn('Failed to fetch valid metrics and dimensions:', error);
+    return null;
+  }
+}
+
+/**
+ * Create verification function for metrics controls
+ */
+export function createMetricsVerification(): AsyncVerify {
+  return async (props: ControlPropsWithExtras) => {
+    const { datasource, form_data, savedMetrics = [], actions } = props;
+
+    // Only verify for semantic layer datasources
+    if (!supportsSemanticLayerVerification(datasource as Dataset)) {
+      return null;
+    }
+
+    // Extract current form fields
+    const queryFields = collectQueryFields(form_data || {});
+
+    // Call validation API
+    const validationResult = await callValidationAPI(
+      datasource as Dataset,
+      queryFields.dimensions,
+      queryFields.metrics,
+    );
+
+    if (!validationResult) {
+      return null;
+    }
+
+    // Filter saved metrics to only include valid ones
+    const validMetricNames = new Set(validationResult.metrics);
+    const filteredSavedMetrics = savedMetrics.filter((metric: any) =>
+      validMetricNames.has(metric.metric_name || metric),
+    );
+
+    // Also filter the datasource metrics (for left panel) if this is a Dataset
+    const dataset = datasource as Dataset;
+    let filteredDatasourceMetrics = dataset.metrics;
+    let filteredDatasourceColumns = dataset.columns;
+    
+    if (dataset.metrics) {
+      filteredDatasourceMetrics = dataset.metrics.filter((metric: any) =>
+        validMetricNames.has(metric.metric_name || metric),
+      );
+    }
+    
+    // Also filter columns using the same validation result
+    const validDimensionNames = new Set(validationResult.dimensions);
+    if (dataset.columns) {
+      filteredDatasourceColumns = dataset.columns.filter((column: any) =>
+        validDimensionNames.has(column.column_name || column),
+      );
+    }
+
+    // Create filtered datasource for left panel
+    const filteredDatasource = {
+      ...dataset,
+      metrics: filteredDatasourceMetrics,
+      columns: filteredDatasourceColumns,
+    };
+
+    // Update the Redux store's datasource to affect the left panel
+    if (actions && typeof actions.syncDatasourceMetadata === 'function') {
+      actions.syncDatasourceMetadata(filteredDatasource);
+    }
+
+    return {
+      savedMetrics: filteredSavedMetrics,
+      datasource: filteredDatasource,
+    };
+  };
+}
+
+/**
+ * Create verification function for dimensions controls
+ */
+export function createColumnsVerification(): AsyncVerify {
+  return async (props: ControlPropsWithExtras) => {
+    const { datasource, form_data, options = [], actions } = props;
+
+    // Only verify for semantic layer datasources
+    if (!supportsSemanticLayerVerification(datasource as Dataset)) {
+      return null;
+    }
+
+    // Extract current form fields
+    const queryFields = collectQueryFields(form_data || {});
+
+    // Call validation API
+    const validationResult = await callValidationAPI(
+      datasource as Dataset,
+      queryFields.dimensions,
+      queryFields.metrics,
+    );
+
+    if (!validationResult) {
+      return null;
+    }
+
+    // Filter dimension options to only include valid ones
+    const validDimensionNames = new Set(validationResult.dimensions);
+    const filteredOptions = options.filter((option: any) =>
+      validDimensionNames.has(option.column_name || option),
+    );
+
+    // Also filter the datasource columns (for left panel) if this is a Dataset
+    const dataset = datasource as Dataset;
+    let filteredDatasourceColumns = dataset.columns;
+    let filteredDatasourceMetrics = dataset.metrics;
+    
+    if (dataset.columns) {
+      filteredDatasourceColumns = dataset.columns.filter((column: any) =>
+        validDimensionNames.has(column.column_name || column),
+      );
+    }
+    
+    // Also filter metrics using the same validation result
+    const validMetricNames = new Set(validationResult.metrics);
+    if (dataset.metrics) {
+      filteredDatasourceMetrics = dataset.metrics.filter((metric: any) =>
+        validMetricNames.has(metric.metric_name || metric),
+      );
+    }
+
+    // Create filtered datasource for left panel
+    const filteredDatasource = {
+      ...dataset,
+      columns: filteredDatasourceColumns,
+      metrics: filteredDatasourceMetrics,
+    };
+
+    // Update the Redux store's datasource to affect the left panel
+    if (actions && typeof actions.syncDatasourceMetadata === 'function') {
+      actions.syncDatasourceMetadata(filteredDatasource);
+    }
+
+    return {
+      options: filteredOptions,
+      datasource: filteredDatasource,
+    };
+  };
+}
+
+/**
+ * Create onChange handler that triggers re-rendering of other controls when 
values change
+ */
+export function createSemanticLayerOnChange(
+  controlName: string,
+  affectedControls: string[],
+) {
+  return (value: JsonValue, props: ControlPropsWithExtras) => {
+    const { actions, form_data } = props;
+
+    // Trigger re-rendering of affected controls by updating their values
+    // This forces the verification to run again
+    affectedControls.forEach(controlField => {
+      if (
+        controlField !== controlName &&
+        form_data &&
+        form_data[controlField]
+      ) {
+        actions.setControlValue(controlField, form_data[controlField], []);
+      }
+    });
+  };
+}
+
+/**
+ * Get list of control fields that should trigger re-rendering
+ */
+export const SEMANTIC_LAYER_CONTROL_FIELDS = [
+  'metrics',
+  'metric',
+  'metric_2',
+  'percent_metrics',
+  'timeseries_limit_metric',
+  'groupby',
+  'columns',
+  'series_columns',
+];
diff --git a/superset-frontend/src/setup/setupSemanticLayer.ts 
b/superset-frontend/src/setup/setupSemanticLayer.ts
new file mode 100644
index 0000000000..b7816890a5
--- /dev/null
+++ b/superset-frontend/src/setup/setupSemanticLayer.ts
@@ -0,0 +1,41 @@
+/**
+ * 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 { setSemanticLayerUtilities } from '@superset-ui/chart-controls';
+import withAsyncVerification from 
'src/explore/components/controls/withAsyncVerification';
+import {
+  createMetricsVerification,
+  createColumnsVerification,
+  createSemanticLayerOnChange,
+  SEMANTIC_LAYER_CONTROL_FIELDS,
+} from 'src/explore/components/controls/SemanticLayerVerification';
+
+/**
+ * Initialize semantic layer controls by setting up the utilities
+ * in the chart controls package.
+ */
+export default function setupSemanticLayer() {
+  setSemanticLayerUtilities({
+    withAsyncVerification,
+    createMetricsVerification,
+    createColumnsVerification,
+    createSemanticLayerOnChange,
+    SEMANTIC_LAYER_CONTROL_FIELDS,
+  });
+}

Reply via email to