Skip to content

feat(heureka): migrate ESLint config to vite-react-ts.mjs - #1883

Open
hodanoori wants to merge 14 commits into
mainfrom
hoda-heureka-update-vite-react-type-script
Open

feat(heureka): migrate ESLint config to vite-react-ts.mjs#1883
hodanoori wants to merge 14 commits into
mainfrom
hoda-heureka-update-vite-react-type-script

Conversation

@hodanoori

@hodanoori hodanoori commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrates the Heureka application from the legacy juno-typescript.mjs ESLint config to the new vite-react-ts.mjs configuration. The new config provides pure TypeScript linting rules without JavaScript rule interference, enabling strict type checking across the app. All 18+ legacy workaround rule overrides have been removed and replaced with real fixes. Part of the project-wide ESLint migration epic #1565.

Changes Made

  • Switch eslint.config.mjs to import vite-react-ts.mjs and remove all legacy rule workarounds
  • Add void operator to all fire-and-forget navigate() calls to satisfy no-floating-promises
  • Wrap async onClick handlers with void to fix no-misused-promises
  • Remove async from test loaders and act() callbacks that had no await (require-await); restore await act(async () => {...}) with a scoped disable for two Suspense-dependent tests where the async is required for React promise resolution
  • Replace issuesPromise && (...) with issuesPromise != null && (...) to fix no-misused-promises in boolean conditionals
  • Type queryClient.setQueriesData cache callbacks with a local cache shape type instead of any
  • Type getActiveVulnerabilityFilter and sanitizeFilterSettings with concrete types instead of any
  • Cast DateTime GraphQL scalar fields explicitly to fix no-unsafe-assignment
  • Fix getNormalizedError network error shape with an explicit type instead of any cast
  • Remove redundant string | "" union types in ComponentInstance (no-redundant-type-constituents)
  • Remove unnecessary as X type assertions in route validateSearch functions
  • Fix @ts-ignore → removed entirely in codegen.ts (dotenv has types)
  • Add /* eslint-disable */ header to auto-generated graphql.ts
  • Replace any in types/index.d.ts plugin options with Record<string, unknown>
  • Replace any in utils.ts utility functions (isEmpty, isNil, omit) with unknown
  • Fix ErrorBoundary resetKeys prop type from any to unknown[] and remove redundant !! cast
  • Add explicit React.MouseEvent / React.ChangeEvent / Date[] types to event handler callbacks where juno-ui-components prop types resolve as any in CI but correctly locally
  • Add scoped eslint-disable comments for useAuth() from greenhouse-auth-provider and encodeV2/decodeV2 from juno-url-state-provider — these packages export error-typed values in CI due to type resolution differences; each disable has an explanatory comment
  • Apply lint fixes to the new RemediationModal component introduced by a concurrent main branch refactor (same patterns: useAuth() cast, void handleConfirm(), typed input callbacks)
  • Add 2 justified rule overrides in eslint.config.mjs: react-refresh/only-export-components (TanStack Router requires mixed exports in route files) and react-hooks/set-state-in-effect (intentional derived-state sync pattern)
  • Set reportUnusedDisableDirectives: "off" to suppress false-positive warnings for CI-only disables that are unused locally (where package types resolve correctly)
  • Exclude vite.config.ts, vitest.config.ts, vitest.setup.ts, and tailwind.config.ts from ESLint entirely (not included in tsconfig.json, causing parse errors in type-aware linting)

Review Guide

Changes are mechanical and fall into 6 categories — reviewers can approve categories 2–5 at a glance and focus attention on 1 and 6:

  1. Config & setup (eslint.config.mjs, package.json, vite-react-ts.mjs) — the actual migration; the only part worth careful review
  2. void navigate(...) (~10 files) — fire-and-forget navigate() calls marked void; no behaviour change
  3. async removal (~8 test files) — loader: async () =>loader: () => and act(asyncact( where there was no await; no behaviour change. Two Suspense tests keep await act(async () => {...}) with a scoped lint disable.
  4. Promise boolean guards (ImageIssuesList, ImageVersionIssuesList) — {promise && ...}{promise != null && ...}; no behaviour change
  5. Type tightening (utils.ts ×2, ErrorBoundary, getTestRouter, types/index.d.ts, event handler annotations) — any replaced with concrete types or explicit casts with comments
  6. Typed cache callbacks (IssuesDataRow, RemediatedIssueDataRow, RemediationHistoryPanel, RemediationModal) — queryClient.setQueriesData callbacks now use a local RemediationsCache type instead of any; verify the shape matches what's actually stored in the cache

Related Issues

Screenshots (if applicable)

none

Testing Instructions

  1. pnpm i
  2. pnpm TASK

Checklist

  • I have performed a self-review of my code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have made corresponding changes to the documentation (if applicable).
  • My changes generate no new warnings or errors.
  • I have created a changeset for my changes.

PR Manifesto

Review the PR Manifesto for best practises.

Switches from juno-typescript.mjs to vite-react-ts.mjs, removing
all 18+ legacy rule workarounds and fixing every violation surfaced
by the stricter TypeScript-only config.

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Copilot AI lite review requested due to automatic review settings August 11, 2026 13:48
@hodanoori
hodanoori requested a review from a team as a code owner August 11, 2026 13:48
@changeset-bot

changeset-bot Bot commented Aug 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: d8cc78b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@cloudoperators/juno-app-heureka Patch
@cloudoperators/juno-app-greenhouse Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Migrates the Heureka app to the new shared vite-react-ts.mjs ESLint flat-config and updates the app codebase to satisfy stricter type-aware TypeScript lint rules introduced by the migration.

Changes:

  • Switch apps/heureka/eslint.config.mjs to use @cloudoperators/juno-config/eslint/vite-react-ts.mjs and replace legacy rule workarounds with targeted, justified overrides.
  • Apply mechanical lint fixes across the app (e.g., void navigate(...), remove unnecessary async, tighten types / remove any, adjust promise guards).
  • Update Heureka devDependencies/lockfile and add a changeset documenting the migration.

Reviewed changes

Copilot reviewed 41 out of 44 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-lock.yaml Locks new ESLint-related dependencies needed for the new config/migration.
packages/config/eslint/vite-react-ts.mjs Introduces/adjusts the shared Vite React TS ESLint flat-config used by apps.
apps/heureka/src/utils.ts Tightens utility typings (anyunknown) to satisfy stricter TS lint rules.
apps/heureka/src/types/index.d.ts Replaces Record<string, any> with Record<string, unknown> for plugin options.
apps/heureka/src/routes/vulnerabilities/index.tsx Removes unnecessary type assertion and async loader where no await is used.
apps/heureka/src/routes/services/index.tsx Removes unnecessary type assertion and marks navigate() as fire-and-forget with void.
apps/heureka/src/mocks/getTestRouter.tsx Adjusts test router helper typing/imports to satisfy linting constraints.
apps/heureka/src/generated/graphql.ts Marks generated file and disables linting for it.
apps/heureka/src/components/Vulnerabilities/VulnerabilitiesList/VulnerabilityDetailsPanel/VulnerabilityServices.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Vulnerabilities/VulnerabilitiesList/VulnerabilityDetailsPanel/index.tsx Adds void to navigations and removes redundant boolean cast in heading.
apps/heureka/src/components/Vulnerabilities/VulnerabilitiesList/VulnerabilitiesDataRows/index.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Vulnerabilities/VulnerabilitiesList/index.test.tsx Removes unnecessary async loader in tests.
apps/heureka/src/components/Vulnerabilities/VulnerabilitiesFilters.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Vulnerabilities/Vulnerabilities.test.tsx Removes unnecessary async loader/act(async ...) usage.
apps/heureka/src/components/Vulnerabilities/utils.ts Replaces any with concrete types; adds explicit DateTime scalar casting and safer cache shape typing.
apps/heureka/src/components/Services/utils.ts Tightens error typing and removes redundant type constituents / any usage.
apps/heureka/src/components/Services/ServicesList/ServicesDataRows/index.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Services/ServicesList/ServicePanel.tsx Adds void to fire-and-forget navigation and removes redundant boolean cast in heading.
apps/heureka/src/components/Services/ServicesList/ServicePanel.test.tsx Removes unnecessary async loader in tests.
apps/heureka/src/components/Services/ServicesList/index.test.tsx Removes unnecessary async loader in tests.
apps/heureka/src/components/Services/ServicesFilters.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Services/Services.test.tsx Removes unnecessary async loader/act(async ...) usage.
apps/heureka/src/components/Service/index.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Service/ImageVersionDetails/ImageVersionIssuesList/index.tsx Fixes promise guard in JSX (promise != null && ...).
apps/heureka/src/components/Service/ImageDetails/RiskAcceptanceModal/RiskAcceptanceModal.test.tsx Tightens mocked component typings and removes unnecessary async test wrapper.
apps/heureka/src/components/Service/ImageDetails/RiskAcceptanceModal/index.tsx Wraps async click handler; adjusts auth typing to satisfy lint rules.
apps/heureka/src/components/Service/ImageDetails/index.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Service/ImageDetails/ImageVersionsList/index.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/RemediationHistoryPanel/RemediationHistoryPanel.test.tsx Replaces any promise typing with explicit result shape.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/RemediationHistoryPanel/index.tsx Tightens query key/cache typing and wraps async click handler with void.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/RemediatedIssuesDataRows/RemediatedIssuesDataRows.test.tsx Removes unnecessary async act(...) usage.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/RemediatedIssuesDataRows/RemediatedIssueDataRow/index.tsx Adds typed cache shapes for setQueriesData and removes any usage.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/IssuesDataRows/IssuesDataRows.test.tsx Updates test act(...) usage and related lint-driven changes.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/IssuesDataRows/IssuesDataRow/index.tsx Adds typed cache shapes for setQueriesData and removes any usage.
apps/heureka/src/components/Service/ImageDetails/ImageIssuesList/index.tsx Fixes promise guards in JSX and adds void to fire-and-forget navigations.
apps/heureka/src/components/Service/ImageDetails/FalsePositiveModal/index.tsx Wraps async click handler; adjusts auth typing to satisfy lint rules.
apps/heureka/src/components/common/Navigation.tsx Adds void to fire-and-forget navigation.
apps/heureka/src/components/common/ErrorBoundary/index.tsx Tightens resetKeys type (anyunknown[]) and removes redundant boolean cast.
apps/heureka/src/components/common/ErrorBoundary/index.test.tsx Tightens spy typing and adds lint suppression for mockRestore call.
apps/heureka/src/components/common/Breadcrumb.tsx Adds void to fire-and-forget navigation.
apps/heureka/package.json Adds ESLint-related devDependencies required by the new config.
apps/heureka/eslint.config.mjs Switches to shared vite-react-ts.mjs config; replaces legacy overrides with 2 justified ones.
apps/heureka/codegen.ts Removes unnecessary @ts-ignore (dotenv has types).
.changeset/heureka-eslint-vite-react-ts-migration.md Adds changeset entry documenting the ESLint config migration.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Suppressed comments (1)

packages/config/eslint/vite-react-ts.mjs:29

  • This config still extends @eslint/js's recommended rules, which reintroduces JavaScript rule sets into what is described (in the PR/epic) as a “pure TypeScript” ESLint config. If the goal is to avoid JS/TS rule mixing, drop the JS recommended config here and rely on the TypeScript-ESLint presets instead.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/heureka/eslint.config.mjs
Comment thread apps/heureka/src/components/Service/ImageDetails/RiskAcceptanceModal/index.tsx Outdated
Comment thread apps/heureka/src/components/Service/ImageDetails/FalsePositiveModal/index.tsx Outdated
hodanoori and others added 9 commits August 11, 2026 15:59
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
- Fix inaccurate comment in eslint.config.mjs: ignores excludes files
  entirely, not just from type-aware linting
- Fix bug: act() with sync callback returns void, not the render result;
  capture unmount from renderWithRouter() directly

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
…nces

- Add explicit React.MouseEvent types to event handlers (stopPropagation,
  preventDefault) where juno-ui-components prop types resolve as any in CI
- Add explicit ChangeEvent/Date[] types to RemediationModal input handlers
- Add explicit string|undefined type to onSearch callbacks
- Add eslint-disable comments for greenhouse-auth-provider and
  juno-url-state-provider types that are error-typed in CI (EmbeddedAuth,
  AuthState, encodeV2, decodeV2)
- Add eslint-disable to vi.mock importActual calls in test files
- Add eslint-disable to getSeverityColor/getSeverityIcon assignments
- Set reportUnusedDisableDirectives: off to suppress unused-directive
  warnings for CI-only disables

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
…ons error type in CI

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
…rors

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
@hodanoori hodanoori added the greenhouse-pr-build Set this label to create a preview image which will automatically set the `greenhouse-pr-preview` label Aug 12, 2026
@github-actions github-actions Bot added the greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY. label Aug 12, 2026
Comment thread apps/heureka/src/components/common/SeverityCount.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 47 out of 50 changed files in this pull request and generated 2 comments.

Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

Comment thread apps/heureka/package.json
Comment thread pnpm-lock.yaml
taymoor89
taymoor89 previously approved these changes Aug 13, 2026

@taymoor89 taymoor89 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall looks good to me!
I'm a little concerned about adding void to every navigate call, since our intention is simply to trigger the navigation without waiting for the promise to resolve. That said, I think we can live with it, as the rule provides more value than the minor inconvenience this introduces.

@taymoor89 taymoor89 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Let's address AI suggestions, some of these are good to address

- Extract QueryFilter/RemediationsCache to shared remediationCacheTypes.ts
  and reuse across IssuesDataRow, RemediatedIssueDataRow, RemediationHistoryPanel
- Add explanatory comments to file-level eslint-disable in IssueIcon,
  SeverityCount, VulnerabilityDataRow (CI-only type resolution issue)
- Add eslint-disable with comment for refreshKey in RemediationHistoryPanel
  useMemo (intentional trigger dependency, not a data dependency)
- Fix useCallback missing deps: add setVulnerabilitiesSuccessMessage and
  setRemediatedSuccessMessage to dependency arrays in ImageIssuesList
- Align postcss version in package.json to 8.5.23 to match lockfile

Signed-off-by: Hoda Noori <hoda.noori@sap.com>
@github-actions github-actions Bot removed the greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY. label Aug 14, 2026
@github-actions github-actions Bot added the greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY. label Aug 14, 2026
Signed-off-by: Hoda Noori <hoda.noori@sap.com>
@github-actions github-actions Bot added greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY. and removed greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY. labels Aug 14, 2026
@hodanoori

hodanoori commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Overall looks good to me!
I'm a little concerned about adding void to every navigate call, since our intention is simply to trigger the navigation without waiting for the promise to resolve. That said, I think we can live with it, as the rule provides more value than the minor inconvenience this introduces.

The void is purely there to satisfy the no-floating-promises rule, not to change behavior. The navigation still fires synchronously and we don't await it. One alternative would be to wrap navigate in a helper that returns void explicitly, but that adds indirection for little gain. Happy to keep it as-is if you're fine with it. Thanks for the review

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

Labels

greenhouse-pr-build Set this label to create a preview image which will automatically set the `greenhouse-pr-preview` greenhouse-pr-preview THIS LABEL IS SET AUTOMATICALLY.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task](Heureka): Migrate to new Vite-React-TypeScript ESLint configuration

4 participants