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 33f6902001bb1c7ea718b3042256fb0404261403
Author: Beto Dealmeida <[email protected]>
AuthorDate: Tue Feb 17 11:06:37 2026 -0500

    CRUD working
---
 .../features/semanticLayers/SemanticLayerModal.tsx |  88 ++++-
 superset-frontend/src/pages/DatabaseList/index.tsx | 383 ++++++++++++++++-----
 superset/commands/semantic_layer/create.py         |   5 +
 superset/commands/semantic_layer/update.py         |   5 +
 superset/semantic_layers/api.py                    | 169 ++++++++-
 superset/static/service-worker.js                  | 206 +++++------
 6 files changed, 654 insertions(+), 202 deletions(-)

diff --git 
a/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx 
b/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
index fbeb984ffa9..37694a9e9a6 100644
--- a/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
+++ b/superset-frontend/src/features/semanticLayers/SemanticLayerModal.tsx
@@ -303,6 +303,7 @@ interface SemanticLayerModalProps {
   onHide: () => void;
   addDangerToast: (msg: string) => void;
   addSuccessToast: (msg: string) => void;
+  semanticLayerUuid?: string;
 }
 
 export default function SemanticLayerModal({
@@ -310,7 +311,9 @@ export default function SemanticLayerModal({
   onHide,
   addDangerToast,
   addSuccessToast,
+  semanticLayerUuid,
 }: SemanticLayerModalProps) {
+  const isEditMode = !!semanticLayerUuid;
   const [step, setStep] = useState<Step>('type');
   const [name, setName] = useState('');
   const [selectedType, setSelectedType] = useState<string | null>(null);
@@ -380,9 +383,47 @@ export default function SemanticLayerModal({
     [addDangerToast, applySchema],
   );
 
+  const fetchExistingLayer = useCallback(
+    async (uuid: string) => {
+      setLoading(true);
+      try {
+        const { json } = await SupersetClient.get({
+          endpoint: `/api/v1/semantic_layer/${uuid}`,
+        });
+        const layer = json.result;
+        setName(layer.name ?? '');
+        setSelectedType(layer.type);
+        setFormData(layer.configuration ?? {});
+        setHasErrors(false);
+        // Fetch base schema (no configuration → no Snowflake connection) to
+        // show the form immediately. The existing maybeRefreshSchema machinery
+        // will trigger an enriched fetch in the background once deps are
+        // satisfied, and DynamicFieldControl will show per-field spinners.
+        const { json: schemaJson } = await SupersetClient.post({
+          endpoint: '/api/v1/semantic_layer/schema/configuration',
+          jsonPayload: { type: layer.type },
+        });
+        applySchema(schemaJson.result);
+        setStep('config');
+      } catch {
+        addDangerToast(
+          t('An error occurred while fetching the semantic layer'),
+        );
+      } finally {
+        setLoading(false);
+      }
+    },
+    [addDangerToast, applySchema],
+  );
+
   useEffect(() => {
     if (show) {
-      fetchTypes();
+      if (isEditMode && semanticLayerUuid) {
+        fetchTypes();
+        fetchExistingLayer(semanticLayerUuid);
+      } else {
+        fetchTypes();
+      }
     } else {
       setStep('type');
       setName('');
@@ -399,7 +440,7 @@ export default function SemanticLayerModal({
       dynamicDepsRef.current = {};
       if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);
     }
-  }, [show, fetchTypes]);
+  }, [show, fetchTypes, isEditMode, semanticLayerUuid, fetchExistingLayer]);
 
   const handleStepAdvance = () => {
     if (selectedType) {
@@ -422,14 +463,26 @@ export default function SemanticLayerModal({
   const handleCreate = async () => {
     setSaving(true);
     try {
-      await SupersetClient.post({
-        endpoint: '/api/v1/semantic_layer/',
-        jsonPayload: { name, type: selectedType, configuration: formData },
-      });
-      addSuccessToast(t('Semantic layer created'));
+      if (isEditMode && semanticLayerUuid) {
+        await SupersetClient.put({
+          endpoint: `/api/v1/semantic_layer/${semanticLayerUuid}`,
+          jsonPayload: { name, configuration: formData },
+        });
+        addSuccessToast(t('Semantic layer updated'));
+      } else {
+        await SupersetClient.post({
+          endpoint: '/api/v1/semantic_layer/',
+          jsonPayload: { name, type: selectedType, configuration: formData },
+        });
+        addSuccessToast(t('Semantic layer created'));
+      }
       onHide();
     } catch {
-      addDangerToast(t('An error occurred while creating the semantic layer'));
+      addDangerToast(
+        isEditMode
+          ? t('An error occurred while updating the semantic layer')
+          : t('An error occurred while creating the semantic layer'),
+      );
     } finally {
       setSaving(false);
     }
@@ -491,8 +544,9 @@ export default function SemanticLayerModal({
   const selectedTypeName =
     types.find(type => type.id === selectedType)?.name ?? '';
 
-  const title =
-    step === 'type'
+  const title = isEditMode
+    ? t('Edit %s', selectedTypeName || t('Semantic Layer'))
+    : step === 'type'
       ? t('New Semantic Layer')
       : t('Configure %s', selectedTypeName);
 
@@ -502,12 +556,12 @@ export default function SemanticLayerModal({
       onHide={onHide}
       onSave={handleSave}
       title={title}
-      icon={<Icons.PlusOutlined />}
+      icon={isEditMode ? <Icons.EditOutlined /> : <Icons.PlusOutlined />}
       width={step === 'type' ? MODAL_STANDARD_WIDTH : MODAL_MEDIUM_WIDTH}
       saveDisabled={
         step === 'type' ? !selectedType : saving || !name.trim() || hasErrors
       }
-      saveText={step === 'type' ? undefined : t('Create')}
+      saveText={step === 'type' ? undefined : isEditMode ? t('Save') : 
t('Create')}
       saveLoading={saving}
       contentLoading={loading}
     >
@@ -534,10 +588,12 @@ export default function SemanticLayerModal({
         </ModalContent>
       ) : (
         <ModalContent>
-          <BackLink type="button" onClick={handleBack}>
-            <Icons.CaretLeftOutlined iconSize="s" />
-            {t('Back')}
-          </BackLink>
+          {!isEditMode && (
+            <BackLink type="button" onClick={handleBack}>
+              <Icons.CaretLeftOutlined iconSize="s" />
+              {t('Back')}
+            </BackLink>
+          )}
           <ModalFormField label={t('Name')} required>
             <Input
               value={name}
diff --git a/superset-frontend/src/pages/DatabaseList/index.tsx 
b/superset-frontend/src/pages/DatabaseList/index.tsx
index 1c1c8ccdc2c..1858e6c7572 100644
--- a/superset-frontend/src/pages/DatabaseList/index.tsx
+++ b/superset-frontend/src/pages/DatabaseList/index.tsx
@@ -24,7 +24,7 @@ import {
   FeatureFlag,
 } from '@superset-ui/core';
 import { css, styled, useTheme } from '@apache-superset/core/ui';
-import { useState, useMemo, useEffect } from 'react';
+import { useState, useMemo, useEffect, useCallback } from 'react';
 import rison from 'rison';
 import { useSelector } from 'react-redux';
 import { useQueryParams, BooleanParam } from 'use-query-params';
@@ -50,6 +50,7 @@ import {
   ListView,
   ListViewFilterOperator as FilterOperator,
   ListViewFilters,
+  type ListViewFetchDataConfig,
 } from 'src/components';
 import { Typography } from '@superset-ui/core/components/Typography';
 import { getUrlParam } from 'src/utils/urlUtils';
@@ -78,6 +79,11 @@ const dbConfigExtraExtension = extensionsRegistry.get(
 
 const PAGE_SIZE = 25;
 
+type ConnectionItem = DatabaseObject & {
+  source_type?: 'database' | 'semantic_layer';
+  sl_type?: string;
+};
+
 interface DatabaseDeleteObject extends DatabaseObject {
   charts: any;
   dashboards: any;
@@ -117,20 +123,105 @@ function DatabaseList({
   user,
 }: DatabaseListProps) {
   const theme = useTheme();
+  const showSemanticLayers = isFeatureEnabled(FeatureFlag.SemanticLayers);
+
+  // Standard database list view resource (used when SL flag is OFF)
   const {
     state: {
-      loading,
-      resourceCount: databaseCount,
-      resourceCollection: databases,
+      loading: dbLoading,
+      resourceCount: dbCount,
+      resourceCollection: dbCollection,
     },
     hasPerm,
-    fetchData,
-    refreshData,
+    fetchData: dbFetchData,
+    refreshData: dbRefreshData,
   } = useListViewResource<DatabaseObject>(
     'database',
     t('database'),
     addDangerToast,
   );
+
+  // Combined endpoint state (used when SL flag is ON)
+  const [combinedItems, setCombinedItems] = useState<ConnectionItem[]>([]);
+  const [combinedCount, setCombinedCount] = useState(0);
+  const [combinedLoading, setCombinedLoading] = useState(true);
+  const [lastFetchConfig, setLastFetchConfig] =
+    useState<ListViewFetchDataConfig | null>(null);
+
+  const combinedFetchData = useCallback(
+    (config: ListViewFetchDataConfig) => {
+      setLastFetchConfig(config);
+      setCombinedLoading(true);
+      const { pageIndex, pageSize, sortBy, filters: filterValues } = config;
+
+      const sourceTypeFilter = filterValues.find(f => f.id === 'source_type');
+      const otherFilters = filterValues
+        .filter(f => f.id !== 'source_type')
+        .filter(
+          ({ value }) => value !== '' && value !== null && value !== undefined,
+        )
+        .map(({ id, operator: opr, value }) => ({
+          col: id,
+          opr,
+          value:
+            value && typeof value === 'object' && 'value' in value
+              ? value.value
+              : value,
+        }));
+
+      const sourceTypeValue =
+        sourceTypeFilter?.value && typeof sourceTypeFilter.value === 'object'
+          ? (sourceTypeFilter.value as { value: string }).value
+          : sourceTypeFilter?.value;
+      if (sourceTypeValue) {
+        otherFilters.push({
+          col: 'source_type',
+          opr: 'eq',
+          value: sourceTypeValue,
+        });
+      }
+
+      const queryParams = rison.encode_uri({
+        order_column: sortBy[0].id,
+        order_direction: sortBy[0].desc ? 'desc' : 'asc',
+        page: pageIndex,
+        page_size: pageSize,
+        ...(otherFilters.length ? { filters: otherFilters } : {}),
+      });
+
+      return SupersetClient.get({
+        endpoint: `/api/v1/semantic_layer/connections/?q=${queryParams}`,
+      })
+        .then(({ json = {} }) => {
+          setCombinedItems(json.result);
+          setCombinedCount(json.count);
+        })
+        .catch(() => {
+          addDangerToast(t('An error occurred while fetching connections'));
+        })
+        .finally(() => {
+          setCombinedLoading(false);
+        });
+    },
+    [addDangerToast],
+  );
+
+  const combinedRefreshData = useCallback(() => {
+    if (lastFetchConfig) {
+      return combinedFetchData(lastFetchConfig);
+    }
+    return undefined;
+  }, [lastFetchConfig, combinedFetchData]);
+
+  // Select the right data source based on feature flag
+  const loading = showSemanticLayers ? combinedLoading : dbLoading;
+  const databaseCount = showSemanticLayers ? combinedCount : dbCount;
+  const databases: ConnectionItem[] = showSemanticLayers
+    ? combinedItems
+    : dbCollection;
+  const fetchData = showSemanticLayers ? combinedFetchData : dbFetchData;
+  const refreshData = showSemanticLayers ? combinedRefreshData : dbRefreshData;
+
   const fullUser = useSelector<any, UserWithPermissionsAndRoles>(
     state => state.user,
   );
@@ -159,6 +250,11 @@ function DatabaseList({
     useState<boolean>(false);
   const [semanticLayerModalOpen, setSemanticLayerModalOpen] =
     useState<boolean>(false);
+  const [slCurrentlyEditing, setSlCurrentlyEditing] = useState<string | null>(
+    null,
+  );
+  const [slCurrentlyDeleting, setSlCurrentlyDeleting] =
+    useState<ConnectionItem | null>(null);
 
   const [allowUploads, setAllowUploads] = useState<boolean>(false);
   const isAdmin = isUserAdmin(fullUser);
@@ -440,6 +536,23 @@ function DatabaseList({
 
   const initialSort = [{ id: 'changed_on_delta_humanized', desc: true }];
 
+  function handleSemanticLayerDelete(item: ConnectionItem) {
+    SupersetClient.delete({
+      endpoint: `/api/v1/semantic_layer/${item.uuid}`,
+    }).then(
+      () => {
+        refreshData();
+        addSuccessToast(t('Deleted: %s', item.database_name));
+        setSlCurrentlyDeleting(null);
+      },
+      createErrorHandler(errMsg =>
+        addDangerToast(
+          t('There was an issue deleting %s: %s', item.database_name, errMsg),
+        ),
+      ),
+    );
+  }
+
   const columns = useMemo(
     () => [
       {
@@ -452,7 +565,7 @@ function DatabaseList({
         accessor: 'backend',
         Header: t('Backend'),
         size: 'xl',
-        disableSortBy: true, // TODO: api support for sorting by 'backend'
+        disableSortBy: true,
         id: 'backend',
       },
       {
@@ -466,13 +579,12 @@ function DatabaseList({
             <span>{t('AQE')}</span>
           </Tooltip>
         ),
-        Cell: ({
-          row: {
-            original: { allow_run_async: allowRunAsync },
-          },
-        }: {
-          row: { original: { allow_run_async: boolean } };
-        }) => <BooleanDisplay value={allowRunAsync} />,
+        Cell: ({ row: { original } }: any) =>
+          original.source_type === 'semantic_layer' ? (
+            <span>–</span>
+          ) : (
+            <BooleanDisplay value={original.allow_run_async} />
+          ),
         size: 'sm',
         id: 'allow_run_async',
       },
@@ -487,33 +599,36 @@ function DatabaseList({
             <span>{t('DML')}</span>
           </Tooltip>
         ),
-        Cell: ({
-          row: {
-            original: { allow_dml: allowDML },
-          },
-        }: any) => <BooleanDisplay value={allowDML} />,
+        Cell: ({ row: { original } }: any) =>
+          original.source_type === 'semantic_layer' ? (
+            <span>–</span>
+          ) : (
+            <BooleanDisplay value={original.allow_dml} />
+          ),
         size: 'sm',
         id: 'allow_dml',
       },
       {
         accessor: 'allow_file_upload',
         Header: t('File upload'),
-        Cell: ({
-          row: {
-            original: { allow_file_upload: allowFileUpload },
-          },
-        }: any) => <BooleanDisplay value={allowFileUpload} />,
+        Cell: ({ row: { original } }: any) =>
+          original.source_type === 'semantic_layer' ? (
+            <span>–</span>
+          ) : (
+            <BooleanDisplay value={original.allow_file_upload} />
+          ),
         size: 'md',
         id: 'allow_file_upload',
       },
       {
         accessor: 'expose_in_sqllab',
         Header: t('Expose in SQL Lab'),
-        Cell: ({
-          row: {
-            original: { expose_in_sqllab: exposeInSqllab },
-          },
-        }: any) => <BooleanDisplay value={exposeInSqllab} />,
+        Cell: ({ row: { original } }: any) =>
+          original.source_type === 'semantic_layer' ? (
+            <span>–</span>
+          ) : (
+            <BooleanDisplay value={original.expose_in_sqllab} />
+          ),
         size: 'md',
         id: 'expose_in_sqllab',
       },
@@ -533,6 +648,49 @@ function DatabaseList({
       },
       {
         Cell: ({ row: { original } }: any) => {
+          const isSemanticLayer =
+            original.source_type === 'semantic_layer';
+
+          if (isSemanticLayer) {
+            if (!canEdit && !canDelete) return null;
+            return (
+              <Actions className="actions">
+                {canDelete && (
+                  <Tooltip
+                    id="delete-action-tooltip"
+                    title={t('Delete')}
+                    placement="bottom"
+                  >
+                    <span
+                      role="button"
+                      tabIndex={0}
+                      className="action-button"
+                      onClick={() => setSlCurrentlyDeleting(original)}
+                    >
+                      <Icons.DeleteOutlined iconSize="l" />
+                    </span>
+                  </Tooltip>
+                )}
+                {canEdit && (
+                  <Tooltip
+                    id="edit-action-tooltip"
+                    title={t('Edit')}
+                    placement="bottom"
+                  >
+                    <span
+                      role="button"
+                      tabIndex={0}
+                      className="action-button"
+                      onClick={() => setSlCurrentlyEditing(original.uuid)}
+                    >
+                      <Icons.EditOutlined iconSize="l" />
+                    </span>
+                  </Tooltip>
+                )}
+              </Actions>
+            );
+          }
+
           const handleEdit = () =>
             handleDatabaseEditModal({ database: original, modalOpen: true });
           const handleDelete = () => openDatabaseDeleteModal(original);
@@ -618,6 +776,12 @@ function DatabaseList({
         hidden: !canEdit && !canDelete,
         disableSortBy: true,
       },
+      {
+        accessor: 'source_type',
+        hidden: true,
+        disableSortBy: true,
+        id: 'source_type',
+      },
       {
         accessor: QueryObjectColumns.ChangedBy,
         hidden: true,
@@ -627,8 +791,8 @@ function DatabaseList({
     [canDelete, canEdit, canExport],
   );
 
-  const filters: ListViewFilters = useMemo(
-    () => [
+  const filters: ListViewFilters = useMemo(() => {
+    const baseFilters: ListViewFilters = [
       {
         Header: t('Name'),
         key: 'search',
@@ -636,62 +800,83 @@ function DatabaseList({
         input: 'search',
         operator: FilterOperator.Contains,
       },
-      {
-        Header: t('Expose in SQL Lab'),
-        key: 'expose_in_sql_lab',
-        id: 'expose_in_sqllab',
-        input: 'select',
-        operator: FilterOperator.Equals,
-        unfilteredLabel: t('All'),
-        selects: [
-          { label: t('Yes'), value: true },
-          { label: t('No'), value: false },
-        ],
-      },
-      {
-        Header: (
-          <Tooltip
-            id="allow-run-async-filter-header-tooltip"
-            title={t('Asynchronous query execution')}
-            placement="top"
-          >
-            <span>{t('AQE')}</span>
-          </Tooltip>
-        ),
-        key: 'allow_run_async',
-        id: 'allow_run_async',
+    ];
+
+    if (showSemanticLayers) {
+      baseFilters.push({
+        Header: t('Source'),
+        key: 'source_type',
+        id: 'source_type',
         input: 'select',
         operator: FilterOperator.Equals,
         unfilteredLabel: t('All'),
         selects: [
-          { label: t('Yes'), value: true },
-          { label: t('No'), value: false },
+          { label: t('Database'), value: 'database' },
+          { label: t('Semantic Layer'), value: 'semantic_layer' },
         ],
-      },
-      {
-        Header: t('Modified by'),
-        key: 'changed_by',
-        id: 'changed_by',
-        input: 'select',
-        operator: FilterOperator.RelationOneMany,
-        unfilteredLabel: t('All'),
-        fetchSelects: createFetchRelated(
-          'database',
-          'changed_by',
-          createErrorHandler(errMsg =>
-            t(
-              'An error occurred while fetching dataset datasource values: %s',
-              errMsg,
+      });
+    }
+
+    if (!showSemanticLayers) {
+      baseFilters.push(
+        {
+          Header: t('Expose in SQL Lab'),
+          key: 'expose_in_sql_lab',
+          id: 'expose_in_sqllab',
+          input: 'select',
+          operator: FilterOperator.Equals,
+          unfilteredLabel: t('All'),
+          selects: [
+            { label: t('Yes'), value: true },
+            { label: t('No'), value: false },
+          ],
+        },
+        {
+          Header: (
+            <Tooltip
+              id="allow-run-async-filter-header-tooltip"
+              title={t('Asynchronous query execution')}
+              placement="top"
+            >
+              <span>{t('AQE')}</span>
+            </Tooltip>
+          ),
+          key: 'allow_run_async',
+          id: 'allow_run_async',
+          input: 'select',
+          operator: FilterOperator.Equals,
+          unfilteredLabel: t('All'),
+          selects: [
+            { label: t('Yes'), value: true },
+            { label: t('No'), value: false },
+          ],
+        },
+        {
+          Header: t('Modified by'),
+          key: 'changed_by',
+          id: 'changed_by',
+          input: 'select',
+          operator: FilterOperator.RelationOneMany,
+          unfilteredLabel: t('All'),
+          fetchSelects: createFetchRelated(
+            'database',
+            'changed_by',
+            createErrorHandler(errMsg =>
+              t(
+                'An error occurred while fetching dataset datasource values: 
%s',
+                errMsg,
+              ),
             ),
+            user,
           ),
-          user,
-        ),
-        paginate: true,
-        dropdownStyle: { minWidth: WIDER_DROPDOWN_WIDTH },
-      },
-    ],
-    [],
-  );
+          paginate: true,
+          dropdownStyle: { minWidth: WIDER_DROPDOWN_WIDTH },
+        },
+      );
+    }
+
+    return baseFilters;
+  }, [showSemanticLayers]);
 
   return (
     <>
@@ -736,10 +921,46 @@ function DatabaseList({
       />
       <SemanticLayerModal
         show={semanticLayerModalOpen}
-        onHide={() => setSemanticLayerModalOpen(false)}
+        onHide={() => {
+          setSemanticLayerModalOpen(false);
+          refreshData();
+        }}
         addDangerToast={addDangerToast}
         addSuccessToast={addSuccessToast}
       />
+      <SemanticLayerModal
+        show={!!slCurrentlyEditing}
+        onHide={() => {
+          setSlCurrentlyEditing(null);
+          refreshData();
+        }}
+        addDangerToast={addDangerToast}
+        addSuccessToast={addSuccessToast}
+        semanticLayerUuid={slCurrentlyEditing ?? undefined}
+      />
+      {slCurrentlyDeleting && (
+        <DeleteModal
+          description={
+            <p>
+              {t('Are you sure you want to delete')}{' '}
+              <b>{slCurrentlyDeleting.database_name}</b>?
+            </p>
+          }
+          onConfirm={() => {
+            if (slCurrentlyDeleting) {
+              handleSemanticLayerDelete(slCurrentlyDeleting);
+            }
+          }}
+          onHide={() => setSlCurrentlyDeleting(null)}
+          open
+          title={
+            <ModalTitleWithIcon
+              icon={<Icons.DeleteOutlined />}
+              title={t('Delete Semantic Layer?')}
+            />
+          }
+        />
+      )}
       {databaseCurrentlyDeleting && (
         <DeleteModal
           description={
diff --git a/superset/commands/semantic_layer/create.py 
b/superset/commands/semantic_layer/create.py
index b0778fe8084..250476d210f 100644
--- a/superset/commands/semantic_layer/create.py
+++ b/superset/commands/semantic_layer/create.py
@@ -16,6 +16,7 @@
 # under the License.
 from __future__ import annotations
 
+import json
 import logging
 from functools import partial
 from typing import Any
@@ -48,6 +49,10 @@ class CreateSemanticLayerCommand(BaseCommand):
     )
     def run(self) -> Model:
         self.validate()
+        if isinstance(self._properties.get("configuration"), dict):
+            self._properties["configuration"] = json.dumps(
+                self._properties["configuration"]
+            )
         return SemanticLayerDAO.create(attributes=self._properties)
 
     def validate(self) -> None:
diff --git a/superset/commands/semantic_layer/update.py 
b/superset/commands/semantic_layer/update.py
index 5242406af8c..66c02d568ab 100644
--- a/superset/commands/semantic_layer/update.py
+++ b/superset/commands/semantic_layer/update.py
@@ -16,6 +16,7 @@
 # under the License.
 from __future__ import annotations
 
+import json
 import logging
 from functools import partial
 from typing import Any
@@ -87,6 +88,10 @@ class UpdateSemanticLayerCommand(BaseCommand):
     def run(self) -> Model:
         self.validate()
         assert self._model
+        if isinstance(self._properties.get("configuration"), dict):
+            self._properties["configuration"] = json.dumps(
+                self._properties["configuration"]
+            )
         return SemanticLayerDAO.update(self._model, 
attributes=self._properties)
 
     def validate(self) -> None:
diff --git a/superset/semantic_layers/api.py b/superset/semantic_layers/api.py
index bb94a0e4b91..bed9dc996a5 100644
--- a/superset/semantic_layers/api.py
+++ b/superset/semantic_layers/api.py
@@ -21,12 +21,13 @@ import logging
 from typing import Any
 
 from flask import make_response, request, Response
-from flask_appbuilder.api import expose, protect, safe
+from flask_appbuilder.api import expose, protect, rison, safe
+from flask_appbuilder.api.schemas import get_list_schema
 from flask_appbuilder.models.sqla.interface import SQLAInterface
 from marshmallow import ValidationError
 from pydantic import ValidationError as PydanticValidationError
 
-from superset import event_logger
+from superset import db, event_logger, is_feature_enabled
 from superset.commands.semantic_layer.create import CreateSemanticLayerCommand
 from superset.commands.semantic_layer.delete import DeleteSemanticLayerCommand
 from superset.commands.semantic_layer.exceptions import (
@@ -46,6 +47,7 @@ from superset.commands.semantic_layer.update import (
 )
 from superset.constants import MODEL_API_RW_METHOD_PERMISSION_MAP
 from superset.daos.semantic_layer import SemanticLayerDAO
+from superset.models.core import Database
 from superset.semantic_layers.models import SemanticLayer, SemanticView
 from superset.semantic_layers.registry import registry
 from superset.semantic_layers.schemas import (
@@ -65,12 +67,17 @@ logger = logging.getLogger(__name__)
 
 
 def _serialize_layer(layer: SemanticLayer) -> dict[str, Any]:
+    config = layer.configuration
+    if isinstance(config, str):
+        config = json.loads(config)
     return {
         "uuid": str(layer.uuid),
         "name": layer.name,
         "description": layer.description,
         "type": layer.type,
         "cache_timeout": layer.cache_timeout,
+        "configuration": config or {},
+        "changed_on_delta_humanized": layer.changed_on_delta_humanized(),
     }
 
 
@@ -515,6 +522,164 @@ class SemanticLayerRestApi(BaseSupersetApi):
             )
             return self.response_422(message=str(ex))
 
+    @expose("/connections/", methods=("GET",))
+    @protect()
+    @safe
+    @statsd_metrics
+    @rison(get_list_schema)
+    @event_logger.log_this_with_context(
+        action=lambda self, *args, **kwargs: f"{self.__class__.__name__}"
+        ".connections",
+        log_to_statsd=False,
+    )
+    def connections(self, **kwargs: Any) -> FlaskResponse:
+        """List databases and semantic layers combined.
+        ---
+        get:
+          summary: List databases and semantic layers combined
+          parameters:
+          - in: query
+            name: q
+            content:
+              application/json:
+                schema:
+                  $ref: '#/components/schemas/get_list_schema'
+          responses:
+            200:
+              description: Combined list of databases and semantic layers
+            401:
+              $ref: '#/components/responses/401'
+            500:
+              $ref: '#/components/responses/500'
+        """
+        args = kwargs.get("rison", {})
+        page = args.get("page", 0)
+        page_size = args.get("page_size", 25)
+        order_column = args.get("order_column", "changed_on")
+        order_direction = args.get("order_direction", "desc")
+        filters = args.get("filters", [])
+
+        source_type = "all"
+        name_filter = None
+        for f in filters:
+            if f.get("col") == "source_type":
+                source_type = f.get("value", "all")
+            elif f.get("col") == "database_name" and f.get("opr") == "ct":
+                name_filter = f.get("value")
+
+        if not is_feature_enabled("SEMANTIC_LAYERS"):
+            source_type = "database"
+
+        reverse = order_direction == "desc"
+
+        def _sort_key_changed_on(
+            item: tuple[str, Database | SemanticLayer],
+        ) -> Any:
+            return item[1].changed_on or ""
+
+        def _sort_key_name(
+            item: tuple[str, Database | SemanticLayer],
+        ) -> str:
+            obj = item[1]
+            raw = (
+                obj.database_name  # type: ignore[union-attr]
+                if item[0] == "database"
+                else obj.name
+            )
+            return raw.lower()
+
+        sort_key_map = {
+            "changed_on_delta_humanized": _sort_key_changed_on,
+            "database_name": _sort_key_name,
+        }
+        sort_key = sort_key_map.get(order_column, _sort_key_changed_on)
+
+        # Fetch databases (lightweight: only loads ORM objects, no eager joins)
+        db_items: list[tuple[str, Database]] = []
+        if source_type in ("all", "database"):
+            db_q = db.session.query(Database)
+            if name_filter:
+                db_q = db_q.filter(
+                    Database.database_name.ilike(f"%{name_filter}%")
+                )
+            db_items = [("database", obj) for obj in db_q.all()]
+
+        # Fetch semantic layers
+        sl_items: list[tuple[str, SemanticLayer]] = []
+        if source_type in ("all", "semantic_layer"):
+            sl_q = db.session.query(SemanticLayer)
+            if name_filter:
+                sl_q = sl_q.filter(
+                    SemanticLayer.name.ilike(f"%{name_filter}%")
+                )
+            sl_items = [("semantic_layer", obj) for obj in sl_q.all()]
+
+        # Merge, sort, count, paginate
+        all_items: list[tuple[str, Any]] = db_items + sl_items  # type: ignore
+        all_items.sort(key=sort_key, reverse=reverse)  # type: ignore
+        total_count = len(all_items)
+
+        start = page * page_size
+        page_items = all_items[start : start + page_size]
+
+        # Serialize
+        result = []
+        for item_type, obj in page_items:
+            if item_type == "database":
+                result.append(self._serialize_database(obj))
+            else:
+                result.append(self._serialize_semantic_layer(obj))
+
+        return self.response(200, count=total_count, result=result)
+
+    @staticmethod
+    def _serialize_database(obj: Database) -> dict[str, Any]:
+        changed_by = obj.changed_by
+        return {
+            "source_type": "database",
+            "id": obj.id,
+            "uuid": str(obj.uuid),
+            "database_name": obj.database_name,
+            "backend": obj.backend,
+            "allow_run_async": obj.allow_run_async,
+            "allow_dml": obj.allow_dml,
+            "allow_file_upload": obj.allow_file_upload,
+            "expose_in_sqllab": obj.expose_in_sqllab,
+            "changed_on_delta_humanized": obj.changed_on_delta_humanized(),
+            "changed_by": {
+                "first_name": changed_by.first_name,
+                "last_name": changed_by.last_name,
+            }
+            if changed_by
+            else None,
+        }
+
+    @staticmethod
+    def _serialize_semantic_layer(obj: SemanticLayer) -> dict[str, Any]:
+        changed_by = obj.changed_by
+        sl_type = obj.type
+        cls = registry.get(sl_type)
+        type_name = cls.name if cls else sl_type
+        return {
+            "source_type": "semantic_layer",
+            "uuid": str(obj.uuid),
+            "database_name": obj.name,
+            "backend": type_name,
+            "sl_type": sl_type,
+            "description": obj.description,
+            "allow_run_async": None,
+            "allow_dml": None,
+            "allow_file_upload": None,
+            "expose_in_sqllab": None,
+            "changed_on_delta_humanized": obj.changed_on_delta_humanized(),
+            "changed_by": {
+                "first_name": changed_by.first_name,
+                "last_name": changed_by.last_name,
+            }
+            if changed_by
+            else None,
+        }
+
     @expose("/", methods=("GET",))
     @protect()
     @safe
diff --git a/superset/static/service-worker.js 
b/superset/static/service-worker.js
index 0a942440ae1..88dce3da348 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 = () => ("669bfdb2217bd9a71a0c")
+/******/               __webpack_require__.h = () => ("9e4777e49256d5920929")
 /******/       })();
-/******/
+/******/       
 /******/       /* 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

Reply via email to