Skip to content

chore: Update dependency @eslint-react/eslint-plugin to v5#1704

Merged
Aureliolo merged 5 commits into
mainfrom
renovate/major-web
May 3, 2026
Merged

chore: Update dependency @eslint-react/eslint-plugin to v5#1704
Aureliolo merged 5 commits into
mainfrom
renovate/major-web

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate Bot commented May 2, 2026

This PR contains the following updates:

Package Change Age Confidence
@eslint-react/eslint-plugin (source) 4.2.35.7.1 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


Release Notes

Rel1cx/eslint-react (@​eslint-react/eslint-plugin)

v5.7.1

Compare Source

🐞 Fixes
  • all preset: Fixed an issue where the all preset accidentally included rules requiring type information (#​1744).
📝 Documentation
  • Fixed a typo in the shared settings description.
  • Fixed missing trailing commas in ESLint settings examples.
  • Updated no-unused-state rule wording and examples.
  • Added a Resources section with AST Explorer, ESLint Developer Guide, and TypeScript Compiler API links to kit-related documentation pages.
🏗️ Internal
  • Pinned dependency versions for next and @rbxts/react.
  • Added react-compiler-fixtures-all-preset.jsonl snapshot generation.

Full Changelog: Rel1cx/eslint-react@v5.7.0...v5.7.1

v5.7.0

Compare Source

✨ New
  • react-x/no-unused-state: The rule re-added as a no-op in v5.6.6 is now fully implemented. It detects state variables declared via useState (or similar state hooks) that are defined but never read, or only read inside an effect or effect dependency array (#​1741).
📝 Documentation
  • Updated minimum version requirements in README and docs (ESLint 10.2.1, TypeScript 6.0.3, pnpm 10.33.2).
  • Fixed no-unused-state migration docs and removed rule reasons.

LTS Maintenance Mode: Starting with v5.7.0, the project has entered a Long-Term Support (LTS) maintenance mode. New feature development is temporarily on hold while the project prioritizes bug fixes, rule improvements, and documentation updates. See #​1740 for details.

Full Changelog: Rel1cx/eslint-react@v5.6.6...v5.7.0

v5.6.6

Compare Source

✨ New
  • react-x/no-unused-state: Re-add the react-x/no-unused-state rule that was removed in 5.0.0 as a no-op rule for detecting unused state in function components in a future release.

Full Changelog: Rel1cx/eslint-react@v5.6.4...v5.6.6

v5.6.4

Compare Source

✨ New
  • react-x/no-unused-class-component-members: Now flags shouldComponentUpdate methods defined in classes extending PureComponent as unused, since PureComponent implements its own shouldComponentUpdate with shallow prop and state comparison (#​1738).
📝 Documentation
  • Added jsx preset documentation to multiple rule docs.
  • Removed empty Presets sections from rule documentation.
🏗️ Internal
  • ast: Added an optional stop predicate to findParent utility for more control over ancestor traversal (#​1736).
  • Replaced skott with sentrux for architecture linting.
  • Updated sentrux rules and baseline metrics.

Full Changelog: Rel1cx/eslint-react@v5.6.3-beta.0...v5.6.4

v5.6.2

Compare Source

🐞 Fixes
  • react-x/use-memo: Fixed false positives in useMemo dependency analysis by using reference/definition analysis (#​1735).
📝 Documentation
  • Added anchor links to rule names in recipe docs.
  • Added migration overview page with sidebar entry.
  • Added naming-convention preset configuration documentation.
  • Simplified conditional formatting in custom-rules-of-state recipe.
  • Updated migration guide and added noDirectAccessProps custom rule example.
🏗️ Internal
  • Removed unused diagram components and imports.
  • Reordered redirects with comments for clarity.
  • Bumped lucide-react from 1.12.0 to 1.14.0.
  • Updated baseline-browser-mapping to 2.10.24.

Full Changelog: Rel1cx/eslint-react@v5.6.0...v5.6.2

v5.6.0

Compare Source

This release consolidates all changes since v4.2.1.

💥 Breaking Changes
Core API Refactoring (@​eslint-react/core)
  • Performed a large-scale flattening refactor of the core package's internal structure, merging modules previously scattered across subdirectories like component/, function/, hook/, semantic/, and api/ into the root directory.
  • Renamed several core APIs:
    • isReactAPIisAPI
    • isReactAPICallisAPICall
    • isInitializedFromReactisAPIFromReact
    • isInitializedFromReactNativeisAPIFromReactNative
    • ComponentDetectionHintFunctionComponentDetectionHint
    • ComponentFlagFunctionComponentFlag
    • getComponentCollectorgetFunctionComponentCollector
    • getComponentCollectorLegacygetClassComponentCollector
  • Migrated type utilities (type-is, type-name, type-variant) from eslint-plugin-react-x to @eslint-react/core.
  • Updated the Toolkit interface in @eslint-react/kit to reflect the naming changes above.
Kit API Simplification (@​eslint-react/kit)
  • Simplified RuleToolkit.is API: Removed pre-built identifier predicates (memo, lazy, forwardRef, etc.) from RuleToolkit.is. Only *Call variants and API/APICall factories are now available.
  • Renamed initialization checkers:
    • initializedFromReactAPIFromReact
    • initializedFromReactNativeAPIFromReactNative
  • Code using is.memo(node), is.lazy(node), etc. must migrate to is.memoCall(node) or use is.API("memo")(node).
Type Alias Removal
  • Removed deprecated RuleDefinition type alias: The RuleDefinition type has been completely removed from @eslint-react/kit. Use RuleFunction instead.
Removed Rules

The following rules have been removed from eslint-plugin-react-x, eslint-plugin-react-dom, and eslint-plugin-react-debug:

Rule Package Notes
component-hook-factories react-x Removed from all configs
no-redundant-should-component-update react-x Removed from all configs
no-unnecessary-use-callback react-x Removed from all configs
no-unnecessary-use-memo react-x Removed from all configs
no-unused-state react-x Removed from all configs
prefer-destructuring-assignment react-x Removed from all configs
prefer-namespace-import react-x Removed from all configs
prefer-namespace-import react-dom Removed from all configs
debug/class-component react-debug Removed from all configs
Class Component Support Deprecation
  • All Class Component-related detection functions in the core package (such as isClassComponent, isPureComponent, and various lifecycle checkers) have been marked as @deprecated, retaining only minimal compatibility support for existing rules.
  • Rules in eslint-plugin-react-web-api, including no-leaked-event-listener, no-leaked-interval, and no-leaked-timeout, have removed detection for Class Component lifecycles (componentDidMount / componentWillUnmount) and now only report on Hook Effects (useEffect, etc.).
✨ New
New Rules
  • react-x/globals: New rule for restricting usage of global variables in React components.
  • react-x/static-components: New rule for enforcing static component definitions. Enhanced with variable reference tracking and a createdHere diagnostic to reduce false positives.
  • react-web-api/no-leaked-fetch: New rule that detects leaked fetch calls in effects, closing #​1714.
Kit Enhancements
  • Added ast.findParent utility to @eslint-react/kit for traversing AST ancestors.
  • Added support for Universally Unique Lexicographically Sortable Identifiers (ULID) for anonymous rules (later migrated to node:crypto randomBytes).
Custom Rule Examples
  • Added Error Boundaries custom rule example.
  • Added boolean prop naming custom rule and documentation.
🐞 Fixes
Rule Fixes
  • react-x/error-boundaries: Fixed false positives on non-React code and resolved catch block over-reporting.
  • react-x/set-state-in-effect: Improved validation accuracy.
  • react-x/use-memo: Added reassignment check, aligned message IDs, and added support for for-of/for-in loops.
Config Fixes
  • Added missing rules to presets, cleaned up experimental disables, and updated documentation.
  • Extracted naming-convention preset and fixed config gaps.
Type Expression Fixes
  • Added missing Extract.unwrap for type expressions and chain expressions.
  • Unwrapped type expressions before inspecting AST node types.
🪄 Improvements
API & Refactoring
  • ast: Normalized API naming conventions and rewrote Check helpers.
  • ast: Renamed isJSXLikeisJSXElementOrFragment and isMethodOrPropertyisPropertyOrMethod.
  • Extracted ESLint types and utilities into the @eslint-react/eslint package.
  • Extracted @eslint-react/jsx from @eslint-react/core into a standalone utility package for static analysis of JSX patterns.
  • Migrated to @ and # path aliases and replaced tsx with vite-node.
  • Moved pattern utilities to rule directories and extracted rule helpers into co-located lib.ts modules across multiple plugins.
  • Reorganized imports across the codebase.
  • Replaced RuleConfig with Linter.RulesRecord from ESLint.
  • Restructured monorepo packages directory layout.
  • Unified import style across packages and plugins.
Core & AST Improvements
  • ast: Updated FunctionInitPath types to support method definitions and property arrow functions in class expressions.
  • ast/isNodeEqual: Fixed JSXNamespacedName comparison logic.
Rule Improvements
  • react-x/static-components: Registered in all, x, and disable-experimental configs.
  • react-rsc/function-definition: Added directive position and quote checks.
  • Extracted HOC detection helpers to dedicated lib.ts files.
Website & Documentation Improvements
  • Added LLM routes (/llms.txt, /llms-full.txt, /llms.mdx).
  • Added inline TOCs and improved navigation.
  • Enabled twoslash type-checking for code examples.
  • Improved accessibility and unified layout configuration.
Testing
  • Expanded compiler fixture coverage across 9 rules.
  • Added comprehensive unit tests for component/hook detection utilities.
Dependencies
  • Bumped TypeScript to 6.0.3.
  • Bumped Vite to ^8.0.7 in examples.
  • Bumped @typescript-eslint packages to 8.59.1.
  • Bumped tsl-dx, tsdown, fumadocs, postcss, lucide-react, eslint-plugin-package-json, and other dependencies.
📝 Documentation
  • Added custom rule recipes for React Children API, Context API, props, state, boolean prop naming, and error boundaries.
  • Added migration examples (no-set-state, no-string-refs).
  • Added IMPL vs SPEC diff documents for 5 React Compiler aligned rules.
  • Added spec documentation for validation rules.
  • Added rule feature docs.
  • Added table of contents to multiple documentation files.
  • Updated migrating-from-eslint-plugin-react guide.
  • Updated local packages docs.
  • Updated roadmap and contributing architecture diagram.
🏗️ Internal
  • Added build:plugins script and updated build path patterns.
  • Added publishConfig.access to packages and marked @local/eff as private.
  • Added documentation comments to rule scripts.
  • Added typedoc docs and engines field.
  • Extracted shared tsdown config.
  • Fixed high-priority build, lockfile, script and doc inconsistencies.
  • Removed "Naming Pattern Quick Reference" from AST abbreviations doc.
  • Removed major-release-checklist.md.
  • Removed scripts/prepare-release.ts and the accompanying prepare:release npm script.
  • Removed barrel exports for utils.
  • Removed unused dependencies and added missing devDependencies.

Full Changelog: Rel1cx/eslint-react@v4.2.1...v5.6.0


Configuration

📅 Schedule: (in timezone Etc/UTC)

  • Branch creation
    • Between 12:00 AM and 06:59 AM, only on Saturday (* 0-6 * * 6)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate Bot added the dependencies Pull requests that update a dependency file label May 2, 2026
@renovate renovate Bot requested a review from Aureliolo as a code owner May 2, 2026 05:57
@renovate renovate Bot added scope:web Vue 3 dashboard type:chore Maintenance, cleanup, dependency updates dependencies Pull requests that update a dependency file labels May 2, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 2, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

OpenSSF Scorecard

Scorecard details
PackageVersionScoreDetails
npm/@eslint-react/ast 5.7.1 UnknownUnknown
npm/@eslint-react/core 5.7.1 UnknownUnknown
npm/@eslint-react/eslint 5.7.1 UnknownUnknown
npm/@eslint-react/eslint-plugin 5.7.1 UnknownUnknown
npm/@eslint-react/jsx 5.7.1 UnknownUnknown
npm/@eslint-react/shared 5.7.1 UnknownUnknown
npm/@eslint-react/var 5.7.1 UnknownUnknown
npm/eslint-plugin-react-dom 5.7.1 UnknownUnknown
npm/eslint-plugin-react-jsx 5.7.1 UnknownUnknown
npm/eslint-plugin-react-naming-convention 5.7.1 UnknownUnknown
npm/eslint-plugin-react-rsc 5.7.1 UnknownUnknown
npm/eslint-plugin-react-web-api 5.7.1 UnknownUnknown
npm/eslint-plugin-react-x 5.7.1 UnknownUnknown

Scanned Files

  • web/package-lock.json

@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 2, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​size-limit@​12.1.01001008087100
Addednpm/​tailwindcss@​4.2.41001008498100
Addednpm/​tailwind-merge@​3.5.01001008696100
Addednpm/​storybook@​10.3.69810088100100
Updatednpm/​@​eslint-react/​eslint-plugin@​4.2.3 ⏵ 5.7.19910010096100

View full report

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 2, 2026

Merging this PR will not alter performance

✅ 21 untouched benchmarks
⏩ 33 skipped benchmarks1


Comparing renovate/major-web (89e9e96) with main (414cfea)2

Open in CodSpeed

Footnotes

  1. 33 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (6d24fd6) during the generation of this report, so 414cfea was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@renovate renovate Bot force-pushed the renovate/major-web branch 9 times, most recently from c6fa7cd to 8a11052 Compare May 3, 2026 07:43
@renovate renovate Bot force-pushed the renovate/major-web branch 2 times, most recently from f3ff4f0 to aafaa48 Compare May 3, 2026 09:22
Aureliolo added a commit that referenced this pull request May 3, 2026
## Summary

Adds a cross-PR file-overlap analysis step to the `/review-dep-pr` skill
so that batch reviews surface merge conflicts upfront and the user can
pick a sequencing strategy before triage.

### What changed

- **New Phase 5 — Cross-PR File Overlap Analysis** (skipped for
single-PR runs):
  - Pulls each PR's changed-file list via `gh pr view --json files`.
- Builds a per-file conflict map and classifies overlaps as **none /
lockfile-only / config / source**.
- Treats `package-lock.json`, `pnpm-lock.yaml`, `uv.lock`, `go.sum`,
`atlas.sum`, etc. as lockfile-only (rebase needed, not a hard blocker).
- Groups PRs into merge **waves** (Wave 1 = parallel-safe, Wave 2+ =
sequential after rebase).
- **Phase 6 (Present Findings)** now leads with a "Batch Overlap
Summary" header and adds a `Files touched / conflicts with` row to each
per-PR card.
- **Phase 7 (User Decision)** opens with a strategy question whenever ≥
2 PRs share files:
  - Wave-based parallel
  - Strict sequential
  - Combine into one PR
  - Defer the conflicting subset
- **Phase 8 (Execute Decisions)** honours the chosen strategy when
sequencing merges (parallel waves, rebase between waves, etc.).
- New rule: multi-PR runs always compute the conflict map; lockfile-only
overlaps are acceptable but expect rebase between merges.

### Why

Without this, the skill would propose merging in parallel any PRs whose
CI is green, then run into surprise conflicts on the second/third merge
— most often on workflow YAMLs and lockfiles. The new phase makes the
conflict surface explicit before the user picks a strategy, and the
strategy choice is then carried through to execution.

### Test plan

Dogfooded against the 8 open Renovate PRs in this repo (#1698-#1705).
Surfaced three conflict clusters (`docker.yml` between
#1698/#1701/#1703, `cli.yml` between #1702/#1703, `web/package.json`
between #1700/#1704) plus the expected lockfile-only overlaps. The
Wave-based strategy successfully merged 5 PRs sequentially with
`--squash --admin` and the lockfile PR (#1705) was rebased via Renovate.

### Review coverage

`/pre-pr-review quick` — docs-only change to a `.claude/` skill file, no
code/agents required. Pre-commit hooks passed (trailing whitespace, EOF,
secrets, em-dashes).
@renovate renovate Bot force-pushed the renovate/major-web branch 3 times, most recently from 3413f91 to 8f3cfca Compare May 3, 2026 10:16
@renovate renovate Bot force-pushed the renovate/major-web branch from 8f3cfca to 650600c Compare May 3, 2026 10:35
Aureliolo added 3 commits May 3, 2026 12:36
The lighthouse.yml site filter watches web/package.json and
web/package-lock.json so a toolchain-only LHCI bump revalidates the
marketing-site Lighthouse score. pages-preview.yml did not mirror those
paths, so a web-only Renovate PR would trigger lighthouse-site but never
trigger a preview deploy for the new commit. lighthouse-site then sat
in its 5-minute wait loop polling for a banner SHA that was never
deployed.

Mirror the two paths in pages-preview.yml so every PR that the
lighthouse-site filter accepts also gets a fresh preview to score
against.
Switch web/eslint.config.js from recommended-typescript to
recommended-type-checked (requires parserOptions.projectService for
the type-aware rules to read inferred types). Add error-level opt-ins
beyond the preset: web-api-no-leaked-fetch (detect fetch in effects
without AbortController cleanup), no-leaked-conditional-rendering
(catch the bug where a falsy 0 renders verbatim, type-aware), and
globals (restrict window / document / localStorage in render bodies).

Static-components fixes: extract ActivityEventIcon and CatalogEntryIcon
as wrapper components doing the lookup internally via createElement.
ActivityEventIcon lives in its own file so react-refresh stays happy
alongside the utility exports in agents.ts. The risk-icon case keeps
the const-Record lookup with a per-line disable since the rule cannot
statically prove map identity stability.

DepartmentEditDrawer: drop the now-unused
eslint-disable set-state-in-effect block (v5 heuristic no longer
flags the prop-sync pattern in that effect).
The new opt-in eslint-react v5 rules surfaced 14 leaked-conditional
errors, 2 globals violations, and 2 kicker-state warnings.
Fixes:

- {prop && jsx} where prop is ReactNode | undefined leaks 0 / empty
  string verbatim. Replace with { prop != null && prop !== false &&
  jsx } across error-banner, input-field, keyboard-shortcut-hint,
  list-header, search-filter-sort, NamespaceSection, and
  SettingsHealthSection. error-banner s onRetry || action compound
  becomes Boolean(onRetry ?? action) and the inner action check uses
  an explicit !== undefined guard.

- AppLayout: hoist the window.location.href and
  window.dispatchEvent calls out of the useMemo action callbacks
  into named useCallback handlers (navigateToDocs,
  openNotificationDrawer) so the globals rule sees them as
  event-handler bound.

- NodeContextMenu: replace direct window.innerWidth /
  window.innerHeight reads inside useMemo with a new useViewportSize
  hook backed by useSyncExternalStore over the resize event. Also
  makes the bounded-position calc reactive to viewport changes.

- VersionHistorySection: drop the reloadNonce useState that was only
  consumed in the effect deps array (no-unused-state). Both the
  initial load and the refresh path now route through a useCallback
  loadHistory helper, with the existing requestEpochRef gating
  stale completions.

- CeremonyPolicyPage: surface isDirty in JSX as a Save-button gate
  and an Unsaved changes affordance so the rule sees a real
  consumer. Save now requires isDirty in addition to the existing
  parse-error and saving guards.

CLAUDE.md updates document the wrapper-icon pattern, the
useViewportSize hook, and the v5 preset / explicit opt-in choices.
@renovate
Copy link
Copy Markdown
Contributor Author

renovate Bot commented May 3, 2026

Edited/Blocked Notification

Renovate will not automatically rebase this PR, because it does not recognize the last commit author and assumes somebody else may have edited the PR.

You can manually request rebase by checking the rebase/retry box above.

⚠️ Warning: custom changes will be lost.

@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 3, 2026 10:38 — with GitHub Actions Inactive
@Aureliolo
Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0ec70319-05c4-43bd-b6d6-8a54ddd296cd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)

Walkthrough

This PR refactors icon-handling and viewport-sizing patterns across the web codebase. Icon factory helpers like getCatalogEntryIcon() and getActivityEventIcon() are replaced with CatalogEntryIcon and ActivityEventIcon wrapper components that perform lookups inside render logic. A new useViewportSize() hook using useSyncExternalStore is introduced for reactive viewport dimension reads. Multiple UI components refactor render conditions from truthiness checks to nullish-aware guards (e.g., != null && !== false) to better handle falsy-but-valid React node values. ESLint configuration updates enforce these patterns via the recommended-type-checked preset and three new type-aware rules. Dependencies are upgraded and documentation guidelines updated accordingly.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.82% which is insufficient. The required threshold is 40.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the main change: updating @eslint-react/eslint-plugin dependency from v4 to v5, which is the primary driver for all modifications in the changeset.
Description check ✅ Passed The PR description is directly related to the changeset, providing detailed release notes, migration guidance, breaking changes, and configuration context for the @eslint-react/eslint-plugin v5 upgrade.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/src/components/ui/input-field.tsx (1)

154-157: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Note: buildInputClasses padding flags still use !!leadingIcon / !!trailingElement.

The render guards on lines 174 and 198 were tightened to != null && !== false, but buildInputClasses on lines 156–157 still derives hasLeadingIcon / hasTrailingElement via !!. For the theoretical case where leadingIcon is a falsy-but-non-null value (e.g. 0), the icon <span> would render without the compensating pl-8 padding, overlapping the text. In practice icon props are always React elements so there's no real risk, but aligning the flag derivation would keep the logic internally consistent:

🔧 Optional consistency fix
  const inputClasses = buildInputClasses({
    hasError,
-   hasLeadingIcon: !!leadingIcon,
-   hasTrailingElement: !!trailingElement,
+   hasLeadingIcon: leadingIcon != null && leadingIcon !== false,
+   hasTrailingElement: trailingElement != null && trailingElement !== false,
    className,
  })

Also applies to: 174-181, 198-202

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/ui/input-field.tsx` around lines 154 - 157, The code uses
!!leadingIcon / !!trailingElement when passing hasLeadingIcon/hasTrailingElement
to buildInputClasses, which is inconsistent with the stricter render guards
(leadingIcon != null && leadingIcon !== false); update the flag derivation so
both the buildInputClasses call and any other uses (hasLeadingIcon,
hasTrailingElement, and places that check leadingIcon/trailingElement) use the
same explicit check: treat a value as present only when (leadingIcon != null &&
leadingIcon !== false) and likewise for trailingElement, then pass those boolean
results into buildInputClasses and use them for padding/spacing decisions
(ensure you update all occurrences referencing
hasLeadingIcon/hasTrailingElement).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/src/components/layout/AppLayout.tsx`:
- Around line 129-134: Replace the global CustomEvent call in
openNotificationDrawer with a direct state update: locate openNotificationDrawer
in AppLayout.tsx and change its body from window.dispatchEvent(new
CustomEvent('open-notification-drawer')) to calling the state setter
setNotificationDrawerOpen(true) (the same setter used in the component's
useEffect listener); if other components like Sidebar.tsx currently rely on the
window event, update them to call the same setter (or lift/shared state/context)
so the global event and CustomEvent usage can be removed for consistency.

In `@web/src/components/version-rollback/VersionHistorySection.tsx`:
- Around line 103-108: The component's requestEpochRef isn't advanced on
unmount, so in-flight promises from client.list() can still call
setItems/setError/setLoading after unmount; add an unmount cleanup that
increments requestEpochRef.current (the same epoch-bump mechanism used for
refresh/client-change) inside the useEffect that sets up requestEpochRef (or the
effect around loadHistory/handleLoadMore) so any settled loadHistory or
handleLoadMore results are ignored when the component unmounts; update any
related logic in loadHistory and handleLoadMore to rely on that epoch check to
discard results from client.list().

In `@web/src/hooks/useViewportSize.ts`:
- Around line 1-46: Update the module comment to clarify that readSnapshot()
returns the real window.innerWidth/innerHeight on the first client render
(CSR/Vite) and that the { width: 0, height: 0 } SSR_SNAPSHOT is only used during
server-side rendering or when window is undefined; reference the existing
module-level helpers (readSnapshot, subscribe, SSR_SNAPSHOT, cachedSnapshot, and
useViewportSize) and replace the misleading "before subscription / before
resize" phrasing with a concise statement that the zero snapshot is the SSR
default while the browser snapshot reflects real dimensions on the initial
render.

In `@web/src/pages/approvals/ApprovalRiskGroupSection.tsx`:
- Around line 32-35: Refactor the getRiskLevelIcon factory into a wrapper
component named RiskLevelIcon and use it in ApprovalRiskGroupSection: create a
new file exporting function RiskLevelIcon({ riskLevel }) that performs the const
Record lookup and returns the icon via React.createElement (preserving stable
identity), replace the getRiskLevelIcon(...) call in ApprovalRiskGroupSection
with <RiskLevelIcon riskLevel={riskLevel} />, and follow the existing patterns
used by ActivityEventIcon and catalog icon components; alternatively, if you
intend to keep the getter, add a short file-level comment in
ApprovalRiskGroupSection explaining why the getRiskLevelIcon usage is an
intentional exception to the rule.

In `@web/src/utils/activity-event-icon.tsx`:
- Around line 20-34: The ACTIVITY_ICON_MAP and FALLBACK_ICON in
activity-event-icon.tsx are duplicated from agents.ts; remove the local
ACTIVITY_ICON_MAP and FALLBACK_ICON definitions and update ActivityEventIcon to
delegate to the existing getActivityEventIcon function exported from
web/src/utils/agents.ts (import it if not present), so the component uses
getActivityEventIcon(event.type) for lookup/fallback instead of maintaining its
own map.

---

Outside diff comments:
In `@web/src/components/ui/input-field.tsx`:
- Around line 154-157: The code uses !!leadingIcon / !!trailingElement when
passing hasLeadingIcon/hasTrailingElement to buildInputClasses, which is
inconsistent with the stricter render guards (leadingIcon != null && leadingIcon
!== false); update the flag derivation so both the buildInputClasses call and
any other uses (hasLeadingIcon, hasTrailingElement, and places that check
leadingIcon/trailingElement) use the same explicit check: treat a value as
present only when (leadingIcon != null && leadingIcon !== false) and likewise
for trailingElement, then pass those boolean results into buildInputClasses and
use them for padding/spacing decisions (ensure you update all occurrences
referencing hasLeadingIcon/hasTrailingElement).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3e9b0475-251f-4cb3-a620-819e0534b5e2

📥 Commits

Reviewing files that changed from the base of the PR and between 6d24fd6 and 177f0ec.

⛔ Files ignored due to path filters (1)
  • web/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (24)
  • .github/workflows/pages-preview.yml
  • web/CLAUDE.md
  • web/eslint.config.js
  • web/package.json
  • web/src/components/layout/AppLayout.tsx
  • web/src/components/ui/error-banner.tsx
  • web/src/components/ui/input-field.tsx
  • web/src/components/ui/keyboard-shortcut-hint.tsx
  • web/src/components/ui/list-header.tsx
  • web/src/components/ui/search-filter-sort.tsx
  • web/src/components/version-rollback/VersionHistorySection.tsx
  • web/src/hooks/useViewportSize.ts
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/approvals/ApprovalRiskGroupSection.tsx
  • web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx
  • web/src/pages/mcp-catalog/CatalogEntryCard.tsx
  • web/src/pages/mcp-catalog/catalog-icons.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/settings/NamespaceSection.tsx
  • web/src/pages/settings/SettingsHealthSection.tsx
  • web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx
  • web/src/utils/activity-event-icon.tsx
  • web/src/utils/agents.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Dashboard Test
🧰 Additional context used
📓 Path-based instructions (6)
web/src/**/*.{tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

web/src/**/*.{tsx,ts}: Reuse components from web/src/components/ui/ before creating new ones (mandatory design system enforcement)
Never hardcode hex colors, font-family, pixel spacing, Motion transitions, or BCP 47 locale strings; use design tokens, @/lib/motion presets, and helpers in @/utils/format
Locale: never hardcode BCP 47 tags or call bare .toLocaleString() / .toLocaleDateString() / .toLocaleTimeString(); use helpers in @/utils/format that read getLocale() from @/utils/locale

Files:

  • web/src/pages/mcp-catalog/CatalogEntryCard.tsx
  • web/src/pages/settings/NamespaceSection.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/hooks/useViewportSize.ts
  • web/src/components/ui/search-filter-sort.tsx
  • web/src/pages/settings/SettingsHealthSection.tsx
  • web/src/pages/approvals/ApprovalRiskGroupSection.tsx
  • web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx
  • web/src/pages/mcp-catalog/catalog-icons.tsx
  • web/src/components/ui/input-field.tsx
  • web/src/components/layout/AppLayout.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/utils/activity-event-icon.tsx
  • web/src/components/version-rollback/VersionHistorySection.tsx
  • web/src/components/ui/keyboard-shortcut-hint.tsx
  • web/src/components/ui/list-header.tsx
  • web/src/utils/agents.ts
  • web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx
  • web/src/components/ui/error-banner.tsx
{src,web/src}/**/*.{py,tsx,ts}

📄 CodeRabbit inference engine (CLAUDE.md)

{src,web/src}/**/*.{py,tsx,ts}: Currency: never hardcode ISO 4217 codes; backend use DEFAULT_CURRENCY from synthorg.budget.currency or runtime budget.currency setting; frontend use DEFAULT_CURRENCY from @/utils/currencies or useSettingsStore().currency
Never use _usd suffix on money fields; the type carries money semantics; the value is in the operator's configured currency
Store UTC datetimes; render via Intl without passing timeZone (browser tz wins)
Always format date/number via Intl; no hand-rolled templates
Use metric units only; International / British English UI default (colour, behaviour, organise, centred, analyse, cancelled); document deviations

Files:

  • web/src/pages/mcp-catalog/CatalogEntryCard.tsx
  • web/src/pages/settings/NamespaceSection.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/hooks/useViewportSize.ts
  • web/src/components/ui/search-filter-sort.tsx
  • web/src/pages/settings/SettingsHealthSection.tsx
  • web/src/pages/approvals/ApprovalRiskGroupSection.tsx
  • web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx
  • web/src/pages/mcp-catalog/catalog-icons.tsx
  • web/src/components/ui/input-field.tsx
  • web/src/components/layout/AppLayout.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/utils/activity-event-icon.tsx
  • web/src/components/version-rollback/VersionHistorySection.tsx
  • web/src/components/ui/keyboard-shortcut-hint.tsx
  • web/src/components/ui/list-header.tsx
  • web/src/utils/agents.ts
  • web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx
  • web/src/components/ui/error-banner.tsx
web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

Always use createLogger from @/lib/logger; never use bare console.warn, console.error, or console.debug in application code (exception: logger.ts itself may use bare console methods)

Use logger variable name log consistently (e.g., const log = createLogger('module-name'))

Pass dynamic/untrusted values to logger as separate arguments (not interpolated into message strings) so they go through sanitizeArg

Wrap attacker-controlled fields inside structured objects in sanitizeForLog() before embedding in logs

Callers MUST NOT wrap store mutation calls in try/catch; the store owns the error UX (error handling is the responsibility of the store, not the caller)

Any new caller of health/readiness endpoints must explicitly handle the 503 unavailable path

Keep the async-leak ceiling from exceeding the documented MAX_ASYNC_LEAKS constant (currently 90); raise the ceiling only with documented per-PR justification

Use <StatusBadge> component (defaults to role="img" with aria-label; set decorative for adjacent-labeled, announce for live WebSocket updates) instead of creating status indicator dots inline

Use <MetricCard>, <Sparkline>, <ProgressGauge>, and <TokenUsageBar> components instead of creating KPI displays inline

Use <SectionCard> (titled wrapper with icon and action slot), <AgentCard>, and <DeptHealthBar> for domain-specific cards instead of creating them inline

Use form field components (<InputField>, <SelectField>, <SliderField>, <ToggleField>, <SegmentedControl>, <TagInput>, <SearchInput>) instead of creating form fields inline

Use <Drawer width="compact|narrow|default|wide"> (Base UI) for slide-in panels; do NOT add inline w-[40vw] overrides

Use <Skeleton> family, <EmptyState>, <ErrorBoundary>, <ErrorBanner>, and <ProgressIndicator> for loading/empty/error states instead of creating them inline

Use useEmptyStateProps({ filteredCount, totalCount, filterActive, empty, filtered }) from ...

Files:

  • web/src/pages/mcp-catalog/CatalogEntryCard.tsx
  • web/src/pages/settings/NamespaceSection.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/hooks/useViewportSize.ts
  • web/src/components/ui/search-filter-sort.tsx
  • web/src/pages/settings/SettingsHealthSection.tsx
  • web/src/pages/approvals/ApprovalRiskGroupSection.tsx
  • web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx
  • web/src/pages/mcp-catalog/catalog-icons.tsx
  • web/src/components/ui/input-field.tsx
  • web/src/components/layout/AppLayout.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/utils/activity-event-icon.tsx
  • web/src/components/version-rollback/VersionHistorySection.tsx
  • web/src/components/ui/keyboard-shortcut-hint.tsx
  • web/src/components/ui/list-header.tsx
  • web/src/utils/agents.ts
  • web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx
  • web/src/components/ui/error-banner.tsx
web/**/pages/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

List page root container should use space-y-section-gap (the majority pattern; flex flex-col gap-section-gap is equivalent but discouraged)

<ErrorBanner> must land immediately after <ListHeader>, before any filter/pagination row

Pages with a one-line mission statement must pass it via <ListHeader description="..." />

Use Kanban grouping for status-flow domains where each row's column conveys lifecycle phase (Tasks, Requests); use a flat scrollable list for queues without explicit phase semantics (Escalations, Approvals)

Use <ListHeader>, <SearchFilterSort>, <Pagination>, <BulkActionBar>, <MetadataGrid>, and <Breadcrumbs> list-page primitives instead of creating them inline

Files:

  • web/src/pages/mcp-catalog/CatalogEntryCard.tsx
  • web/src/pages/settings/NamespaceSection.tsx
  • web/src/pages/agents/ActivityLogItem.tsx
  • web/src/pages/org/NodeContextMenu.tsx
  • web/src/pages/settings/SettingsHealthSection.tsx
  • web/src/pages/approvals/ApprovalRiskGroupSection.tsx
  • web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx
  • web/src/pages/mcp-catalog/catalog-icons.tsx
  • web/src/pages/org-edit/DepartmentEditDrawer.tsx
  • web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx
web/**/components/ui/**/*.{ts,tsx}

📄 CodeRabbit inference engine (web/CLAUDE.md)

Always reuse existing components from web/src/components/ui/ before creating new ones

Never hardcode hex colors, font-family declarations, pixel spacing, Motion transition durations, BCP 47 locale literals ('en-US'), or currency symbols/codes; use design tokens, @/lib/motion presets, helpers in @/utils/format, and DEFAULT_CURRENCY from @/utils/currencies

Component Props interface name must be <ComponentName>Props and must be exported from the same file (e.g., AgentCardProps in agent-card.tsx)

Base UI primitives are imported directly from @base-ui/react/<subpath> and use the native render prop for polymorphism; the local <Slot> helper is reserved only for <Button asChild>

Files:

  • web/src/components/ui/search-filter-sort.tsx
  • web/src/components/ui/input-field.tsx
  • web/src/components/ui/keyboard-shortcut-hint.tsx
  • web/src/components/ui/list-header.tsx
  • web/src/components/ui/error-banner.tsx
web/eslint.config.js

📄 CodeRabbit inference engine (web/CLAUDE.md)

Configure @eslint-react/eslint-plugin v5+ via the recommended-type-checked preset with parserOptions.projectService: true and enable explicit error-level rules: @eslint-react/web-api-no-leaked-fetch, @eslint-react/no-leaked-conditional-rendering, @eslint-react/globals

Files:

  • web/eslint.config.js
🔇 Additional comments (20)
web/src/pages/settings/ceremony-policy/CeremonyPolicyPage.tsx (1)

421-432: LGTM — save-row logic is correct.

The isDirty && !saving guard uses two strict booleans, so the short-circuit never produces a truthy non-boolean (no 0-leak risk). The extended disabled expression correctly encodes all four blocking conditions:

Condition Effect
!isDirty No pending edits — nothing to save
saving In-flight save — prevent double submit
configParseError Corrupt stored JSON — cannot safely overwrite
overridesParseError Same, for the overrides key

setIsDirty(false) after a successful Promise.all and preserving isDirty = true on catch are both the right choices, so the button correctly re-enables on retry.

web/src/components/layout/AppLayout.tsx (1)

148-153: LGTM.

Both callbacks are stable (memoized with []), so adding them to the useMemo dependency array is correct and introduces no spurious recomputation of globalCommands. The navigate reference from React Router 7 is also stable, keeping the existing dependency correct.

web/src/pages/settings/SettingsHealthSection.tsx (1)

84-86: LGTM. The != null && !== false guard aligns with the project-mandated pattern for ReactNode slot props.

web/src/pages/org-edit/DepartmentEditDrawer.tsx (1)

57-70: LGTM. Removing the now-stale eslint-disable/eslint-enable pair is correct — retaining them would trigger unused-disable-directive warnings under --max-warnings 0.

web/src/components/ui/keyboard-shortcut-hint.tsx (1)

65-67: LGTM — the guard correctly prevents '' from rendering a label span. Minor note: the project convention for ReactNode slots is != null && !== false (see CLAUDE.md line 112), which additionally suppresses null and false. label={null} or label={false} with the current check renders an empty <span>, but since React renders nothing for those values inside the element the visual impact is nil.

web/CLAUDE.md (1)

104-115: LGTM. The new icon-helper, viewport-size, and ESLint rule documentation is accurate and actionable.

web/src/components/ui/search-filter-sort.tsx (1)

37-48: LGTM. All four slot guards uniformly follow the != null && !== false pattern mandated for ReactNode props.

web/src/components/ui/list-header.tsx (1)

56-62: LGTM. Both action slot guards correctly follow the != null && !== false pattern.

web/src/pages/settings/NamespaceSection.tsx (1)

178-198: Correct nullish-aware conditional rendering for footerAction.

Both render branches now use footerAction != null && footerAction !== false, which matches the canonical ReactNode | undefined guard pattern and satisfies the newly enforced @eslint-react/no-leaked-conditional-rendering rule without suppressing valid falsy nodes like 0.

web/src/components/ui/error-banner.tsx (1)

195-231: Cluster guard and action rendering are correct.

Boolean(onRetry ?? action) at line 195 correctly prevents the {0 && <div>} leak pattern (satisfies @eslint-react/no-leaked-conditional-rendering) while still rendering the cluster whenever a real action or retry handler is present. The action !== undefined narrowing at line 227 permits null through, but null renders as nothing so this is harmless in practice.

web/src/pages/org/NodeContextMenu.tsx (1)

122-126: Viewport clamping correctly migrated to useViewportSize().

The useMemo dependency array includes viewport.width and viewport.height from the reactive hook, so position clamping will recompute on every resize. margin (8) and menuWidth (180) are render-scope literal constants and their omission from the deps array is safe — no runtime divergence is possible since they never change.

web/src/pages/mcp-catalog/catalog-icons.tsx (1)

32-45: Correct wrapper component pattern per coding guidelines.

ENTRY_ICONS is intentionally non-exported so the file's only runtime export is CatalogEntryIcon. The createElement(ENTRY_ICONS[entryId] ?? Package, rest) approach correctly keeps the icon lookup inside the component (satisfying react-x/static-components) without creating a new component definition on every render.

web/src/pages/mcp-catalog/CatalogDetailDrawer.tsx (1)

42-42: Clean icon usage update.

web/src/pages/mcp-catalog/CatalogEntryCard.tsx (1)

49-49: Clean icon usage update.

web/eslint.config.js (2)

15-31: Preset and type-aware parser options are correct.

recommended-type-checked is confirmed as a valid preset: "same as the recommended-typescript preset but enables additional rules that require type information." The separate files: ['**/*.ts', '**/*.tsx'] block for projectService: true (lines 17-31) works correctly in ESLint flat config — all matching blocks are merged before rules run, so type-aware rules from the preset have the project service available when processing TS/TSX files.


69-83: All three new rule names are valid in v5.7.1.

From the official ESLint React docs and changelog:

  • globals is listed in the X Rules group, accessible as @eslint-react/globals
  • react-web-api/no-leaked-fetch is a new rule in v5 — exposed as @eslint-react/web-api-no-leaked-fetch
  • @eslint-react/no-leaked-conditional-rendering is a confirmed X rule ✓
.github/workflows/pages-preview.yml (1)

19-26: LGTM — The added path filters and the accompanying comment are clear and well-justified. Mirroring the lighthouse.yml site filter prevents the Lighthouse preview audit from timing out on toolchain-only bumps like this one.

web/src/utils/agents.ts (1)

286-290: LGTM — Comment accurately documents the module split and its rationale (react-refresh/only-export-components). No runtime changes.

web/src/pages/agents/ActivityLogItem.tsx (1)

1-16: LGTM — Correctly replaces the inline getActivityEventIcon() call with the <ActivityEventIcon /> wrapper, satisfying the react-x/static-components rule while preserving identical render output.

web/package.json (1)

69-69: @eslint-react/eslint-plugin@5.7.1 peer dependencies are compatible with the current toolchain.

The package requires eslint@^10.2.1 and typescript@*, both satisfied by eslint@10.3.0 and typescript@6.0.3 in the stack. No overrides needed.

Comment on lines +129 to +134
const navigateToDocs = useCallback(() => {
window.location.href = ROUTES.DOCUMENTATION
}, [])
const openNotificationDrawer = useCallback(() => {
window.dispatchEvent(new CustomEvent('open-notification-drawer'))
}, [])
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.

🧹 Nitpick | 🔵 Trivial | 💤 Low value

openNotificationDrawer could bypass the event bus and call state directly.

The callback dispatches open-notification-drawer on window and relies on the useEffect listener (line 88) in the same component to call setNotificationDrawerOpen(true). This is a self-message via a global event. It is functionally correct (custom events are synchronous), and intentionally mirrors the pattern in Sidebar.tsx (window.dispatchEvent(new CustomEvent('open-notification-drawer'))), so the indirection is justified for cross-component consistency.

If that cross-component consistency argument ever becomes moot (e.g., the Sidebar is refactored to call the state setter directly), consider collapsing this to:

♻️ Simpler alternative (no window access needed)
-  const openNotificationDrawer = useCallback(() => {
-    window.dispatchEvent(new CustomEvent('open-notification-drawer'))
-  }, [])
+  const openNotificationDrawer = useCallback(() => {
+    setNotificationDrawerOpen(true)
+  }, [])
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const navigateToDocs = useCallback(() => {
window.location.href = ROUTES.DOCUMENTATION
}, [])
const openNotificationDrawer = useCallback(() => {
window.dispatchEvent(new CustomEvent('open-notification-drawer'))
}, [])
const navigateToDocs = useCallback(() => {
window.location.href = ROUTES.DOCUMENTATION
}, [])
const openNotificationDrawer = useCallback(() => {
setNotificationDrawerOpen(true)
}, [])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/layout/AppLayout.tsx` around lines 129 - 134, Replace the
global CustomEvent call in openNotificationDrawer with a direct state update:
locate openNotificationDrawer in AppLayout.tsx and change its body from
window.dispatchEvent(new CustomEvent('open-notification-drawer')) to calling the
state setter setNotificationDrawerOpen(true) (the same setter used in the
component's useEffect listener); if other components like Sidebar.tsx currently
rely on the window event, update them to call the same setter (or lift/shared
state/context) so the global event and CustomEvent usage can be removed for
consistency.

Comment thread web/src/components/version-rollback/VersionHistorySection.tsx
Comment thread web/src/hooks/useViewportSize.ts
Comment thread web/src/pages/approvals/ApprovalRiskGroupSection.tsx Outdated
Comment thread web/src/utils/activity-event-icon.tsx Outdated
Implements 5 of the 6 actionable items from the CodeRabbit review on
PR #1704. The skipped item is the `openNotificationDrawer` direct-call
suggestion (`AppLayout.tsx:129-134`), which the reviewer themselves
classified as Trivial / Low-value and acknowledged as intentional
cross-component-bus consistency with `Sidebar.tsx`.

Changes:

- `VersionHistorySection.tsx`: advance `requestEpochRef` on unmount so
  any in-flight `client.list()` promise that settles after the
  component is gone discards its result instead of calling
  `setItems` / `setError` / `setLoading` against an unmounted tree.
  React 19 silently swallows post-unmount setState, but the explicit
  cleanup keeps the epoch-based cancellation contract honest.

- `useViewportSize.ts`: clarify the module comment. In a browser
  context `readSnapshot()` is called synchronously during the first
  render and returns the real `window.inner*` dimensions immediately;
  the `{ width: 0, height: 0 }` SSR_SNAPSHOT is only the
  server-snapshot argument to `useSyncExternalStore`. Replaces the
  misleading "before subscription / before resize" framing.

- `ApprovalRiskGroupSection.tsx`: replace the terse per-line
  `eslint-disable` justification with a longer explanation that
  documents why this stays a `getRiskLevelIcon` getter rather than
  the canonical wrapper-component pattern: `SectionCard.icon`
  expects a `LucideIcon` component reference, not a JSX node, so a
  parameterised wrapper like `<RiskLevelIcon riskLevel=... />` cannot
  be plugged in. The const-Record lookup returns a stable reference
  per level and the rule does not fire because the result is consumed
  as a prop, not as `<Icon />` JSX in this body.

- `activity-event-icon.tsx`: drop the duplicated `ACTIVITY_ICON_MAP` /
  `FALLBACK_ICON` declarations. Delegate to the existing
  `getActivityEventIcon()` exported from `@/utils/agents` so the
  Record stays a single source of truth.

- `input-field.tsx`: align the `hasLeadingIcon` / `hasTrailingElement`
  flags passed to `buildInputClasses` with the stricter
  `!= null && !== false` render guards on the icon `<span>`s, so the
  padding flag and JSX presence agree on every legal `ReactNode`
  value (including `0`, `''`, `false`).
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 3, 2026 11:03 — with GitHub Actions Inactive
@Aureliolo Aureliolo merged commit 1cb1294 into main May 3, 2026
76 checks passed
@Aureliolo Aureliolo deleted the renovate/major-web branch May 3, 2026 11:16
@Aureliolo Aureliolo temporarily deployed to cloudflare-preview May 3, 2026 11:17 — with GitHub Actions Inactive
Aureliolo pushed a commit that referenced this pull request May 3, 2026
<!-- HIGHLIGHTS_START -->
## Highlights

> _AI-generated summary (model: `openai/gpt-4.1-mini` via GitHub
Models). Commit-based changelog below._

### What you'll notice
- Frontend and UX polishing improves user interface responsiveness and
visual consistency.
- API hygiene and validation enhancements provide smoother and more
reliable interactions.

### What's new
- Introduced typed-boundary helpers enabling better type safety and
parse_typed workflows.
- Added codebase-audit skill prompt tuning for improved project
auditing.

### Under the hood
- Eliminated flaky tests caused by module-level state for more stable
test outcomes.
- Unified image tag management under CLI and Renovate for consistent
dependency updates.
- Added cross-PR file-overlap analysis to the review dependency pull
request skill.
- Updated multiple dependencies including Python, Web, CLI, and
container libraries.
- Improved CI tooling and lock file maintenance for better build
reliability.

<!-- HIGHLIGHTS_END -->

:robot: I have created a release *beep* *boop*
---


##
[0.7.8](v0.7.7...v0.7.8)
(2026-05-03)


### Features

* **api:** typed-boundary helper + codebase-audit skill prompt tuning
([#1712](#1712))
([40ee65b](40ee65b))
* **boundary:** RFC
[#1711](#1711) Phases 2 + 3
— typed boundaries via parse_typed
([#1720](#1720))
([7b9f409](7b9f409))


### Bug Fixes

* **api:** audit cleanup B -- API hygiene & validation
([#1719](#1719))
([3d790d9](3d790d9))
* audit cleanup C - persistence, concurrency & data integrity
([#1708](#1708))
([#1717](#1717))
([bcce097](bcce097))
* **test:** exterminate xdist-flaky tests with module-level state
([#1713](#1713))
([#1721](#1721))
([8d258dd](8d258dd))
* **web:** audit cleanup E -- frontend & UX polish
([#1710](#1710))
([#1718](#1718))
([3a3591a](3a3591a))


### Refactoring

* **cli:** single source of truth for DHI image tags + Renovate manager
([#1723](#1723))
([57980a2](57980a2))


### Documentation

* audit cleanup D -- public-facing & docs sync
([#1709](#1709))
([#1715](#1715))
([ade03b7](ade03b7))


### Tests

* **engine:** make TestDrainTimeout deterministic + preserve subclass
type in [@Ontology](https://github.com/ontology)_entity
([#1729](#1729))
([b00fb05](b00fb05))


### CI/CD

* Update CI tool dependencies
([#1703](#1703))
([355a9ff](355a9ff))


### Maintenance

* add cross-PR file-overlap analysis to review-dep-pr skill
([#1722](#1722))
([3861d8a](3861d8a))
* **ci:** unify apko-version under workflow env so Renovate manages it
everywhere ([#1724](#1724))
([9c0a7fd](9c0a7fd))
* consolidate DHI image-pin custom regex managers
([#1726](#1726))
([b8b0cba](b8b0cba))
* **deps:** update dependency chainguard-dev/melange to v0.50.4
([#1701](#1701))
([8cbf83a](8cbf83a))
* Lock file maintenance
([#1705](#1705))
([414cfea](414cfea))
* Lock file maintenance
([#1727](#1727))
([5cb1212](5cb1212))
* Update CLI dependencies
([#1702](#1702))
([9fb57b9](9fb57b9))
* Update Container dependencies
([#1698](#1698))
([6d24fd6](6d24fd6))
* Update dependency @eslint-react/eslint-plugin to v5
([#1704](#1704))
([1cb1294](1cb1294))
* Update Python dependencies
([#1699](#1699))
([8e7af3a](8e7af3a))
* Update Python dependencies to v4.15.0
([#1725](#1725))
([69164c8](69164c8))
* Update Web dependencies
([#1700](#1700))
([715300d](715300d))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: synthorg-repo-bot[bot] <279117679+synthorg-repo-bot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file scope:web Vue 3 dashboard type:chore Maintenance, cleanup, dependency updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant