Skip to content

Refactor TypeScript types and improve type safety across components#28081

Draft
chirag-madlani wants to merge 4 commits into
mainfrom
fix-linting
Draft

Refactor TypeScript types and improve type safety across components#28081
chirag-madlani wants to merge 4 commits into
mainfrom
fix-linting

Conversation

@chirag-madlani
Copy link
Copy Markdown
Collaborator

@chirag-madlani chirag-madlani commented May 13, 2026

This pull request introduces comprehensive documentation and configuration for a new custom ESLint rule, no-duplicate-api-calls, aimed at improving code quality in the OpenMetadata UI by detecting and preventing redundant API calls in React components. The changes include detailed usage instructions, configuration options, troubleshooting guides, and example patterns for refactoring, along with the rule's implementation and registration in the ESLint plugin system.

Documentation and Usage Guides:

  • Added README.md with a full overview of the no-duplicate-api-calls rule, including its purpose, configuration options, detected patterns, and implementation details. Example code snippets demonstrate both violations and best practices.
  • Added CONFIGURATION.md detailing how to configure the rule, adjust severity, set exceptions, handle file exclusions, and migrate existing codebases. Includes troubleshooting and best practice recommendations.
  • Added QUICK_START.md providing a concise, example-driven introduction to the rule, how to fix violations, suppress warnings, and answers to common questions.

Rule Implementation:

  • Registered the no-duplicate-api-calls rule in the ESLint plugin entry point (index.js), making it available for use in the codebase.

Describe your changes:

Fixes #

I worked on ... because ...

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

High-level design:

N/A — small change.

Tests:

Use cases covered

Unit tests

Backend integration tests

Ingestion integration tests

Playwright (UI) tests

Manual testing performed

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.
  • For UI changes: I attached a screen recording and/or screenshots above.
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.

Summary by Gitar

  • Code Refactoring & Type Safety:
    • Improved type definitions in CSVUtilsClassBase.tsx by correctly wrapping EditCellProps returns.
    • Enhanced type safety in FollowingWidget.tsx, data-insight.interface.ts, and AppPlugin.ts.
  • Testing Infrastructure:
    • Updated CustomizeNavigation.test.ts to use actual icon components instead of string mock-icons.
    • Cleaned up TokenServiceUtil.test.ts and removed unused test code in NodeChildren.component.test.tsx.
  • CI/CD Improvements:
    • Refined ui-checkstyle.yml by adjusting job dependency structures and formatting configurations.

This will update automatically on new commits.

- Updated various components to replace `any` with more specific types, enhancing type safety and clarity.
- Modified `DomainTreeView` to include `loadDomains` in dependency array for `useEffect`.
- Improved test files by removing unnecessary `eslint-disable` comments and replacing `any` with appropriate types.
- Refined `NodeSuggestions` to use a more specific type for `selectRef`.
- Changed `WorkflowHistory` interface to use `unknown` instead of `any` for `variables`.
- Enhanced `ServiceConnectionDetails` and `TeamsSelectableNew` components to use `unknown` for state management.
- Updated utility functions and context definitions to replace `any` with `unknown`, ensuring better type safety.
- Removed redundant code and improved readability in `getKeyValues` function in `ServiceConnectionDetailsUtils`.
- General cleanup of comments and code structure for better maintainability.
Copilot AI review requested due to automatic review settings May 13, 2026 09:25
@chirag-madlani chirag-madlani requested a review from a team as a code owner May 13, 2026 09:25
@chirag-madlani chirag-madlani marked this pull request as draft May 13, 2026 09:25
@github-actions github-actions Bot added safe to test Add this label to run secure Github workflows on PRs UI UI specific issues labels May 13, 2026
Comment on lines +189 to +203
function checkDuplicates(callsMap, scope) {
for (const [signature, data] of callsMap.entries()) {
if (data.count >= threshold) {
data.nodes.forEach((node, index) => {
if (index > 0) {
context.report({
node,
messageId: 'duplicateApiCall',
data: {
apiCall: signature,
count: data.count,
scope,
},
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 Bug: ESLint rule never fires due to wrong Map passed to checkDuplicates

In no-duplicate-api-calls.js, the CallExpression handler stores API call data in a nested Map structure: currentComponent.calls.get('global') returns an inner Map of signature -> {count, nodes, apiFunction}. However, the exit handler at line 252-253 passes the outer map (component.calls) to checkDuplicates(). This means checkDuplicates iterates over entries like ['global', Map], where data is a Map object — not {count, nodes}. Since Map.count is undefined, the condition data.count >= threshold will never be true, and the rule will silently never report any violations.

Pass the inner 'global' map to checkDuplicates instead of the outer map:

if (isComponent && componentStack.length > 0) {
    const component = componentStack.pop();
    const globalCalls = component.calls.get('global');
    if (globalCalls) {
      checkDuplicates(globalCalls, `component "${component.name}"`);
    }

    if (componentStack.length === 0) {
      currentComponent = null;
    } else {
      currentComponent = componentStack[componentStack.length - 1];
    }
  }
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

NODE_HEIGHT: 36,
}));

const mockNavigate = jest.fn();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Bug: Duplicate mockNavigate declaration will cause test failure

The diff adds const mockNavigate = jest.fn(); at line 69, but there is already an identical declaration at line 420 in the same file. In strict mode or with let/const, this causes a SyntaxError: Identifier 'mockNavigate' has already been declared. The pre-existing declaration at line 420 should be removed, or the new one at line 69 should replace it.

Remove the new duplicate declaration at line 69 since the one at line 420 already exists (or vice versa):

// Remove line 69: const mockNavigate = jest.fn();
// Keep only the single declaration at line 420
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Comment on lines +46 to +52
const handleCheckboxChange = (fieldName: string) => {
setCheckedItems((prev) =>
prev.includes(fieldName)
? prev.filter((item) => item !== fieldName)
: [...prev, fieldName]
);
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance: useMemo invalidated every render due to unstable dependency

handleCheckboxChange is added to the menuItems useMemo dependency array but is not wrapped in useCallback. Since it's a plain function declaration, it gets a new reference on every render, causing menuItems to recompute every time — completely defeating the purpose of useMemo.

Wrap handleCheckboxChange in useCallback to stabilize its reference:

const handleCheckboxChange = useCallback((fieldName: string) => {
  setCheckedItems((prev) =>
    prev.includes(fieldName)
      ? prev.filter((item) => item !== fieldName)
      : [...prev, fieldName]
  );
}, []);
  • Apply fix

Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens TypeScript typing across multiple UI utilities/components (replacing any with unknown/more specific types) and introduces a new custom ESLint rule (custom-rules/no-duplicate-api-calls) with accompanying documentation to help detect redundant API calls in React components.

Changes:

  • Replaced several any usages with unknown / stricter generics across UI utilities, hooks, and component props/refs.
  • Added and wired a custom ESLint rule (no-duplicate-api-calls) into the UI’s flat ESLint config, plus documentation (README/config/quick start) and an example file.
  • Minor refactors to improve hook dependency correctness and internal helper organization.

Reviewed changes

Copilot reviewed 34 out of 34 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
openmetadata-ui/src/main/resources/ui/src/utils/WorkflowConfigUtils.ts Narrows workflow definition typing for workflow config helpers.
openmetadata-ui/src/main/resources/ui/src/utils/ServiceConnectionDetailsUtils.tsx Refactors schema/key-value rendering with stricter types and helper extraction.
openmetadata-ui/src/main/resources/ui/src/utils/QueryBuilderUtils.tsx Replaces Record<string, any> with Record<string, unknown> in query filter conversion.
openmetadata-ui/src/main/resources/ui/src/utils/ExtensionPointRegistry.ts Changes default generic from any to unknown for extension contributions.
openmetadata-ui/src/main/resources/ui/src/utils/EntitySummaryPanelUtilsV1.tsx Tightens table render record typing (anyunknown).
openmetadata-ui/src/main/resources/ui/src/utils/CustomizaNavigation/CustomizeNavigation.test.ts Removes inline ESLint suppression comment near any cast.
openmetadata-ui/src/main/resources/ui/src/utils/CSV/CSVUtilsClassBase.tsx Introduces typed aliases to replace RenderEditCellProps<any, any>.
openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts Removes inline ESLint suppression comments around any casts.
openmetadata-ui/src/main/resources/ui/src/pages/SwaggerPage/RapiDocReact.tsx Narrows Rapidoc event callback types (anyRecord<string, unknown>).
openmetadata-ui/src/main/resources/ui/src/interface/data-insight.interface.ts Narrows Recharts tooltip generics for data insight tooltip props.
openmetadata-ui/src/main/resources/ui/src/hooks/usePubSub.ts Switches pub/sub callback generics default from any to unknown.
openmetadata-ui/src/main/resources/ui/src/contexts/WorkflowModeContext.tsx Narrows workflowDefinition context prop type (anyRecord<string, unknown>).
openmetadata-ui/src/main/resources/ui/src/components/Settings/Users/UsersProfile/UserProfileRoles/UserProfileRoles.component.tsx Attempts to type the Select ref more strictly.
openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx Attempts to type forwardRef and TreeSelect ref more strictly.
openmetadata-ui/src/main/resources/ui/src/components/Settings/Services/ServiceConnectionDetails/ServiceConnectionDetails.component.tsx Changes schema state typing (anyunknown).
openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/TermBoost/TermBoost.tsx Narrows option parameter typing in tag change handler.
openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/FilterConfiguration/FilterConfiguration.tsx Moves checkbox handler and adjusts hook dependencies.
openmetadata-ui/src/main/resources/ui/src/components/MyData/RightSidebar/FollowingWidget.tsx Narrows helper parameter typing for entity icon selection.
openmetadata-ui/src/main/resources/ui/src/components/KnowledgeGraph/KnowledgeGraph.test.tsx Adds a shared mockNavigate for router mocking.
openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/tabs/WorkFlowTab/WorkFlowHistory.interface.ts Replaces Record<string, any> with Record<string, unknown>.
openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeSuggestions.component.tsx Narrows ref type from any to a minimal focusable interface.
openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx Removes inline ESLint suppression comments around any usage.
openmetadata-ui/src/main/resources/ui/src/components/DomainListing/components/DomainTreeView.tsx Adds missing dependency to a callback dependency array.
openmetadata-ui/src/main/resources/ui/src/components/DataProducts/DataProductsPage/DataProductsPage.component.tsx Reorders fetch helpers without changing behavior.
openmetadata-ui/src/main/resources/ui/src/components/common/ListView/ListView.component.tsx Changes default generic type from any to Record<string, unknown>.
openmetadata-ui/src/main/resources/ui/src/components/common/atoms/asyncTreeSelect/useTreeData.tsx Moves helper function earlier for readability/organization.
openmetadata-ui/src/main/resources/ui/src/components/ActivityFeed/FeedEditor/FeedEditor.tsx Narrows mention item typing (Record<string, any>Record<string, unknown>).
openmetadata-ui/src/main/resources/ui/eslint.config.mjs Registers custom-rules plugin, enables no-duplicate-api-calls, and escalates no-explicit-any.
openmetadata-ui/src/main/resources/ui/eslint-rules/test-example.tsx Adds an example demonstrating duplicate API call detection (documentation/demo).
openmetadata-ui/src/main/resources/ui/eslint-rules/README.md Adds full documentation for the custom ESLint rule(s).
openmetadata-ui/src/main/resources/ui/eslint-rules/QUICK_START.md Adds quick-start usage guide for the new rule.
openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js Implements the no-duplicate-api-calls custom ESLint rule.
openmetadata-ui/src/main/resources/ui/eslint-rules/index.js Exposes the custom rule via a plugin-style rules export.
openmetadata-ui/src/main/resources/ui/eslint-rules/CONFIGURATION.md Adds detailed configuration/troubleshooting guide for the rule.
Comments suppressed due to low confidence (1)

openmetadata-ui/src/main/resources/ui/src/components/Settings/Team/TeamsSelectable/TeamsSelectableNew.tsx:33

  • This component declares forwardRef<HTMLDivElement, ...> and then casts the ref for an AntD TreeSelect. AntD TreeSelect refs are not DOM element refs (they expose imperative methods like focus/blur). Using HTMLDivElement here can break callers expecting the correct ref shape. Use AntD’s select ref type (BaseSelectRef / RefSelectProps, depending on your AntD version) instead of HTMLDivElement.
const TeamsSelectableNew = forwardRef<HTMLDivElement, TeamsSelectableProps>(
  (
    {
      showTeamsAlert,
      onSelectionChange,

Comment on lines +253 to +254
checkDuplicates(component.calls, `component "${component.name}"`);

Comment on lines +77 to +81
const options = context.options[0] || {};
const threshold = options.threshold || 2;
const checkUseEffect = options.checkUseEffect !== false;
const checkCallbacks = options.checkCallbacks !== false;
const allowedDuplicates = new Set(options.allowedDuplicates || []);
Comment on lines +121 to +124
objectName === 'axios' ||
objectName === 'APIClient' ||
['get', 'post', 'put', 'patch', 'delete'].includes(propertyName) ||
apiCallPatterns.some((pattern) => {
Comment on lines +139 to +143
if (
serviceType === EntityType.PIPELINE_SERVICE &&
key === 'connection' &&
value.type?.toString().toLowerCase() === 'airflow'
) {
Comment on lines +321 to +323
return renderInputField(
key,
value as string,
Comment on lines +1008 to 1011
render: (name: string, record: Record<string, unknown>) => (
<div className="d-inline-flex" style={{ maxWidth: '68%' }}>
<span className="break-word">{record.displayName || name}</span>
</div>
Comment on lines 66 to 69
className: 'menu-items',
}),
[entityFields, checkedItems]
[entityFields, checkedItems, handleCheckboxChange]
);
Comment on lines 288 to 292
open={isDropdownOpen}
options={useRolesOption}
popupClassName="roles-custom-dropdown-class"
ref={dropdownRef as any}
ref={dropdownRef as React.Ref<HTMLDivElement> | undefined}
tagRender={TagRenderer}
@github-actions
Copy link
Copy Markdown
Contributor

🔴 Playwright Results — 1 failure(s), 17 flaky

✅ 4069 passed · ❌ 1 failed · 🟡 17 flaky · ⏭️ 86 skipped

Shard Passed Failed Flaky Skipped
🟡 Shard 1 298 0 1 4
🟡 Shard 2 759 0 8 8
🟡 Shard 3 779 0 5 7
🔴 Shard 4 789 1 0 18
✅ Shard 5 709 0 0 41
🟡 Shard 6 735 0 3 8

Genuine Failures (failed on all attempts)

Pages/Domains.spec.ts › should render the domain tree view with correct details (shard 4)
Error: �[2mexpect(�[22m�[31mlocator�[39m�[2m).�[22mtoBeVisible�[2m(�[22m�[2m)�[22m failed

Locator: getByTestId('page-layout-v1').getByRole('textbox', { name: 'Search' })
Expected: visible
Timeout: 15000ms
Error: element(s) not found

Call log:
�[2m  - Expect "toBeVisible" with timeout 15000ms�[22m
�[2m  - waiting for getByTestId('page-layout-v1').getByRole('textbox', { name: 'Search' })�[22m

🟡 17 flaky test(s) (passed on retry)
  • Pages/Bots.spec.ts › Bots Page should work properly (shard 1, 1 retry)
  • Features/BulkEditEntity.spec.ts › Glossary (shard 2, 1 retry)
  • Features/DataQuality/TestCaseImportExportE2eFlow.spec.ts › Admin: Complete export-import-validate flow (shard 2, 1 retry)
  • Features/DataQuality/TestCaseResultPermissions.spec.ts › User with only VIEW cannot PATCH results (shard 2, 1 retry)
  • Features/Glossary/GlossaryWorkflow.spec.ts › should start term as Draft when glossary has reviewers (shard 2, 1 retry)
  • Features/KnowledgeCenter.spec.ts › Article mentions in description should working for Knowledge Center (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/KnowledgeCenterTextEditor.spec.ts › Rich Text Editor - Text Formatting (shard 2, 1 retry)
  • Features/RTL.spec.ts › Verify Following widget functionality (shard 3, 1 retry)
  • Features/Table.spec.ts › Table pagination with sorting should works (shard 3, 1 retry)
  • Features/Workflows/WorkflowOssRestrictions.spec.ts › save, cancel, and validate buttons visible; delete absent in edit mode (shard 3, 1 retry)
  • Flow/PersonaDeletionUserProfile.spec.ts › User profile loads correctly before and after persona deletion (shard 3, 1 retry)
  • Flow/PersonaFlow.spec.ts › Set default persona for team should work properly (shard 3, 1 retry)
  • Features/AutoPilot.spec.ts › Agents created by AutoPilot should be deleted (shard 6, 1 retry)
  • Pages/Lineage/DataAssetLineage.spec.ts › verify create lineage for entity - Worksheet (shard 6, 1 retry)
  • Pages/Lineage/LineageFilters.spec.ts › Verify lineage schema filter selection (shard 6, 1 retry)

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

@gitar-bot
Copy link
Copy Markdown

gitar-bot Bot commented May 13, 2026

Code Review 🚫 Blocked 1 resolved / 4 findings

Refactors TypeScript types and improves testing infrastructure, but currently blocked due to a broken ESLint rule logic, duplicate mock declarations in tests, and an unstable useMemo dependency.

🚨 Bug: ESLint rule never fires due to wrong Map passed to checkDuplicates

📄 openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:189-203 📄 openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:252-253 📄 openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:263-277

In no-duplicate-api-calls.js, the CallExpression handler stores API call data in a nested Map structure: currentComponent.calls.get('global') returns an inner Map of signature -> {count, nodes, apiFunction}. However, the exit handler at line 252-253 passes the outer map (component.calls) to checkDuplicates(). This means checkDuplicates iterates over entries like ['global', Map], where data is a Map object — not {count, nodes}. Since Map.count is undefined, the condition data.count >= threshold will never be true, and the rule will silently never report any violations.

Pass the inner 'global' map to checkDuplicates instead of the outer map
if (isComponent && componentStack.length > 0) {
    const component = componentStack.pop();
    const globalCalls = component.calls.get('global');
    if (globalCalls) {
      checkDuplicates(globalCalls, `component "${component.name}"`);
    }

    if (componentStack.length === 0) {
      currentComponent = null;
    } else {
      currentComponent = componentStack[componentStack.length - 1];
    }
  }
⚠️ Bug: Duplicate mockNavigate declaration will cause test failure

📄 openmetadata-ui/src/main/resources/ui/src/components/KnowledgeGraph/KnowledgeGraph.test.tsx:69

The diff adds const mockNavigate = jest.fn(); at line 69, but there is already an identical declaration at line 420 in the same file. In strict mode or with let/const, this causes a SyntaxError: Identifier 'mockNavigate' has already been declared. The pre-existing declaration at line 420 should be removed, or the new one at line 69 should replace it.

Remove the new duplicate declaration at line 69 since the one at line 420 already exists (or vice versa)
// Remove line 69: const mockNavigate = jest.fn();
// Keep only the single declaration at line 420
⚠️ Performance: useMemo invalidated every render due to unstable dependency

📄 openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/FilterConfiguration/FilterConfiguration.tsx:46-52 📄 openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/FilterConfiguration/FilterConfiguration.tsx:68

handleCheckboxChange is added to the menuItems useMemo dependency array but is not wrapped in useCallback. Since it's a plain function declaration, it gets a new reference on every render, causing menuItems to recompute every time — completely defeating the purpose of useMemo.

Wrap handleCheckboxChange in useCallback to stabilize its reference
const handleCheckboxChange = useCallback((fieldName: string) => {
  setCheckedItems((prev) =>
    prev.includes(fieldName)
      ? prev.filter((item) => item !== fieldName)
      : [...prev, fieldName]
  );
}, []);
✅ 1 resolved
Quality: eslint-disable comments replaced with blank lines instead of removed

📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:29 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:49 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:338 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:422 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:571 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:604 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:625 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:643 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:672 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:701 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:725 📄 openmetadata-ui/src/main/resources/ui/src/components/Entity/EntityLineage/NodeChildren/NodeChildren.component.test.tsx:759 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:35 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:80 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:92 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:108 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:250 📄 openmetadata-ui/src/main/resources/ui/src/utils/Auth/TokenService/TokenServiceUtil.test.ts:272
In NodeChildren.component.test.tsx and TokenServiceUtil.test.ts, the // eslint-disable-next-line @typescript-eslint/no-explicit-any comments are replaced with empty lines (just whitespace) rather than being fully deleted. This leaves trailing whitespace/blank lines that serve no purpose.

🤖 Prompt for agents
Code Review: Refactors TypeScript types and improves testing infrastructure, but currently blocked due to a broken ESLint rule logic, duplicate mock declarations in tests, and an unstable useMemo dependency.

1. 🚨 Bug: ESLint rule never fires due to wrong Map passed to checkDuplicates
   Files: openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:189-203, openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:252-253, openmetadata-ui/src/main/resources/ui/eslint-rules/no-duplicate-api-calls.js:263-277

   In `no-duplicate-api-calls.js`, the `CallExpression` handler stores API call data in a nested Map structure: `currentComponent.calls.get('global')` returns an inner Map of `signature -> {count, nodes, apiFunction}`. However, the exit handler at line 252-253 passes the *outer* map (`component.calls`) to `checkDuplicates()`. This means `checkDuplicates` iterates over entries like `['global', Map]`, where `data` is a `Map` object — not `{count, nodes}`. Since `Map.count` is `undefined`, the condition `data.count >= threshold` will never be true, and the rule will silently never report any violations.

   Fix (Pass the inner 'global' map to checkDuplicates instead of the outer map):
   if (isComponent && componentStack.length > 0) {
       const component = componentStack.pop();
       const globalCalls = component.calls.get('global');
       if (globalCalls) {
         checkDuplicates(globalCalls, `component "${component.name}"`);
       }
   
       if (componentStack.length === 0) {
         currentComponent = null;
       } else {
         currentComponent = componentStack[componentStack.length - 1];
       }
     }

2. ⚠️ Bug: Duplicate `mockNavigate` declaration will cause test failure
   Files: openmetadata-ui/src/main/resources/ui/src/components/KnowledgeGraph/KnowledgeGraph.test.tsx:69

   The diff adds `const mockNavigate = jest.fn();` at line 69, but there is already an identical declaration at line 420 in the same file. In strict mode or with `let`/`const`, this causes a `SyntaxError: Identifier 'mockNavigate' has already been declared`. The pre-existing declaration at line 420 should be removed, or the new one at line 69 should replace it.

   Fix (Remove the new duplicate declaration at line 69 since the one at line 420 already exists (or vice versa)):
   // Remove line 69: const mockNavigate = jest.fn();
   // Keep only the single declaration at line 420

3. ⚠️ Performance: useMemo invalidated every render due to unstable dependency
   Files: openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/FilterConfiguration/FilterConfiguration.tsx:46-52, openmetadata-ui/src/main/resources/ui/src/components/SearchSettings/FilterConfiguration/FilterConfiguration.tsx:68

   `handleCheckboxChange` is added to the `menuItems` useMemo dependency array but is not wrapped in `useCallback`. Since it's a plain function declaration, it gets a new reference on every render, causing `menuItems` to recompute every time — completely defeating the purpose of `useMemo`.

   Fix (Wrap handleCheckboxChange in useCallback to stabilize its reference):
   const handleCheckboxChange = useCallback((fieldName: string) => {
     setCheckedItems((prev) =>
       prev.includes(fieldName)
         ? prev.filter((item) => item !== fieldName)
         : [...prev, fieldName]
     );
   }, []);

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants