Skip to content

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

Open
hodanoori wants to merge 12 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 12 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: 5ed0dc1

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
* SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and Juno contributors
* SPDX-License-Identifier: Apache-2.0
*/
/* eslint-disable @typescript-eslint/no-unsafe-assignment */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

thats in nowhere i am confused

setIsExpanded(!isExpanded)
}

type QueryFilter = { service?: string[]; image?: string[]; vulnerability?: string[] }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That could be reused

`
}

type QueryFilter = { service?: string[]; image?: string[]; vulnerability?: string[] }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

here

// staleTime: 0 makes ensureQueryData treat any cached entry as immediately stale, forcing a
// network request without cancelling in-flight queries (unlike removeQueries).
return fetchRemediations({ apiClient, queryClient, filter, staleTime: 0 })
}, [service, image, vulnerability, apiClient, queryClient, refreshKey])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if the linter is right and the refreshKey is not needed good to clean this up

`Vulnerability ${cveNumber} has been marked as a false positive and moved to the Remediated list.`
)
}, [])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

may take a look at these linter warnings

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 on lines 71 to 73
"jsdom": "30.0.1",
"postcss": "8.5.10",
"prettier": "3.8.5",
Comment thread pnpm-lock.yaml
Comment on lines +538 to +540
postcss:
specifier: ^8.5.18
version: 8.5.23
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

3 participants