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

rusackas pushed a commit to branch fix/antd-direct-imports
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 8371a5060ba3e77c5e63543bafbef9a705b35d89
Author: Evan Rusackas <[email protected]>
AuthorDate: Fri Oct 2 15:16:28 2026 -0700

    fix(frontend): finish migrating off direct antd imports, enforce it in 
custom rules
    
    Six files still imported from 'antd' or 'antd/<path>' directly instead
    of the @superset-ui/core/components wrappers CLAUDE.md mandates:
    
    - MenuItemWithTruncation.tsx and DrillBySubmenu.tsx/ChangeDatasourceModal
      only needed the MenuItemProps/InputRef *types*, both of which the
      Menu/Input wrappers already re-export (or are derivable via
      ComponentProps<typeof Menu.Item>), so no antd import was needed at all.
    - components/Tag/index.tsx needed TagProps/CheckableTagProps, which the
      Tag wrapper didn't re-export yet; added that export to
      packages/superset-ui-core/src/components/Tag (antd/es/tag has both),
      matching the pattern Input/Menu already follow.
    
    Deliberately left alone: theme/utils/antdTokenNames.ts (introspects
    antd's own design-token set at runtime; there's no wrapper for that)
    and theme/tests/ThemeController.test.ts (asserts against antd's real
    algorithm constants to verify the theme integration itself) -- both
    inside src/theme/, the same area already exempted from the sibling
    no-literal-colors custom rule for the same reason.
    
    Added checkNoDirectAntdImports to scripts/check-custom-rules.js so this
    doesn't quietly regress again, with the same two exemptions (theme/utils,
    plus the superset-ui-core/superset-core wrapper packages themselves,
    which are the one place importing antd directly is the point).
    
    Co-Authored-By: Evan Rusackas <[email protected]>
    Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
 .../superset-ui-core/src/components/Tag/index.tsx  |  1 +
 superset-frontend/scripts/check-custom-rules.js    | 40 ++++++++++++++++++++++
 .../components/Chart/DrillBy/DrillBySubmenu.tsx    |  2 +-
 .../components/Chart/MenuItemWithTruncation.tsx    |  5 ++-
 .../Datasource/ChangeDatasourceModal/index.tsx     |  2 +-
 superset-frontend/src/components/Tag/index.tsx     |  8 +++--
 6 files changed, 50 insertions(+), 8 deletions(-)

diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/Tag/index.tsx 
b/superset-frontend/packages/superset-ui-core/src/components/Tag/index.tsx
index f9b7884464a..7275d529104 100644
--- a/superset-frontend/packages/superset-ui-core/src/components/Tag/index.tsx
+++ b/superset-frontend/packages/superset-ui-core/src/components/Tag/index.tsx
@@ -17,3 +17,4 @@
  * under the License.
  */
 export { Tag } from 'antd';
+export type { TagProps, CheckableTagProps } from 'antd/es/tag';
diff --git a/superset-frontend/scripts/check-custom-rules.js 
b/superset-frontend/scripts/check-custom-rules.js
index 11697b0515f..de049f4e5a6 100755
--- a/superset-frontend/scripts/check-custom-rules.js
+++ b/superset-frontend/scripts/check-custom-rules.js
@@ -174,6 +174,44 @@ function checkNoFaIcons(ast, filepath) {
   });
 }
 
+/**
+ * App code (and plugins) must go through the @superset-ui/core/components
+ * wrappers rather than importing from antd directly, so theming and behavior
+ * stay centralized in one place. The wrapper packages themselves
+ * (superset-ui-core, superset-core) are the legitimate exception -- they're
+ * what the wrappers are built from -- and `theme/utils` files that introspect
+ * antd's own design tokens are exempted the same way checkNoLiteralColors
+ * already exempts that directory (there is no wrapper for "list antd's own
+ * token names").
+ */
+const ANTD_DIRECT_IMPORT_EXEMPT = [
+  /\/theme\/utils\//,
+  /packages\/superset-ui-core\//,
+  /packages\/superset-core\//,
+];
+
+function checkNoDirectAntdImports(ast, filepath) {
+  if (ANTD_DIRECT_IMPORT_EXEMPT.some(pattern => pattern.test(filepath))) {
+    return;
+  }
+
+  traverse(ast, {
+    ImportDeclaration(path) {
+      const source = path.node.source.value;
+      if (source === 'antd' || source.startsWith('antd/')) {
+        if (hasEslintDisable(path, 'no-restricted-imports')) return;
+
+        // eslint-disable-next-line no-console
+        console.error(
+          `${RED}✖${RESET} ${filepath}: Direct import from "${source}". ` +
+            `Use the @superset-ui/core/components wrapper instead.`,
+        );
+        errorCount += 1;
+      }
+    },
+  });
+}
+
 /**
  * Check for improper i18n template usage
  */
@@ -625,6 +663,7 @@ function processFile(filepath) {
     // Run all checks
     checkNoLiteralColors(ast, filepath);
     checkNoFaIcons(ast, filepath);
+    checkNoDirectAntdImports(ast, filepath);
     checkI18nTemplates(ast, filepath);
     checkEagerTranslationsInConfig(ast, filepath);
     checkUntranslatedStrings(ast, filepath);
@@ -787,6 +826,7 @@ if (__filename === process.argv[1]) {
 export default {
   checkNoLiteralColors,
   checkNoFaIcons,
+  checkNoDirectAntdImports,
   checkI18nTemplates,
   checkUntranslatedStrings,
   checkTypeScriptOnlySource,
diff --git a/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx 
b/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
index 3e8a5fea83a..5d0fedf5ce9 100644
--- a/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
+++ b/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
@@ -42,11 +42,11 @@ import {
   Loading,
   Popover,
   Icons,
+  type InputRef,
 } from '@superset-ui/core/components';
 import { Radio } from '@superset-ui/core/components/Radio';
 import { debounce } from 'lodash-es';
 import { List, type RowComponentProps } from 'react-window';
-import { InputRef } from 'antd';
 import { MenuItemTooltip } from '../DisabledMenuItemTooltip';
 import { VirtualizedMenuItem } from '../MenuItemWithTruncation';
 import { Dataset } from '../types';
diff --git a/superset-frontend/src/components/Chart/MenuItemWithTruncation.tsx 
b/superset-frontend/src/components/Chart/MenuItemWithTruncation.tsx
index 89cdec80c32..d2c67c2d4e5 100644
--- a/superset-frontend/src/components/Chart/MenuItemWithTruncation.tsx
+++ b/superset-frontend/src/components/Chart/MenuItemWithTruncation.tsx
@@ -17,17 +17,16 @@
  * under the License.
  */
 
-import { ReactNode, CSSProperties, useCallback } from 'react';
+import { ComponentProps, ReactNode, CSSProperties, useCallback } from 'react';
 import { truncationCSS, useCSSTextTruncation } from '@superset-ui/core';
 import { css, useTheme } from '@apache-superset/core/theme';
 import { Menu, type ItemType } from '@superset-ui/core/components/Menu';
 import { Flex, Tooltip } from '@superset-ui/core/components';
-import { MenuItemProps } from 'antd';
 
 export type MenuItemWithTruncationProps = {
   tooltipText: ReactNode;
   children: ReactNode;
-  onClick?: MenuItemProps['onClick'];
+  onClick?: ComponentProps<typeof Menu.Item>['onClick'];
   style?: CSSProperties;
   menuKey?: string;
 };
diff --git 
a/superset-frontend/src/components/Datasource/ChangeDatasourceModal/index.tsx 
b/superset-frontend/src/components/Datasource/ChangeDatasourceModal/index.tsx
index 093fe8c25f7..9697b8a6fec 100644
--- 
a/superset-frontend/src/components/Datasource/ChangeDatasourceModal/index.tsx
+++ 
b/superset-frontend/src/components/Datasource/ChangeDatasourceModal/index.tsx
@@ -37,6 +37,7 @@ import {
   Loading,
   Modal,
   TableView,
+  type InputRef,
 } from '@superset-ui/core/components';
 import {
   ServerPagination,
@@ -51,7 +52,6 @@ import {
   SORT_BY as DATASET_SORT_BY,
 } from 'src/features/datasets/constants';
 import withToasts from 'src/components/MessageToasts/withToasts';
-import { InputRef } from 'antd';
 import type { Datasource, ChangeDatasourceModalProps } from '../types';
 import { datasetLabelLower } from 'src/features/semanticLayers/label';
 
diff --git a/superset-frontend/src/components/Tag/index.tsx 
b/superset-frontend/src/components/Tag/index.tsx
index 0605977bc08..6229632f27c 100644
--- a/superset-frontend/src/components/Tag/index.tsx
+++ b/superset-frontend/src/components/Tag/index.tsx
@@ -20,10 +20,12 @@
 import { styled } from '@apache-superset/core/theme';
 import { Link } from 'react-router-dom';
 import type { TagType } from 'src/types/TagType';
-import { Tag as AntdTag } from '@superset-ui/core/components/Tag';
+import {
+  Tag as AntdTag,
+  type TagProps,
+  type CheckableTagProps,
+} from '@superset-ui/core/components/Tag';
 import { Tooltip } from '@superset-ui/core/components/Tooltip';
-import type { TagProps } from 'antd/es';
-import type { CheckableTagProps } from 'antd/es/tag';
 import { useMemo } from 'react';
 
 const StyledTag = styled(AntdTag)`

Reply via email to