You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by be...@apache.org on 2026/02/17 16:06:54 UTC

(superset) 04/07: Dynamic

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

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

commit 3d8acd5b719ff646524469aba389995ffb616b33
Author: Beto Dealmeida <ro...@dealmeida.net>
AuthorDate: Fri Feb 13 16:46:36 2026 -0500

    Dynamic
---
 .../features/semanticLayers/SemanticLayerModal.tsx | 219 ++++++++++++++++++---
 superset/static/service-worker.js                  | 206 +++++++++----------
 2 files changed, 291 insertions(+), 134 deletions(-)

diff --git a/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx b/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
index 0e176fa081b..045b102aa38 100644
--- a/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
+++ b/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
@@ -22,11 +22,23 @@ import { styled } from '@apache-superset/core/ui';
 import { SupersetClient } from '@superset-ui/core';
 import { Select } from '@superset-ui/core/components';
 import { Icons } from '@superset-ui/core/components/Icons';
-import { JsonForms } from '@jsonforms/react';
-import type { JsonSchema, UISchemaElement } from '@jsonforms/core';
+import { JsonForms, withJsonFormsControlProps } from '@jsonforms/react';
+import type {
+  JsonSchema,
+  UISchemaElement,
+  ControlProps,
+} from '@jsonforms/core';
+import {
+  rankWith,
+  and,
+  isStringControl,
+  formatIs,
+  schemaMatches,
+} from '@jsonforms/core';
 import {
   rendererRegistryEntries,
   cellRegistryEntries,
+  TextControl,
 } from '@great-expectations/jsonforms-antd-renderers';
 import type { ErrorObject } from 'ajv';
 import {
@@ -36,9 +48,50 @@ import {
   MODAL_MEDIUM_WIDTH,
 } from 'src/components/Modal';
 
+/**
+ * Custom renderer that renders `Input.Password` for fields with
+ * `format: "password"` in the JSON Schema (e.g. Pydantic `SecretStr`).
+ */
+function PasswordControl(props: ControlProps) {
+  const uischema = {
+    ...props.uischema,
+    options: { ...props.uischema.options, type: 'password' },
+  };
+  return TextControl({ ...props, uischema });
+}
+const PasswordRenderer = withJsonFormsControlProps(PasswordControl);
+const passwordEntry = {
+  tester: rankWith(3, and(isStringControl, formatIs('password'))),
+  renderer: PasswordRenderer,
+};
+
+/**
+ * Renderer for `const` properties (e.g. Pydantic discriminator fields).
+ * Renders nothing visually but ensures the const value is set in form data,
+ * so discriminated unions resolve correctly on the backend.
+ */
+function ConstControl({ data, handleChange, path, schema }: ControlProps) {
+  const constValue = (schema as Record<string, unknown>).const;
+  useEffect(() => {
+    if (constValue !== undefined && data !== constValue) {
+      handleChange(path, constValue);
+    }
+  }, [constValue, data, handleChange, path]);
+  return null;
+}
+const ConstRenderer = withJsonFormsControlProps(ConstControl);
+const constEntry = {
+  tester: rankWith(10, schemaMatches(s => s !== undefined && 'const' in s)),
+  renderer: ConstRenderer,
+};
+
+const renderers = [...rendererRegistryEntries, passwordEntry, constEntry];
+
 type Step = 'type' | 'config';
 type ValidationMode = 'ValidateAndHide' | 'ValidateAndShow';
 
+const SCHEMA_REFRESH_DEBOUNCE_MS = 500;
+
 /**
  * Removes empty `enum` arrays from schema properties. The JSON Schema spec
  * requires `enum` to have at least one item, and AJV rejects empty arrays.
@@ -108,6 +161,69 @@ function buildUiSchema(
   return { type: 'VerticalLayout', elements } as UISchemaElement;
 }
 
+/**
+ * Extracts dynamic field dependency mappings from the schema.
+ * Returns a map of field name → list of dependency field names.
+ */
+function getDynamicDependencies(
+  schema: JsonSchema,
+): Record<string, string[]> {
+  const deps: Record<string, string[]> = {};
+  if (!schema.properties) return deps;
+  for (const [key, prop] of Object.entries(schema.properties)) {
+    if (
+      typeof prop === 'object' &&
+      prop !== null &&
+      'x-dynamic' in prop &&
+      'x-dependsOn' in prop &&
+      Array.isArray((prop as Record<string, unknown>)['x-dependsOn'])
+    ) {
+      deps[key] = (prop as Record<string, unknown>)[
+        'x-dependsOn'
+      ] as string[];
+    }
+  }
+  return deps;
+}
+
+/**
+ * Checks whether all dependency values are filled (non-empty).
+ * Handles nested objects (like auth) by checking they have at least one key.
+ */
+function areDependenciesSatisfied(
+  dependencies: string[],
+  data: Record<string, unknown>,
+): boolean {
+  return dependencies.every(dep => {
+    const value = data[dep];
+    if (value === null || value === undefined || value === '') return false;
+    if (typeof value === 'object' && Object.keys(value).length === 0)
+      return false;
+    return true;
+  });
+}
+
+/**
+ * Serializes the dependency values for a set of fields into a stable string
+ * for comparison, so we only re-fetch when dependency values actually change.
+ */
+function serializeDependencyValues(
+  dynamicDeps: Record<string, string[]>,
+  data: Record<string, unknown>,
+): string {
+  const allDepKeys = new Set<string>();
+  for (const deps of Object.values(dynamicDeps)) {
+    for (const dep of deps) {
+      allDepKeys.add(dep);
+    }
+  }
+  const snapshot: Record<string, unknown> = {};
+  for (const key of [...allDepKeys].sort()) {
+    snapshot[key] = data[key];
+  }
+  return JSON.stringify(snapshot);
+}
+
 const ModalContent = styled.div`
   padding: ${({ theme }) => theme.sizeUnit * 4}px;
 `;
@@ -161,6 +277,9 @@ export default function SemanticLayerModal({
   const [validationMode, setValidationMode] =
     useState<ValidationMode>('ValidateAndHide');
   const errorsRef = useRef<ErrorObject[]>([]);
+  const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
+  const lastDepSnapshotRef = useRef<string>('');
+  const dynamicDepsRef = useRef<Record<string, string[]>>({});
 
   const fetchTypes = useCallback(async () => {
     setLoading(true);
@@ -178,27 +297,35 @@ export default function SemanticLayerModal({
     }
   }, [addDangerToast]);
 
+  const applySchema = useCallback((rawSchema: JsonSchema) => {
+    const schema = sanitizeSchema(rawSchema);
+    setConfigSchema(schema);
+    setUiSchema(buildUiSchema(schema));
+    dynamicDepsRef.current = getDynamicDependencies(rawSchema);
+  }, []);
+
   const fetchConfigSchema = useCallback(
-    async (type: string) => {
-      setLoading(true);
+    async (type: string, configuration?: Record<string, unknown>) => {
+      const isInitialFetch = !configuration;
+      if (isInitialFetch) setLoading(true);
       try {
         const { json } = await SupersetClient.post({
           endpoint: '/api/v1/semantic_layer/schema/configuration',
-          jsonPayload: { type },
+          jsonPayload: { type, configuration },
         });
-        const schema: JsonSchema = sanitizeSchema(json.result);
-        setConfigSchema(schema);
-        setUiSchema(buildUiSchema(schema));
-        setStep('config');
+        applySchema(json.result);
+        if (isInitialFetch) setStep('config');
       } catch {
-        addDangerToast(
-          t('An error occurred while fetching the configuration schema'),
-        );
+        if (isInitialFetch) {
+          addDangerToast(
+            t('An error occurred while fetching the configuration schema'),
+          );
+        }
       } finally {
-        setLoading(false);
+        if (isInitialFetch) setLoading(false);
       }
     },
-    [addDangerToast],
+    [addDangerToast, applySchema],
   );
 
   useEffect(() => {
@@ -213,6 +340,9 @@ export default function SemanticLayerModal({
       setFormData({});
       setValidationMode('ValidateAndHide');
       errorsRef.current = [];
+      lastDepSnapshotRef.current = '';
+      dynamicDepsRef.current = {};
+      if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
     }
   }, [show, fetchTypes]);
 
@@ -229,6 +359,9 @@ export default function SemanticLayerModal({
     setFormData({});
     setValidationMode('ValidateAndHide');
     errorsRef.current = [];
+    lastDepSnapshotRef.current = '';
+    dynamicDepsRef.current = {};
+    if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
   };
 
   const handleCreate = async () => {
@@ -258,22 +391,46 @@ export default function SemanticLayerModal({
     }
   };
 
-  const handleFormChange = ({
-    data,
-    errors,
-  }: {
-    data: Record<string, unknown>;
-    errors?: ErrorObject[];
-  }) => {
-    setFormData(data);
-    errorsRef.current = errors ?? [];
-    if (
-      validationMode === 'ValidateAndShow' &&
-      errorsRef.current.length === 0
-    ) {
-      handleCreate();
-    }
-  };
+  const maybeRefreshSchema = useCallback(
+    (data: Record<string, unknown>) => {
+      if (!selectedType) return;
+
+      const dynamicDeps = dynamicDepsRef.current;
+      if (Object.keys(dynamicDeps).length === 0) return;
+
+      // Check if any dynamic field has all dependencies satisfied
+      const hasSatisfiedDeps = Object.values(dynamicDeps).some(deps =>
+        areDependenciesSatisfied(deps, data),
+      );
+      if (!hasSatisfiedDeps) return;
+
+      // Only re-fetch if dependency values actually changed
+      const snapshot = serializeDependencyValues(dynamicDeps, data);
+      if (snapshot === lastDepSnapshotRef.current) return;
+      lastDepSnapshotRef.current = snapshot;
+
+      if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
+      debounceTimerRef.current = setTimeout(() => {
+        fetchConfigSchema(selectedType, data);
+      }, SCHEMA_REFRESH_DEBOUNCE_MS);
+    },
+    [selectedType, fetchConfigSchema],
+  );
+
+  const handleFormChange = useCallback(
+    ({ data, errors }: { data: Record<string, unknown>; errors?: ErrorObject[] }) => {
+      setFormData(data);
+      errorsRef.current = errors ?? [];
+      if (
+        validationMode === 'ValidateAndShow' &&
+        errorsRef.current.length === 0
+      ) {
+        handleCreate();
+      }
+      maybeRefreshSchema(data);
+    },
+    [validationMode, handleCreate, maybeRefreshSchema],
+  );
 
   const selectedTypeName =
     types.find(type => type.id === selectedType)?.name ?? '';
@@ -328,7 +485,7 @@ export default function SemanticLayerModal({
               schema={configSchema}
               uischema={uiSchema}
               data={formData}
-              renderers={rendererRegistryEntries}
+              renderers={renderers}
               cells={cellRegistryEntries}
               validationMode={validationMode}
               onChange={handleFormChange}
diff --git a/superset/static/service-worker.js b/superset/static/service-worker.js
index 1b47c746120..d0398cca888 100644
--- a/superset/static/service-worker.js
+++ b/superset/static/service-worker.js
@@ -24,7 +24,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /************************************************************************/
 /******/ 	// The module cache
 /******/ 	var __webpack_module_cache__ = {};
-/******/ 	
+/******/
 /******/ 	// The require function
 /******/ 	function __webpack_require__(moduleId) {
 /******/ 		// Check if module is in cache
@@ -44,29 +44,29 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			loaded: false,
 /******/ 			exports: {}
 /******/ 		};
-/******/ 	
+/******/
 /******/ 		// Execute the module function
 /******/ 		var execOptions = { id: moduleId, module: module, factory: __webpack_modules__[moduleId], require: __webpack_require__ };
 /******/ 		__webpack_require__.i.forEach(function(handler) { handler(execOptions); });
 /******/ 		module = execOptions.module;
 /******/ 		execOptions.factory.call(module.exports, module, module.exports, execOptions.require);
-/******/ 	
+/******/
 /******/ 		// Flag the module as loaded
 /******/ 		module.loaded = true;
-/******/ 	
+/******/
 /******/ 		// Return the exports of the module
 /******/ 		return module.exports;
 /******/ 	}
-/******/ 	
+/******/
 /******/ 	// expose the modules object (__webpack_modules__)
 /******/ 	__webpack_require__.m = __webpack_modules__;
-/******/ 	
+/******/
 /******/ 	// expose the module cache
 /******/ 	__webpack_require__.c = __webpack_module_cache__;
-/******/ 	
+/******/
 /******/ 	// expose the module execution interceptor
 /******/ 	__webpack_require__.i = [];
-/******/ 	
+/******/
 /************************************************************************/
 /******/ 	/* webpack/runtime/chunk loaded */
 /******/ 	(() => {
@@ -99,7 +99,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return result;
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/compat get default export */
 /******/ 	(() => {
 /******/ 		// getDefaultExport function for compatibility with non-harmony modules
@@ -111,7 +111,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return getter;
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/create fake namespace object */
 /******/ 	(() => {
 /******/ 		var getProto = Object.getPrototypeOf ? (obj) => (Object.getPrototypeOf(obj)) : (obj) => (obj.__proto__);
@@ -141,7 +141,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return ns;
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/define property getters */
 /******/ 	(() => {
 /******/ 		// define getter functions for harmony exports
@@ -153,7 +153,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			}
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/get javascript update chunk filename */
 /******/ 	(() => {
 /******/ 		// This function allow to reference all chunks
@@ -162,17 +162,17 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return "" + chunkId + "." + __webpack_require__.h() + ".hot-update.js";
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/get update manifest filename */
 /******/ 	(() => {
 /******/ 		__webpack_require__.hmrF = () => ("service-worker." + __webpack_require__.h() + ".hot-update.json");
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/getFullHash */
 /******/ 	(() => {
-/******/ 		__webpack_require__.h = () => ("00be46f47da6fd073e72")
+/******/ 		__webpack_require__.h = () => ("f2a1d44b322dddcb4e87")
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/harmony module decorator */
 /******/ 	(() => {
 /******/ 		__webpack_require__.hmd = (module) => {
@@ -187,12 +187,12 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return module;
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/hasOwnProperty shorthand */
 /******/ 	(() => {
 /******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/load script */
 /******/ 	(() => {
 /******/ 		var inProgress = {};
@@ -211,13 +211,13 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			if(!script) {
 /******/ 				needAttach = true;
 /******/ 				script = document.createElement('script');
-/******/ 		
+/******/
 /******/ 				script.charset = 'utf-8';
 /******/ 				if (__webpack_require__.nc) {
 /******/ 					script.setAttribute("nonce", __webpack_require__.nc);
 /******/ 				}
 /******/ 				script.setAttribute("data-webpack", dataWebpackPrefix + key);
-/******/ 		
+/******/
 /******/ 				script.src = url;
 /******/ 			}
 /******/ 			inProgress[url] = [done];
@@ -237,7 +237,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			needAttach && document.head.appendChild(script);
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/make namespace object */
 /******/ 	(() => {
 /******/ 		// define __esModule on exports
@@ -248,7 +248,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			Object.defineProperty(exports, '__esModule', { value: true });
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/node module decorator */
 /******/ 	(() => {
 /******/ 		__webpack_require__.nmd = (module) => {
@@ -257,7 +257,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return module;
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/sharing */
 /******/ 	(() => {
 /******/ 		__webpack_require__.S = {};
@@ -309,30 +309,30 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			return initPromises[name] = Promise.all(promises).then(() => (initPromises[name] = 1));
 /******/ 		};
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/hot module replacement */
 /******/ 	(() => {
 /******/ 		var currentModuleData = {};
 /******/ 		var installedModules = __webpack_require__.c;
-/******/ 		
+/******/
 /******/ 		// module and require creation
 /******/ 		var currentChildModule;
 /******/ 		var currentParents = [];
-/******/ 		
+/******/
 /******/ 		// status
 /******/ 		var registeredStatusHandlers = [];
 /******/ 		var currentStatus = "idle";
-/******/ 		
+/******/
 /******/ 		// while downloading
 /******/ 		var blockingPromises = 0;
 /******/ 		var blockingPromisesWaiting = [];
-/******/ 		
+/******/
 /******/ 		// The update info
 /******/ 		var currentUpdateApplyHandlers;
 /******/ 		var queuedInvalidatedModules;
-/******/ 		
+/******/
 /******/ 		__webpack_require__.hmrD = currentModuleData;
-/******/ 		
+/******/
 /******/ 		__webpack_require__.i.push(function (options) {
 /******/ 			var module = options.module;
 /******/ 			var require = createRequire(options.require, options.id);
@@ -342,10 +342,10 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			currentParents = [];
 /******/ 			options.require = require;
 /******/ 		});
-/******/ 		
+/******/
 /******/ 		__webpack_require__.hmrC = {};
 /******/ 		__webpack_require__.hmrI = {};
-/******/ 		
+/******/
 /******/ 		function createRequire(require, moduleId) {
 /******/ 			var me = installedModules[moduleId];
 /******/ 			if (!me) return require;
@@ -396,7 +396,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			};
 /******/ 			return fn;
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function createModuleHotObject(moduleId, me) {
 /******/ 			var _main = currentChildModule !== moduleId;
 /******/ 			var hot = {
@@ -414,7 +414,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					currentChildModule = _main ? undefined : moduleId;
 /******/ 					__webpack_require__(moduleId);
 /******/ 				},
-/******/ 		
+/******/
 /******/ 				// Module API
 /******/ 				active: true,
 /******/ 				accept: function (dep, callback, errorHandler) {
@@ -481,7 +481,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							break;
 /******/ 					}
 /******/ 				},
-/******/ 		
+/******/
 /******/ 				// Management API
 /******/ 				check: hotCheck,
 /******/ 				apply: hotApply,
@@ -496,24 +496,24 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					var idx = registeredStatusHandlers.indexOf(l);
 /******/ 					if (idx >= 0) registeredStatusHandlers.splice(idx, 1);
 /******/ 				},
-/******/ 		
+/******/
 /******/ 				// inherit from previous dispose call
 /******/ 				data: currentModuleData[moduleId]
 /******/ 			};
 /******/ 			currentChildModule = undefined;
 /******/ 			return hot;
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function setStatus(newStatus) {
 /******/ 			currentStatus = newStatus;
 /******/ 			var results = [];
-/******/ 		
+/******/
 /******/ 			for (var i = 0; i < registeredStatusHandlers.length; i++)
 /******/ 				results[i] = registeredStatusHandlers[i].call(null, newStatus);
-/******/ 		
+/******/
 /******/ 			return Promise.all(results).then(function () {});
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function unblock() {
 /******/ 			if (--blockingPromises === 0) {
 /******/ 				setStatus("ready").then(function () {
@@ -527,7 +527,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				});
 /******/ 			}
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function trackBlockingPromise(promise) {
 /******/ 			switch (currentStatus) {
 /******/ 				case "ready":
@@ -541,7 +541,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					return promise;
 /******/ 			}
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function waitForBlockingPromises(fn) {
 /******/ 			if (blockingPromises === 0) return fn();
 /******/ 			return new Promise(function (resolve) {
@@ -550,7 +550,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				});
 /******/ 			});
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function hotCheck(applyOnUpdate) {
 /******/ 			if (currentStatus !== "idle") {
 /******/ 				throw new Error("check() is only allowed in idle status");
@@ -565,11 +565,11 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							}
 /******/ 						);
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					return setStatus("prepare").then(function () {
 /******/ 						var updatedModules = [];
 /******/ 						currentUpdateApplyHandlers = [];
-/******/ 		
+/******/
 /******/ 						return Promise.all(
 /******/ 							Object.keys(__webpack_require__.hmrC).reduce(function (
 /******/ 								promises,
@@ -599,7 +599,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					});
 /******/ 				});
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function hotApply(options) {
 /******/ 			if (currentStatus !== "ready") {
 /******/ 				return Promise.resolve().then(function () {
@@ -612,46 +612,46 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			}
 /******/ 			return internalApply(options);
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function internalApply(options) {
 /******/ 			options = options || {};
-/******/ 		
+/******/
 /******/ 			applyInvalidatedModules();
-/******/ 		
+/******/
 /******/ 			var results = currentUpdateApplyHandlers.map(function (handler) {
 /******/ 				return handler(options);
 /******/ 			});
 /******/ 			currentUpdateApplyHandlers = undefined;
-/******/ 		
+/******/
 /******/ 			var errors = results
 /******/ 				.map(function (r) {
 /******/ 					return r.error;
 /******/ 				})
 /******/ 				.filter(Boolean);
-/******/ 		
+/******/
 /******/ 			if (errors.length > 0) {
 /******/ 				return setStatus("abort").then(function () {
 /******/ 					throw errors[0];
 /******/ 				});
 /******/ 			}
-/******/ 		
+/******/
 /******/ 			// Now in "dispose" phase
 /******/ 			var disposePromise = setStatus("dispose");
-/******/ 		
+/******/
 /******/ 			results.forEach(function (result) {
 /******/ 				if (result.dispose) result.dispose();
 /******/ 			});
-/******/ 		
+/******/
 /******/ 			// Now in "apply" phase
 /******/ 			var applyPromise = setStatus("apply");
-/******/ 		
+/******/
 /******/ 			var error;
 /******/ 			var reportError = function (err) {
 /******/ 				if (!error) error = err;
 /******/ 			};
-/******/ 		
+/******/
 /******/ 			var outdatedModules = [];
-/******/ 		
+/******/
 /******/ 			var onAccepted = function () {
 /******/ 				return Promise.all([disposePromise, applyPromise]).then(function () {
 /******/ 					// handle errors in accept handlers and self accepted module load
@@ -660,7 +660,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							throw error;
 /******/ 						});
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					if (queuedInvalidatedModules) {
 /******/ 						return internalApply(options).then(function (list) {
 /******/ 							outdatedModules.forEach(function (moduleId) {
@@ -669,13 +669,13 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							return list;
 /******/ 						});
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					return setStatus("idle").then(function () {
 /******/ 						return outdatedModules;
 /******/ 					});
 /******/ 				});
 /******/ 			};
-/******/ 		
+/******/
 /******/ 			return Promise.all(
 /******/ 				results
 /******/ 					.filter(function (result) {
@@ -696,7 +696,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				})
 /******/ 				.then(onAccepted);
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		function applyInvalidatedModules() {
 /******/ 			if (queuedInvalidatedModules) {
 /******/ 				if (!currentUpdateApplyHandlers) currentUpdateApplyHandlers = [];
@@ -713,12 +713,12 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			}
 /******/ 		}
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/publicPath */
 /******/ 	(() => {
 /******/ 		__webpack_require__.p = "/static/assets/";
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/react refresh */
 /******/ 	(() => {
 /******/ 		const setup = (moduleId) => {
@@ -736,7 +736,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			};
 /******/ 			return refresh;
 /******/ 		};
-/******/ 		
+/******/
 /******/ 		__webpack_require__.i.push((options) => {
 /******/ 			const originalFactory = options.factory;
 /******/ 			options.factory = function(moduleObject, moduleExports, webpackRequire) {
@@ -762,7 +762,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			};
 /******/ 		});
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/consumes */
 /******/ 	(() => {
 /******/ 		var parseVersion = (str) => {
@@ -843,7 +843,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			}
 /******/ 			return fn(scopeName, __webpack_require__.S[scopeName], key, eager, c, d);
 /******/ 		});
-/******/ 		
+/******/
 /******/ 		var useFallback = (scopeName, key, fallback) => {
 /******/ 			return fallback ? fallback() : failAsNotExist(scopeName, key);
 /******/ 		}
@@ -904,11 +904,11 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 		});
 /******/ 		// no chunk loading of consumes
 /******/ 	})();
-/******/ 	
+/******/
 /******/ 	/* webpack/runtime/jsonp chunk loading */
 /******/ 	(() => {
 /******/ 		// no baseURI
-/******/ 		
+/******/
 /******/ 		// object to store loaded and loading chunks
 /******/ 		// undefined = chunk not loaded, null = chunk preloaded/prefetched
 /******/ 		// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
@@ -916,13 +916,13 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			"service-worker": 0,
 /******/ 			"webpack_sharing_consume_default_react-dom_react-dom-webpack_sharing_consume_default_react_rea-153fef": 0
 /******/ 		};
-/******/ 		
+/******/
 /******/ 		// no chunk on demand loading
-/******/ 		
+/******/
 /******/ 		// no prefetching
-/******/ 		
+/******/
 /******/ 		// no preloaded
-/******/ 		
+/******/
 /******/ 		var currentUpdatedModulesList;
 /******/ 		var waitingUpdateResolves = {};
 /******/ 		function loadUpdateChunk(chunkId, updatedModulesList) {
@@ -948,7 +948,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				__webpack_require__.l(url, loadingEnded);
 /******/ 			});
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		globalThis["webpackHotUpdatesuperset"] = (chunkId, moreModules, runtime) => {
 /******/ 			for(var moduleId in moreModules) {
 /******/ 				if(__webpack_require__.o(moreModules, moduleId)) {
@@ -962,7 +962,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				waitingUpdateResolves[chunkId] = undefined;
 /******/ 			}
 /******/ 		};
-/******/ 		
+/******/
 /******/ 		var currentUpdateChunks;
 /******/ 		var currentUpdate;
 /******/ 		var currentUpdateRemovedChunks;
@@ -973,7 +973,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			function getAffectedModuleEffects(updateModuleId) {
 /******/ 				var outdatedModules = [updateModuleId];
 /******/ 				var outdatedDependencies = {};
-/******/ 		
+/******/
 /******/ 				var queue = outdatedModules.map(function (id) {
 /******/ 					return {
 /******/ 						chain: [id],
@@ -1031,7 +1031,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 						});
 /******/ 					}
 /******/ 				}
-/******/ 		
+/******/
 /******/ 				return {
 /******/ 					type: "accepted",
 /******/ 					moduleId: updateModuleId,
@@ -1039,26 +1039,26 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					outdatedDependencies: outdatedDependencies
 /******/ 				};
 /******/ 			}
-/******/ 		
+/******/
 /******/ 			function addAllToSet(a, b) {
 /******/ 				for (var i = 0; i < b.length; i++) {
 /******/ 					var item = b[i];
 /******/ 					if (a.indexOf(item) === -1) a.push(item);
 /******/ 				}
 /******/ 			}
-/******/ 		
+/******/
 /******/ 			// at begin all updates modules are outdated
 /******/ 			// the "outdated" status can propagate to parents if they don't accept the children
 /******/ 			var outdatedDependencies = {};
 /******/ 			var outdatedModules = [];
 /******/ 			var appliedUpdate = {};
-/******/ 		
+/******/
 /******/ 			var warnUnexpectedRequire = function warnUnexpectedRequire(module) {
 /******/ 				console.warn(
 /******/ 					"[HMR] unexpected require(" + module.id + ") to disposed module"
 /******/ 				);
 /******/ 			};
-/******/ 		
+/******/
 /******/ 			for (var moduleId in currentUpdate) {
 /******/ 				if (__webpack_require__.o(currentUpdate, moduleId)) {
 /******/ 					var newModuleFactory = currentUpdate[moduleId];
@@ -1141,7 +1141,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				}
 /******/ 			}
 /******/ 			currentUpdate = undefined;
-/******/ 		
+/******/
 /******/ 			// Store self accepted outdated modules to require them later by the module system
 /******/ 			var outdatedSelfAcceptedModules = [];
 /******/ 			for (var j = 0; j < outdatedModules.length; j++) {
@@ -1162,41 +1162,41 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 					});
 /******/ 				}
 /******/ 			}
-/******/ 		
+/******/
 /******/ 			var moduleOutdatedDependencies;
-/******/ 		
+/******/
 /******/ 			return {
 /******/ 				dispose: function () {
 /******/ 					currentUpdateRemovedChunks.forEach(function (chunkId) {
 /******/ 						delete installedChunks[chunkId];
 /******/ 					});
 /******/ 					currentUpdateRemovedChunks = undefined;
-/******/ 		
+/******/
 /******/ 					var idx;
 /******/ 					var queue = outdatedModules.slice();
 /******/ 					while (queue.length > 0) {
 /******/ 						var moduleId = queue.pop();
 /******/ 						var module = __webpack_require__.c[moduleId];
 /******/ 						if (!module) continue;
-/******/ 		
+/******/
 /******/ 						var data = {};
-/******/ 		
+/******/
 /******/ 						// Call dispose handlers
 /******/ 						var disposeHandlers = module.hot._disposeHandlers;
 /******/ 						for (j = 0; j < disposeHandlers.length; j++) {
 /******/ 							disposeHandlers[j].call(null, data);
 /******/ 						}
 /******/ 						__webpack_require__.hmrD[moduleId] = data;
-/******/ 		
+/******/
 /******/ 						// disable module (this disables requires from this module)
 /******/ 						module.hot.active = false;
-/******/ 		
+/******/
 /******/ 						// remove module from cache
 /******/ 						delete __webpack_require__.c[moduleId];
-/******/ 		
+/******/
 /******/ 						// when disposing there is no need to call dispose handler
 /******/ 						delete outdatedDependencies[moduleId];
-/******/ 		
+/******/
 /******/ 						// remove "parents" references from all children
 /******/ 						for (j = 0; j < module.children.length; j++) {
 /******/ 							var child = __webpack_require__.c[module.children[j]];
@@ -1207,7 +1207,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							}
 /******/ 						}
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					// remove outdated dependency from module children
 /******/ 					var dependency;
 /******/ 					for (var outdatedModuleId in outdatedDependencies) {
@@ -1233,12 +1233,12 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							__webpack_require__.m[updateModuleId] = appliedUpdate[updateModuleId];
 /******/ 						}
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					// run new runtime modules
 /******/ 					for (var i = 0; i < currentUpdateRuntime.length; i++) {
 /******/ 						currentUpdateRuntime[i](__webpack_require__);
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					// call accept handlers
 /******/ 					for (var outdatedModuleId in outdatedDependencies) {
 /******/ 						if (__webpack_require__.o(outdatedDependencies, outdatedModuleId)) {
@@ -1309,7 +1309,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							}
 /******/ 						}
 /******/ 					}
-/******/ 		
+/******/
 /******/ 					var onAccepted = function () {
 /******/ 						// Load self accepted modules
 /******/ 						for (var o = 0; o < outdatedSelfAcceptedModules.length; o++) {
@@ -1353,7 +1353,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 							}
 /******/ 						}
 /******/ 					};
-/******/ 		
+/******/
 /******/ 					return Promise.all(acceptPromises)
 /******/ 						.then(onAccepted)
 /******/ 						.then(function () {
@@ -1413,7 +1413,7 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				};
 /******/ 			}
 /******/ 		};
-/******/ 		
+/******/
 /******/ 		__webpack_require__.hmrM = () => {
 /******/ 			if (typeof fetch === "undefined") throw new Error("No browser support: need fetch API");
 /******/ 			return fetch(__webpack_require__.p + __webpack_require__.hmrF()).then((response) => {
@@ -1422,9 +1422,9 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 				return response.json();
 /******/ 			});
 /******/ 		};
-/******/ 		
+/******/
 /******/ 		__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
-/******/ 		
+/******/
 /******/ 		// install a JSONP callback for chunk loading
 /******/ 		var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
 /******/ 			var [chunkIds, moreModules, runtime] = data;
@@ -1449,14 +1449,14 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 			}
 /******/ 			return __webpack_require__.O(result);
 /******/ 		}
-/******/ 		
+/******/
 /******/ 		var chunkLoadingGlobal = globalThis["webpackChunksuperset"] = globalThis["webpackChunksuperset"] || [];
 /******/ 		chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
 /******/ 		chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
 /******/ 	})();
-/******/ 	
+/******/
 /************************************************************************/
-/******/ 	
+/******/
 /******/ 	// module cache are used so entry inlining is disabled
 /******/ 	// startup
 /******/ 	// Load entry module and return exports
@@ -1466,6 +1466,6 @@ eval("{/**\n * Licensed to the Apache Software Foundation (ASF) under one\n * or
 /******/ 	__webpack_require__.O(undefined, ["vendors","vendors-node_modules_rc-component_color-picker_es_index_js-node_modules_rc-component_mutate-o-484854","webpack_sharing_consume_default_react-dom_react-dom-webpack_sharing_consume_default_react_rea-153fef"], () => (__webpack_require__("./node_modules/@pmmmwh/react-refresh-webpack-plugin/client/ErrorOverlayEntry.js")))
 /******/ 	var __webpack_exports__ = __webpack_require__.O(undefined, ["vendors","vendors-node_modules_rc-component_color-picker_es_index_js-node_modules_rc-component_mutate-o-484854","webpack_sharing_consume_default_react-dom_react-dom-webpack_sharing_consume_default_react_rea-153fef"], () => (__webpack_require__("./src/service-worker.ts")))
 /******/ 	__webpack_exports__ = __webpack_require__.O(__webpack_exports__);
-/******/ 	
+/******/
 /******/ })()
-;
\ No newline at end of file
+;