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

maximebeauchemin pushed a commit to branch ts_migrate_claude
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 04ba0a00b37b837558e9a10a47339b32f95f5561
Author: Maxime Beauchemin <maximebeauche...@gmail.com>
AuthorDate: Sun Jul 13 11:22:22 2025 -0700

    src/utils
---
 ...cedMessageQueue.js => DebouncedMessageQueue.ts} | 26 ++++++++--
 .../src/utils/{common.test.jsx => common.test.tsx} |  0
 .../src/utils/{common.js => common.ts}             | 27 ++++++----
 .../{datasourceUtils.js => datasourceUtils.ts}     | 16 +++++-
 .../src/utils/getControlsForVizType.js             | 52 -------------------
 ...zType.test.js => getControlsForVizType.test.ts} |  0
 .../src/utils/getControlsForVizType.ts             | 58 ++++++++++++++++++++++
 .../{hostNamesConfig.js => hostNamesConfig.ts}     |  6 +--
 .../src/utils/{reducerUtils.js => reducerUtils.ts} | 38 ++++++++++++--
 9 files changed, 147 insertions(+), 76 deletions(-)

diff --git a/superset-frontend/src/utils/DebouncedMessageQueue.js 
b/superset-frontend/src/utils/DebouncedMessageQueue.ts
similarity index 73%
rename from superset-frontend/src/utils/DebouncedMessageQueue.js
rename to superset-frontend/src/utils/DebouncedMessageQueue.ts
index 6fd6c5b778..cf1550ad75 100644
--- a/superset-frontend/src/utils/DebouncedMessageQueue.js
+++ b/superset-frontend/src/utils/DebouncedMessageQueue.ts
@@ -18,33 +18,49 @@
  */
 import { debounce } from 'lodash';
 
+interface DebouncedMessageQueueConfig {
+  callback?: (events: any[]) => void;
+  sizeThreshold?: number;
+  delayThreshold?: number;
+}
+
 class DebouncedMessageQueue {
+  private queue: any[];
+
+  private sizeThreshold: number;
+
+  private delayThreshold: number;
+
+  private callback: (events: any[]) => void;
+
+  private trigger: () => void;
+
   constructor({
     callback = () => {},
     sizeThreshold = 1000,
     delayThreshold = 1000,
-  }) {
+  }: DebouncedMessageQueueConfig = {}) {
     this.queue = [];
     this.sizeThreshold = sizeThreshold;
     this.delayThreshold = delayThreshold;
 
-    this.trigger = debounce(this.trigger.bind(this), this.delayThreshold);
+    this.trigger = debounce(this.triggerQueue.bind(this), this.delayThreshold);
     this.callback = callback;
   }
 
-  append(eventData) {
+  append(eventData: any): void {
     this.queue.push(eventData);
     this.trigger();
   }
 
-  trigger() {
+  private triggerQueue(): void {
     if (this.queue.length > 0) {
       const events = this.queue.splice(0, this.sizeThreshold);
       this.callback.call(null, events);
 
       // If there are remaining items, call it again.
       if (this.queue.length > 0) {
-        this.trigger();
+        this.triggerQueue();
       }
     }
   }
diff --git a/superset-frontend/src/utils/common.test.jsx 
b/superset-frontend/src/utils/common.test.tsx
similarity index 100%
rename from superset-frontend/src/utils/common.test.jsx
rename to superset-frontend/src/utils/common.test.tsx
diff --git a/superset-frontend/src/utils/common.js 
b/superset-frontend/src/utils/common.ts
similarity index 85%
rename from superset-frontend/src/utils/common.js
rename to superset-frontend/src/utils/common.ts
index 4ceceb0b41..ad51161565 100644
--- a/superset-frontend/src/utils/common.js
+++ b/superset-frontend/src/utils/common.ts
@@ -21,6 +21,7 @@ import {
   getTimeFormatter,
   TimeFormats,
   ensureIsArray,
+  JsonObject,
 } from '@superset-ui/core';
 
 // ATTENTION: If you change any constants, make sure to also change 
constants.py
@@ -36,7 +37,7 @@ export const SHORT_TIME = 'h:m a';
 
 const DATETIME_FORMATTER = getTimeFormatter(TimeFormats.DATABASE_DATETIME);
 
-export function storeQuery(query) {
+export function storeQuery(query: JsonObject): Promise<string> {
   return SupersetClient.post({
     endpoint: '/kv/store/',
     postPayload: { data: query },
@@ -47,7 +48,7 @@ export function storeQuery(query) {
   });
 }
 
-export function optionLabel(opt) {
+export function optionLabel(opt: any): string {
   if (opt === null) {
     return NULL_STRING;
   }
@@ -66,23 +67,26 @@ export function optionLabel(opt) {
   return opt;
 }
 
-export function optionValue(opt) {
+export function optionValue(opt: any): any {
   if (opt === null) {
     return NULL_STRING;
   }
   return opt;
 }
 
-export function optionFromValue(opt) {
+export function optionFromValue(opt: any): { value: any; label: string } {
   // From a list of options, handles special values & labels
   return { value: optionValue(opt), label: optionLabel(opt) };
 }
 
-function getColumnName(column) {
+function getColumnName(column: any): string {
   return column.name || column;
 }
 
-export function prepareCopyToClipboardTabularData(data, columns) {
+export function prepareCopyToClipboardTabularData(
+  data: JsonObject[],
+  columns: any[],
+): string {
   let result = columns.length
     ? `${columns.map(getColumnName).join('\t')}\n`
     : '';
@@ -103,7 +107,10 @@ export function prepareCopyToClipboardTabularData(data, 
columns) {
   return result;
 }
 
-export function applyFormattingToTabularData(data, timeFormattedColumns) {
+export function applyFormattingToTabularData(
+  data: JsonObject[],
+  timeFormattedColumns: string[],
+): JsonObject[] {
   if (
     !data ||
     data.length === 0 ||
@@ -124,10 +131,10 @@ export function applyFormattingToTabularData(data, 
timeFormattedColumns) {
   }));
 }
 
-export const noOp = () => undefined;
+export const noOp = (): undefined => undefined;
 
 // Detects the user's OS through the browser
-export const detectOS = () => {
+export const detectOS = (): string => {
   const { appVersion } = navigator;
 
   // Leveraging this condition because of stackOverflow
@@ -140,7 +147,7 @@ export const detectOS = () => {
   return 'Unknown OS';
 };
 
-export const isSafari = () => {
+export const isSafari = (): boolean => {
   const { userAgent } = navigator;
 
   return userAgent && /^((?!chrome|android).)*safari/i.test(userAgent);
diff --git a/superset-frontend/src/utils/datasourceUtils.js 
b/superset-frontend/src/utils/datasourceUtils.ts
similarity index 76%
rename from superset-frontend/src/utils/datasourceUtils.js
rename to superset-frontend/src/utils/datasourceUtils.ts
index 144a3ff88b..20ab4329bb 100644
--- a/superset-frontend/src/utils/datasourceUtils.js
+++ b/superset-frontend/src/utils/datasourceUtils.ts
@@ -16,7 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-export const getDatasourceAsSaveableDataset = source => ({
+import { Dataset } from '@superset-ui/chart-controls';
+
+interface SaveableDataset {
+  columns: any[];
+  name: string;
+  dbId?: number;
+  sql: string;
+  catalog?: string | null;
+  schema?: string;
+  templateParams?: string;
+}
+
+export const getDatasourceAsSaveableDataset = (
+  source: Partial<Dataset>,
+): SaveableDataset => ({
   columns: source.columns,
   name: source?.datasource_name || source?.name || 'Untitled',
   dbId: source?.database?.id || source?.dbId,
diff --git a/superset-frontend/src/utils/getControlsForVizType.js 
b/superset-frontend/src/utils/getControlsForVizType.js
deleted file mode 100644
index 8771d91dc7..0000000000
--- a/superset-frontend/src/utils/getControlsForVizType.js
+++ /dev/null
@@ -1,52 +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 memoizeOne from 'memoize-one';
-import { isControlPanelSectionConfig } from '@superset-ui/chart-controls';
-import { getChartControlPanelRegistry } from '@superset-ui/core';
-import { controls } from '../explore/controls';
-
-const memoizedControls = memoizeOne((vizType, controlPanel) => {
-  const controlsMap = {};
-  (controlPanel?.controlPanelSections || [])
-    .filter(isControlPanelSectionConfig)
-    .forEach(section => {
-      section.controlSetRows.forEach(row => {
-        row.forEach(control => {
-          if (!control) return;
-          if (typeof control === 'string') {
-            // For now, we have to look in controls.jsx to get the config for 
some controls.
-            // Once everything is migrated out, delete this if statement.
-            controlsMap[control] = controls[control];
-          } else if (control.name && control.config) {
-            // condition needed because there are elements, e.g. <hr /> in 
some control configs (I'm looking at you, FilterBox!)
-            controlsMap[control.name] = control.config;
-          }
-        });
-      });
-    });
-  return controlsMap;
-});
-
-const getControlsForVizType = vizType => {
-  const controlPanel = getChartControlPanelRegistry().get(vizType);
-  return memoizedControls(vizType, controlPanel);
-};
-
-export default getControlsForVizType;
diff --git a/superset-frontend/src/utils/getControlsForVizType.test.js 
b/superset-frontend/src/utils/getControlsForVizType.test.ts
similarity index 100%
rename from superset-frontend/src/utils/getControlsForVizType.test.js
rename to superset-frontend/src/utils/getControlsForVizType.test.ts
diff --git a/superset-frontend/src/utils/getControlsForVizType.ts 
b/superset-frontend/src/utils/getControlsForVizType.ts
new file mode 100644
index 0000000000..c77ca77d2e
--- /dev/null
+++ b/superset-frontend/src/utils/getControlsForVizType.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 memoizeOne from 'memoize-one';
+import {
+  isControlPanelSectionConfig,
+  ControlStateMapping,
+  ControlPanelConfig,
+} from '@superset-ui/chart-controls';
+import { getChartControlPanelRegistry } from '@superset-ui/core';
+import { controls } from '../explore/controls';
+
+const memoizedControls = memoizeOne(
+  (vizType: string, controlPanel: ControlPanelConfig): ControlStateMapping => {
+    const controlsMap: ControlStateMapping = {};
+    (controlPanel?.controlPanelSections || [])
+      .filter(isControlPanelSectionConfig)
+      .forEach(section => {
+        section.controlSetRows.forEach(row => {
+          row.forEach(control => {
+            if (!control) return;
+            if (typeof control === 'string') {
+              // For now, we have to look in controls.jsx to get the config 
for some controls.
+              // Once everything is migrated out, delete this if statement.
+              controlsMap[control] = controls[control];
+            } else if (control.name && control.config) {
+              // condition needed because there are elements, e.g. <hr /> in 
some control configs (I'm looking at you, FilterBox!)
+              controlsMap[control.name] = control.config;
+            }
+          });
+        });
+      });
+    return controlsMap;
+  },
+);
+
+const getControlsForVizType = (vizType: string): ControlStateMapping => {
+  const controlPanel = getChartControlPanelRegistry().get(vizType);
+  return memoizedControls(vizType, controlPanel);
+};
+
+export default getControlsForVizType;
diff --git a/superset-frontend/src/utils/hostNamesConfig.js 
b/superset-frontend/src/utils/hostNamesConfig.ts
similarity index 91%
rename from superset-frontend/src/utils/hostNamesConfig.js
rename to superset-frontend/src/utils/hostNamesConfig.ts
index 2ba9b7555c..f2359f2e84 100644
--- a/superset-frontend/src/utils/hostNamesConfig.js
+++ b/superset-frontend/src/utils/hostNamesConfig.ts
@@ -19,7 +19,7 @@
 import { initFeatureFlags } from '@superset-ui/core';
 import getBootstrapData from './getBootstrapData';
 
-function getDomainsConfig() {
+function getDomainsConfig(): string[] {
   const appContainer = document.getElementById('app');
   if (!appContainer) {
     return [];
@@ -49,6 +49,6 @@ function getDomainsConfig() {
   return Array.from(availableDomains);
 }
 
-export const availableDomains = getDomainsConfig();
+export const availableDomains: string[] = getDomainsConfig();
 
-export const allowCrossDomain = availableDomains.length > 1;
+export const allowCrossDomain: boolean = availableDomains.length > 1;
diff --git a/superset-frontend/src/utils/reducerUtils.js 
b/superset-frontend/src/utils/reducerUtils.ts
similarity index 72%
rename from superset-frontend/src/utils/reducerUtils.js
rename to superset-frontend/src/utils/reducerUtils.ts
index 199c8aa292..300f878d94 100644
--- a/superset-frontend/src/utils/reducerUtils.js
+++ b/superset-frontend/src/utils/reducerUtils.ts
@@ -18,7 +18,16 @@
  */
 import { nanoid } from 'nanoid';
 
-export function addToObject(state, arrKey, obj) {
+interface StateWithId {
+  id?: string;
+  [key: string]: any;
+}
+
+export function addToObject<T extends Record<string, any>>(
+  state: T,
+  arrKey: keyof T,
+  obj: StateWithId,
+): T {
   const newObject = { ...state[arrKey] };
   const copiedObject = { ...obj };
 
@@ -29,13 +38,23 @@ export function addToObject(state, arrKey, obj) {
   return { ...state, [arrKey]: newObject };
 }
 
-export function alterInObject(state, arrKey, obj, alterations) {
+export function alterInObject<T extends Record<string, any>>(
+  state: T,
+  arrKey: keyof T,
+  obj: StateWithId,
+  alterations: Record<string, any>,
+): T {
   const newObject = { ...state[arrKey] };
   newObject[obj.id] = { ...newObject[obj.id], ...alterations };
   return { ...state, [arrKey]: newObject };
 }
 
-export function alterInArr(state, arrKey, obj, alterations) {
+export function alterInArr<T extends Record<string, any>>(
+  state: T,
+  arrKey: keyof T,
+  obj: StateWithId,
+  alterations: Record<string, any>,
+): T {
   // Finds an item in an array in the state and replaces it with a
   // new object with an altered property
   const idKey = 'id';
@@ -50,7 +69,12 @@ export function alterInArr(state, arrKey, obj, alterations) {
   return { ...state, [arrKey]: newArr };
 }
 
-export function removeFromArr(state, arrKey, obj, idKey = 'id') {
+export function removeFromArr<T extends Record<string, any>>(
+  state: T,
+  arrKey: keyof T,
+  obj: StateWithId,
+  idKey: string = 'id',
+): T {
   const newArr = [];
   state[arrKey].forEach(arrItem => {
     if (!(obj[idKey] === arrItem[idKey])) {
@@ -60,7 +84,11 @@ export function removeFromArr(state, arrKey, obj, idKey = 
'id') {
   return { ...state, [arrKey]: newArr };
 }
 
-export function addToArr(state, arrKey, obj) {
+export function addToArr<T extends Record<string, any>>(
+  state: T,
+  arrKey: keyof T,
+  obj: StateWithId,
+): T {
   const newObj = { ...obj };
   if (!newObj.id) {
     newObj.id = nanoid();

Reply via email to