Skip to content

chore(clusters): engine v2 review improvements - #3060

Merged
rmnbrd merged 19 commits into
feat/cluster-engine-v2from
chore/cluster-engine-v2-review-improvements
Oct 5, 2026
Merged

rmnbrd merged 19 commits into
feat/cluster-engine-v2from
chore/cluster-engine-v2-review-improvements

Conversation

@rmnbrd

@rmnbrd rmnbrd commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Improvements from reviewing the Engine v2 branch (origin/staging...HEAD) against every project skill: qovery-console-standards, qovery-ui, react-useeffect, vercel-react-best-practices and web-design-guidelines. Based on feat/cluster-engine-v2 (after #3057), one commit per change.

Bugs

  • Keep edits made while saving: a successful save cleared every local edit, including ones typed while the request was in flight. It now removes only the values it submitted.
  • Redirect once when the Operator connects: the install effect ran again on each parent re-render. With a parent that updates state in onClose, onClose ran 53 times in the test.
  • Item modal dismissed with Escape: the modal's "open" flag stayed set, so unmounting the field later closed an unrelated modal.
  • Focus outline: focus-visible:ring-brand generates no CSS, so the profile sidebar and Operator footer buttons had Tailwind's default blue ring. They now use outline-brand-strong, like the rest of the console.
  • Provider icons in ClusterAvatar: OVH, ORACLE and IBM now map to their *_CLOUD icons for every avatar (breadcrumbs, cards, overview). The profile header uses ClusterAvatar instead of its own mapping.

Performance

  • No debounce on component switches: opening another component no longer waits 300 ms before its preview request, so the skeleton doesn't flash even when the preview is cached. Edits are still debounced.

Consistency

  • Copy:
    • "Qovery Operator" casing everywhere.
    • Loading layers… with an ellipsis.
    • Error text that says what to do next.
    • The search empty states no longer mention filters, which were removed.
    • No trailing period on the tooltip.
  • Sidebar layer icon: the Font Awesome layer-group icon replaces a CSS mask of apps/console/public/assets/sidebar-test/layer.svg. The feature lib no longer depends on an app asset, and the SVG is deleted.
  • Route ids: ProfileOperatorFooter and ClusterOperatorStatus read the route ids with useParams instead of receiving them as props.
  • isHttpStatus: no longer exported publicly from clusters data-access.
  • Console logging: the dev-only API response logs in cluster-profile.tsx are removed; the branch has no console calls left.

Tests

  • Spec for the platform configuration helpers.
  • InputSearch tests use userEvent instead of fireEvent.
  • Unused import removed.

Not included (for discussion)

  • Product or design choices:
    • Label the Operator step's submit "Create cluster" instead of "Continue".
    • Replace the changes bar's hardcoded shadow and button gaps with tokens (they follow Figma today).
    • Revert the green EmptyState variant.
    • Add skeletons to the profile header.
  • Larger changes:
    • Real links for the profile tabs (Cmd-click, copy link).
    • Debounce or defer search URL updates.
    • Prefetch the profile queries in a route loader.
    • Warn before leaving with unsaved changes.
    • Move focus to the heading on each creation step.
    • Live regions for the polling install step.
    • Link input errors with aria-invalid / aria-describedby in shared inputs.
    • Make the password toggle a keyboard-reachable button.
    • Batch the per-card Operator status requests on the clusters list.

Test plan

  • jest: clusters feature (561), shared ui (471), clusters data-access
  • New tests fail without their fix (save, redirect, modal dismissal, debounce, avatar icons)
  • tsc app and libs, ESLint, Prettier
  • yarn build:console

🤖 Generated with Claude Code


Summary by cubic

Applies code review improvements to the Engine v2 cluster profile and creation flows, fixing four bugs and tightening performance, consistency, and test coverage.

Bug fixes

  • Saving no longer clears edits typed while the request was in flight.
  • The Operator connect redirect runs once even if the parent re-renders.
  • Item modals report their mount state explicitly, so dismissing by Escape no longer leaves a stale flag that could close an unrelated modal later, and StrictMode double-mounting is handled.
  • OVH, Oracle, and IBM clusters now show their *_CLOUD icons in all avatars, and the profile header uses ClusterAvatar.

Refactors

  • The edit debounce now applies to profile edits only, so switching components previews immediately.
  • Copy is aligned ("Qovery Operator", Loading layers…, action-oriented errors); the sidebar shows "No layers match your search" only when searching, else "No layers available"; and the layer icon uses the Font Awesome layer-group icon.
  • ProfileOperatorFooter and ClusterOperatorStatus read route ids via useParams, isHttpStatus is no longer publicly exported, and dev-only API response logging is removed.
  • Added tests for the platform configuration helpers and avatar icons, and InputSearch tests now use userEvent.

Written for commit 4734090. Summary will update on new commits.

Review in cubic

rmnbrd and others added 14 commits October 2, 2026 17:21
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 2, 2026 15:22
@nx-cloud

nx-cloud Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 4734090

Command Status Duration Result
nx run console:build --parallel=3 --configurati... ✅ Succeeded 1m 3s View ↗
nx affected --target=test --parallel=3 --config... ✅ Succeeded 2m 54s View ↗
nx affected --target=lint --parallel=3 ✅ Succeeded 2m 40s View ↗
nx-cloud record -- yarn nx format:check ✅ Succeeded 5s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-10-02 16:34:28 UTC

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.

Copilot review overview

🟡 Changes recommended

Component-switch previews can still use stale debounced requests, and the sidebar can show search-specific copy without an active search.

Review effort: Balanced
Findings: 2 Medium severity

Open (2)
What changed in this PR

Improves Engine v2 cluster profile reliability, consistency, performance, and test coverage.

Changes:

  • Preserves edits made during saves and prevents repeated redirects or stale modal state.
  • Standardizes Operator copy, provider icons, focus outlines, route parameters, and empty states.
  • Adds regression coverage and removes obsolete assets/exports.
File Description
input-search.spec.tsx Migrates interactions to userEvent.
self-managed-cluster-creation-flow.tsx Prevents repeated installation redirects.
self-managed-cluster-creation-flow.spec.tsx Tests single redirect behavior.
platform-configuration-utils.spec.ts Adds utility coverage.
profile-operator-footer.tsx Uses route parameters and updated UI copy.
profile-operator-footer.spec.tsx Updates footer tests.
profile-configuration-field.tsx Tracks modal dismissal through unmounting.
profile-array-item-modal.tsx Adds unmount notification support.
cluster-profile.tsx Updates previews, avatar, footer, and empty state.
cluster-profile.spec.tsx Adds save, modal, preview, and copy regressions.
cluster-profile-sidebar.tsx Replaces the layer asset and updates UI states.
cluster-profile-context.tsx Preserves edits made during saves.
cluster-operator-status.tsx Reads identifiers from route parameters.
cluster-operator-status.spec.tsx Updates status tests for route parameters.
cluster-avatar.tsx Maps additional provider icons.
cluster-avatar.spec.tsx Tests provider icon mappings.
cluster-add.tsx Standardizes Operator capitalization.
data-access/​src/​index.ts Removes the internal HTTP helper export.
layer.svg Removes the obsolete sidebar asset.

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

Comment thread libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile-sidebar.tsx Outdated
Comment on lines +344 to +346
const settledPreviewRequests = equal(Object.keys(debouncedPreviewRequests), Object.keys(previewRequests))
? debouncedPreviewRequests
: previewRequests

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 19 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.tsx Outdated
Comment thread libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile-sidebar.tsx Outdated
@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 80.00000% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 51.74%. Comparing base (a7ce69c) to head (4734090).

Files with missing lines Patch % Lines
...rc/lib/cluster-profile/cluster-profile-sidebar.tsx 60.00% 0 Missing and 2 partials ⚠️
...rc/lib/cluster-profile/profile-operator-footer.tsx 0.00% 1 Missing and 1 partial ⚠️
...luster-operator-status/cluster-operator-status.tsx 0.00% 1 Missing ⚠️
...eature/src/lib/cluster-profile/cluster-profile.tsx 80.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@                    Coverage Diff                     @@
##           feat/cluster-engine-v2    #3060      +/-   ##
==========================================================
+ Coverage                   51.60%   51.74%   +0.13%     
==========================================================
  Files                        1408     1329      -79     
  Lines                       31622    29608    -2014     
  Branches                     9371     8995     -376     
==========================================================
- Hits                        16320    15322     -998     
+ Misses                      12700    11838     -862     
+ Partials                     2602     2448     -154     
Flag Coverage Δ
unittests 51.74% <80.00%> (+0.13%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

rmnbrd and others added 4 commits October 2, 2026 17:41
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

@cubic-dev-ai cubic-dev-ai Bot 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.

2 issues found across 6 files (changes from recent commits).

Confidence score: 4/5

  • Re-selecting a component in cluster-profile.tsx within the 300 ms debounce can leave its preview stale instead of requesting the latest values. Restart or refresh the request on re-selection.
  • cluster-profile.spec.tsx does not cover the A→B→A switch within the debounce window, so the stale-preview case can go undetected. Add a test for that sequence.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.spec.tsx">

<violation number="1" location="libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.spec.tsx:433">
P3: These tests only cover the two extreme debounce states (a mock that never settles and one that settles instantly), so the in-window case that motivated the fix — edit in A, switch A→B→A within the 300 ms debounce — is never exercised, as noted in the inline review on cluster-profile.tsx. Neither extreme mock can represent a pending debounce, so a regression in the A→B→A transition would pass both tests. Add a controllable debounce mock (one whose resolution the test triggers explicitly, or jest fake timers) and assert that returning to A before the debounce settles still fires the immediate request and reports the latest local edit once it does.</violation>
</file>

<file name="libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.tsx">

<violation number="1" location="libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.tsx:330">
P2: Re-selecting a component whose latest edit is still inside the 300 ms debounce keeps showing the stale preview and does not restart its request with the current values. The request payload for each component is now built from `debouncedEdits`, so re-entering component A after editing it and switching away (A→B→A within the window) leaves A's query keyed on the pre-edit payload; the fresh request is only emitted when the debounce timer fires, and until then the visible preview and Save gating stay on old data. The removed `settledPreviewRequests` comparison refreshed requests on the selection transition, so this is a regression for the exact A→B→A case called out in the PR discussion. Consider keeping the per-component request payload derived from the latest `edits` once the component is displayed (or restarting its query on selection) while letting the debounce only delay background refreshes for non-displayed components.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

[configuration?.clusterInputs, clusterInputs, resolvedComponents]
)
const edits = useMemo(() => ({ profileValues, clusterInputs }), [clusterInputs, profileValues])
const debouncedEdits = useDebounce(edits, 300)

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.

P2: Re-selecting a component whose latest edit is still inside the 300 ms debounce keeps showing the stale preview and does not restart its request with the current values. The request payload for each component is now built from debouncedEdits, so re-entering component A after editing it and switching away (A→B→A within the window) leaves A's query keyed on the pre-edit payload; the fresh request is only emitted when the debounce timer fires, and until then the visible preview and Save gating stay on old data. The removed settledPreviewRequests comparison refreshed requests on the selection transition, so this is a regression for the exact A→B→A case called out in the PR discussion. Consider keeping the per-component request payload derived from the latest edits once the component is displayed (or restarting its query on selection) while letting the debounce only delay background refreshes for non-displayed components.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.tsx, line 330:

<comment>Re-selecting a component whose latest edit is still inside the 300 ms debounce keeps showing the stale preview and does not restart its request with the current values. The request payload for each component is now built from `debouncedEdits`, so re-entering component A after editing it and switching away (A→B→A within the window) leaves A's query keyed on the pre-edit payload; the fresh request is only emitted when the debounce timer fires, and until then the visible preview and Save gating stay on old data. The removed `settledPreviewRequests` comparison refreshed requests on the selection transition, so this is a regression for the exact A→B→A case called out in the PR discussion. Consider keeping the per-component request payload derived from the latest `edits` once the component is displayed (or restarting its query on selection) while letting the debounce only delay background refreshes for non-displayed components.</comment>

<file context>
@@ -326,30 +326,36 @@ function ClusterProfileView({
     [configuration?.clusterInputs, clusterInputs, resolvedComponents]
   )
+  const edits = useMemo(() => ({ profileValues, clusterInputs }), [clusterInputs, profileValues])
+  const debouncedEdits = useDebounce(edits, 300)
   const previewRequests = useMemo(
     () =>
</file context>

expect(screen.queryByRole('status', { name: 'Loading configuration' })).not.toBeInTheDocument()
})

describe('edits debounce across component switches', () => {

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.

P3: These tests only cover the two extreme debounce states (a mock that never settles and one that settles instantly), so the in-window case that motivated the fix — edit in A, switch A→B→A within the 300 ms debounce — is never exercised, as noted in the inline review on cluster-profile.tsx. Neither extreme mock can represent a pending debounce, so a regression in the A→B→A transition would pass both tests. Add a controllable debounce mock (one whose resolution the test triggers explicitly, or jest fake timers) and assert that returning to A before the debounce settles still fires the immediate request and reports the latest local edit once it does.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At libs/domains/clusters/feature/src/lib/cluster-profile/cluster-profile.spec.tsx, line 433:

<comment>These tests only cover the two extreme debounce states (a mock that never settles and one that settles instantly), so the in-window case that motivated the fix — edit in A, switch A→B→A within the 300 ms debounce — is never exercised, as noted in the inline review on cluster-profile.tsx. Neither extreme mock can represent a pending debounce, so a regression in the A→B→A transition would pass both tests. Add a controllable debounce mock (one whose resolution the test triggers explicitly, or jest fake timers) and assert that returning to A before the debounce settles still fires the immediate request and reports the latest local edit once it does.</comment>

<file context>
@@ -430,6 +430,48 @@ describe('ClusterProfileFeature', () => {
     expect(screen.queryByRole('status', { name: 'Loading configuration' })).not.toBeInTheDocument()
   })
 
+  describe('edits debounce across component switches', () => {
+    function ClusterProfileWithNavigation() {
+      const [componentKey, setComponentKey] = useState<string>()
</file context>

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@rmnbrd
rmnbrd merged commit 0c4f236 into feat/cluster-engine-v2 Oct 5, 2026
10 checks passed
@rmnbrd
rmnbrd deleted the chore/cluster-engine-v2-review-improvements branch October 5, 2026 04:38
rmnbrd added a commit that referenced this pull request Oct 14, 2026
* Add Profile page

* Implement main Profile page UI elements

* fix(clusters): disable unavailable cluster profile controls

- Remove unused cluster actions
- Disable the log infrastructure toggle and update its test

* feat(clusters): support dynamic platform configuration

- Resolve cluster bindings and component configuration previews
- Render API-defined fields and validation states in cluster profiles

* feat(clusters): add the cluster profile layer sidebar

- Add searchable, selectable layer and component navigation with status indicators
- Reuse the shared search input and expose its accessible label

* feat(clusters): arrange profile inputs in compact rows

- Add row layouts with truncated descriptions and tooltips
- Align profile controls and errors consistently

* feat(clusters): show positive empty state for unconfigured components

- Add a positive variant to the shared EmptyState component
- Use it when a cluster profile component needs no configuration

* fix(clusters): constrain profile page to its container

* fix(clusters): match profile skeleton to configuration rows

* chore(clusters): log profile schema responses in development

* fix(clusters): preserve resolved profile fields on refresh

- Show configuration skeletons only until displayed components resolve
- Keep the last resolved fields visible when background refreshes fail

* fix(clusters): match profile tab icons to sidebar

- Reuse the sidebar component icon in profile tabs
- Assert matching icons for Loki and Alloy

* fix(clusters): remove operator footer from profile sidebar

- Add bottom spacing to the profile configuration panel

* feat(clusters): support nested profile configuration fields

- Add and edit array items through validated modals
- Show nested field violations and enforce array limits

* feat(clusters): remove heading

* fix(clusters): use section for profile content region

* feat(clusters): add searchable cluster profile settings

- Persist profile search in the URL and filter matching layers, components, and fields
- Highlight search matches in configuration labels and descriptions

* feat(clusters): save and deploy profile changes

* refactor(clusters): move profile state into context

* fix(shared-ui): order highlight text classes consistently

* fix(clusters): remove profile header surface background

* feat(clusters): add Engine V2 cluster creation flow

* fix(clusters): disable components without configuration

- Skip non-configurable components when opening profile layers or URL selections
- Hide their tabs and explain disabled sidebar items

* fix(clusters): reflect resolved layer statuses in profile

- Disable skipped and Qovery-managed layers using cluster configuration
- Show a status-specific explanation when a layer is disabled

* fix(ui): preserve input defaults and select accessibility

- Omit undefined search defaults from rendered input attributes
- Keep small select aria labels explicit
- Center select chevrons vertically

* fix(clusters): detect Engine v2 clusters for deployment actions

- Use Operator status to identify Engine v2 clusters
- Restrict deployment actions for those clusters

* feat(clusters): show Operator status in cluster profile

* fix(clusters): prevent dismissing install flow

- Keep the creation modal open during Operator installation
- Cover dismissal before and after installation in ClusterAdd specs

* fix(clusters): create self-managed clusters without a template

- Send only edited Operator configuration and allow default platform selection
- Clarify Operator installation guidance and cover template loading

* fix(clusters): block creation when templates fail to load

- Show a retry option when Operator templates cannot be loaded
- Keep cluster creation disabled until templates load successfully

* fix(clusters): remove obsolete requirement status badge

* fix(clusters): use list items for layer sidebar states

* fix(clusters): use navbar links for profile components

- Replace tab buttons with Navbar links
- Update navigation tests for link semantics and keyboard movement

* fix(clusters): prevent leaving flow during cluster creation

* fix(clusters): block saving invalid profile changes

- Disable save actions until component checks pass
- Cover violations, missing inputs, and unresolved checks

* fix(clusters): reset profile state when switching clusters

* feat(clusters): add component routes to cluster profile

* fix(clusters): ignore cached Operator status when disabled

- Gate Engine v2 detection on the feature flag and self-managed cluster type
- Cover disabled, managed, and unattached cluster cases

* fix(clusters): prevent duplicate Operator updates

- Disable the update button while an update is in progress
- Cover version arguments and in-progress behavior with tests

* fix(clusters): remove obsolete update button comment

* fix(clusters): wait for profile feature flag to load

* fix(clusters): expose profile navbar as navigation

* fix(clusters): stop loading when template queries are disabled

- Gate template loading on the query being enabled
- Cover supported, failed, and unsupported cluster states

* fix(clusters): remove gateway API warning indicator

* test(clusters): verify self-managed cluster selection tracking

* fix(clusters): block saving for offscreen invalid components

- Include edited components outside the active section in configuration resolution
- Keep save actions disabled when any edited component has validation errors

* test(clusters): cover Operator update action visibility

* fix(clusters): remove disabled profile controls

* fix(clusters): close item modal when profile unmounts

- Track the array item modal lifecycle and close it on profile unmount
- Cover modal cleanup with a regression test

* fix(clusters): address engine v2 review comments (#3057)

* fix(clusters): wait for the Operator configuration check before creating

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): stop polling clusters without Operator and show status errors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): block incomplete or invalid profile array items

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show the cluster provider and layers on every profile width

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(ui): name and sync profile inputs for assistive tech and navigation

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): mark EKS Anywhere as an access request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(ui): rename the search highlight surface token

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): require resolved Operator inputs before creating

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): ignore paused or outdated Operator checks

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): let a failed Operator check be retried

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): map vendor names to their profile header icons

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): assert the array items added from defaults

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show Operator status errors over the cached status

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(ui): show the clear button for external search values

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(clusters): engine v2 review improvements (#3060)

* fix(clusters): keep profile edits made while saving

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): redirect only once when the Operator connects

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): track the item modal however it is dismissed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(clusters): only debounce profile edits, not component switches

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): use the brand focus outline on profile sidebar buttons

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show OVH, Oracle and IBM icons in cluster avatars

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): use ClusterAvatar in the profile header

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): align Operator and profile search copy

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): use the layer-group icon in the profile sidebar

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): keep the HTTP status helper private to data-access

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(ui): drive InputSearch with userEvent

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): read route ids in the Operator status components

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): cover the platform configuration helpers

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): drop an unused testing import

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* UI tweak

* perf(clusters): debounce profile edits instead of preview requests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): only mention the search when the sidebar has one

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): report the item modal mount state explicitly

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(clusters): remove profile API response logging

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): address remaining Cubic and Copilot review feedback on engine v2 (#3063)

* fix(clusters): do not select a disabled layer when none can be opened

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): do not open non-configurable components matched by search

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): keep polling the Operator status while the Operator is being installed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): leave out reverted edits when saving the profile

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): mask sensitive number inputs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): hide decorative provider icons from assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): cover analytics of the EKS Anywhere access request

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): drop keyboard simulation on a disabled update button

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): show the Operator status in a popover so its action is keyboard reachable

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): cover an enabled layer with nothing to configure

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): give the Operator status popover an accessible name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): hide cloned SVG provider icons from assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): scope the decorative icon assertion to the rendered cluster-add

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): close out the remaining engine v2 review threads (#3064)

* fix(shared): tie catalog input errors to their controls for assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): reset the allowed-values select when its value is cleared

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): give the modal close button an accessible name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(clusters): style the EKS Anywhere card as unavailable until access is granted

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): do not mark a cluster input reset to its default as changed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(clusters): confirm before leaving the Operator install step

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): name the install step blocker test after what it verifies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): derive catalog input error ids per instance

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): compare cluster input edits as the inputs display them

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): resolve engine v2 build and profile issues

- Ignore test files when generating TanStack routes
- Normalize platform requirement types and provider icon props
- Upgrade React and the TypeScript Axios SDK

* fix(clusters): show resolved values for read-only fields

- Disable read-only profile inputs and display their API-resolved values
- Add regression coverage for the read-only field behavior

* fix(clusters): keep disabled sensitive fields masked

* refactor(clusters): address engine v2 review comments (#3099)

* fix(clusters): keep read-only fields disabled in the array item modal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(clusters): warn before leaving the profile with unsaved changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(shared): move isHttpStatus next to the Axios interceptor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): rename useIsEngineV2Cluster to useIsOperatorManagedCluster

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): default platform configuration hook keys to empty strings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): move platform configuration hooks next to the other cluster hooks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): move platform configuration utils next to the other cluster utils

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): use the shared Heading and Section in the self-managed creation flow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): type the creation flow layouts with PropsWithChildren

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): show unmapped Operator violations in a Callout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(clusters): export the profile tree like the other modules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(catalog): move the catalog variable helpers and input into their own library

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): use cva for the EmptyState size and variant classes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(ui): add HighlightText stories

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): drop the unused Tooltip arrow class and collision padding props

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): control the InputSearch value instead of syncing its default value

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): rename useIsOperatorManagedCluster to useIsOperatorAttached

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): keep the InputSelectSmall accessible name opt-in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): simplify the cluster profile layout

- Remove the cluster header and its unused context data
- Add a divider to the profile sidebar

* fix(clusters): show empty state when no settings match search

- Detect when the selected component matches only hidden settings
- Cover the filtered settings empty state

* refactor(clusters): clarify layer is not configurable yet

* refactor(clusters): clarify when the Operator status row is clickable

- Add hover and pointer styling only when the status panel can open
- Cover clickable and unavailable status states in the footer spec

* test(clusters): clarify Operator status row clickability coverage

* fix(clusters): keep profile saving available during checks

- Allow saving while configuration edits are being checked again
- Keep saving blocked when checks fail or report violations or missing inputs

* fix(clusters): keep the refresh error visible when no setting matches the search

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(clusters): describe that the last save verdict holds during rechecks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(schema-fields): rename the catalog lib to a shared schema fields library

The library holds schema-driven field definitions, validation and inputs. It is not tied to
the service catalog and is meant to be shared across domains, so it moves to
@qovery/shared/schema-fields/feature and drops the Catalog and Variable prefixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ui): render InputSearch specs with the shared test utils

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(clusters): only show the profile for Engine v2 clusters (#3105)

feat(clusters): only show the profile for clusters attached to the Operator

The Profile tab and route were gated on the feature flag alone, so every cluster had them.
They now also require a self-managed cluster attached to the Qovery Operator, like the
Operator-specific cluster actions. useIsOperatorAttached reports undefined until the flags,
the cluster and its Operator status are loaded, so the route does not redirect too early.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
erebe added a commit that referenced this pull request Oct 14, 2026
* feat(clusters): label Operator updates in deployment history (#3098)

* chore(skills): clarify implementation and review guidance (#3101)

* chore(skills): clarify implementation and review guidance

* chore(skills): refine actionable review rules

* chore(skills): synchronize standards rule index

* chore(skills): define operation display mismatches

* chore(skills): clarify conditional class composition

* chore(skills): clarify domain placement and library ownership

* chore(skills): align legacy shared library guidance

* chore(skills): consolidate implementation and review guidance

- Align clsx/twMerge guidance across rules
- Move code placement and console-shared rules to project architecture
- Compile implementation and review rules into AGENTS.md and SKILL.md
- Drop tool-specific cubic section and tighten wording into bullets

* chore(skills): reconcile shared helper placement

* feat(audit-logs): label Operator update events (#3104)

Bump qovery-typescript-axios to 1.1.1010 for the OPERATOR_UPDATE and
MAINTENANCE_OPERATOR audit event types. They read "Operator Update" and
"Maintenance · Operator Update", with the icons of their TRIGGER_DEPLOY and
MAINTENANCE counterparts, and show up in the Event filter.

* feat(qov-2363): Set SAML local storage even if coming from direct link (#3100)

* feat(qov-2363) Set SAML local storage even if coming from direct link

* refacto: Use the useLocalStorage hook

---------

Co-authored-by: Melvin Zottola <mzottola@qovery.com>

* feat(environments): add deploy by version (#3014)

* feat(environments): add deploy by version

* fix(environments): harden deploy by version

* fix(environments): keep version menu above modal

* fix(environments): pin deploy modal actions

* test(environments): clarify deploy modal option coverage

* fix(environments): redirect actions to deployment pipeline

* fix(environments): share pipeline toast navigation

* test(environments): mock tanstack params in redeploy flag

* fix(environments): update environment pipeline hook callers

* fix(toast): show loading for async actions

* fix(shared-ui): catch toast action errors

* fix(shared-ui): allow toast callbacks to return values

* chore(environments): group pipeline navigation hook and helper

* fix(environments): use registry details for version selection

* feat: introduce new engine (#2997)

* Add Profile page

* Implement main Profile page UI elements

* fix(clusters): disable unavailable cluster profile controls

- Remove unused cluster actions
- Disable the log infrastructure toggle and update its test

* feat(clusters): support dynamic platform configuration

- Resolve cluster bindings and component configuration previews
- Render API-defined fields and validation states in cluster profiles

* feat(clusters): add the cluster profile layer sidebar

- Add searchable, selectable layer and component navigation with status indicators
- Reuse the shared search input and expose its accessible label

* feat(clusters): arrange profile inputs in compact rows

- Add row layouts with truncated descriptions and tooltips
- Align profile controls and errors consistently

* feat(clusters): show positive empty state for unconfigured components

- Add a positive variant to the shared EmptyState component
- Use it when a cluster profile component needs no configuration

* fix(clusters): constrain profile page to its container

* fix(clusters): match profile skeleton to configuration rows

* chore(clusters): log profile schema responses in development

* fix(clusters): preserve resolved profile fields on refresh

- Show configuration skeletons only until displayed components resolve
- Keep the last resolved fields visible when background refreshes fail

* fix(clusters): match profile tab icons to sidebar

- Reuse the sidebar component icon in profile tabs
- Assert matching icons for Loki and Alloy

* fix(clusters): remove operator footer from profile sidebar

- Add bottom spacing to the profile configuration panel

* feat(clusters): support nested profile configuration fields

- Add and edit array items through validated modals
- Show nested field violations and enforce array limits

* feat(clusters): remove heading

* fix(clusters): use section for profile content region

* feat(clusters): add searchable cluster profile settings

- Persist profile search in the URL and filter matching layers, components, and fields
- Highlight search matches in configuration labels and descriptions

* feat(clusters): save and deploy profile changes

* refactor(clusters): move profile state into context

* fix(shared-ui): order highlight text classes consistently

* fix(clusters): remove profile header surface background

* feat(clusters): add Engine V2 cluster creation flow

* fix(clusters): disable components without configuration

- Skip non-configurable components when opening profile layers or URL selections
- Hide their tabs and explain disabled sidebar items

* fix(clusters): reflect resolved layer statuses in profile

- Disable skipped and Qovery-managed layers using cluster configuration
- Show a status-specific explanation when a layer is disabled

* fix(ui): preserve input defaults and select accessibility

- Omit undefined search defaults from rendered input attributes
- Keep small select aria labels explicit
- Center select chevrons vertically

* fix(clusters): detect Engine v2 clusters for deployment actions

- Use Operator status to identify Engine v2 clusters
- Restrict deployment actions for those clusters

* feat(clusters): show Operator status in cluster profile

* fix(clusters): prevent dismissing install flow

- Keep the creation modal open during Operator installation
- Cover dismissal before and after installation in ClusterAdd specs

* fix(clusters): create self-managed clusters without a template

- Send only edited Operator configuration and allow default platform selection
- Clarify Operator installation guidance and cover template loading

* fix(clusters): block creation when templates fail to load

- Show a retry option when Operator templates cannot be loaded
- Keep cluster creation disabled until templates load successfully

* fix(clusters): remove obsolete requirement status badge

* fix(clusters): use list items for layer sidebar states

* fix(clusters): use navbar links for profile components

- Replace tab buttons with Navbar links
- Update navigation tests for link semantics and keyboard movement

* fix(clusters): prevent leaving flow during cluster creation

* fix(clusters): block saving invalid profile changes

- Disable save actions until component checks pass
- Cover violations, missing inputs, and unresolved checks

* fix(clusters): reset profile state when switching clusters

* feat(clusters): add component routes to cluster profile

* fix(clusters): ignore cached Operator status when disabled

- Gate Engine v2 detection on the feature flag and self-managed cluster type
- Cover disabled, managed, and unattached cluster cases

* fix(clusters): prevent duplicate Operator updates

- Disable the update button while an update is in progress
- Cover version arguments and in-progress behavior with tests

* fix(clusters): remove obsolete update button comment

* fix(clusters): wait for profile feature flag to load

* fix(clusters): expose profile navbar as navigation

* fix(clusters): stop loading when template queries are disabled

- Gate template loading on the query being enabled
- Cover supported, failed, and unsupported cluster states

* fix(clusters): remove gateway API warning indicator

* test(clusters): verify self-managed cluster selection tracking

* fix(clusters): block saving for offscreen invalid components

- Include edited components outside the active section in configuration resolution
- Keep save actions disabled when any edited component has validation errors

* test(clusters): cover Operator update action visibility

* fix(clusters): remove disabled profile controls

* fix(clusters): close item modal when profile unmounts

- Track the array item modal lifecycle and close it on profile unmount
- Cover modal cleanup with a regression test

* fix(clusters): address engine v2 review comments (#3057)

* fix(clusters): wait for the Operator configuration check before creating

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): stop polling clusters without Operator and show status errors

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): block incomplete or invalid profile array items

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show the cluster provider and layers on every profile width

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(ui): name and sync profile inputs for assistive tech and navigation

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): mark EKS Anywhere as an access request

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(ui): rename the search highlight surface token

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): require resolved Operator inputs before creating

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): ignore paused or outdated Operator checks

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): let a failed Operator check be retried

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): map vendor names to their profile header icons

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): assert the array items added from defaults

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show Operator status errors over the cached status

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(ui): show the clear button for external search values

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(clusters): engine v2 review improvements (#3060)

* fix(clusters): keep profile edits made while saving

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): redirect only once when the Operator connects

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): track the item modal however it is dismissed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* perf(clusters): only debounce profile edits, not component switches

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): use the brand focus outline on profile sidebar buttons

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): show OVH, Oracle and IBM icons in cluster avatars

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): use ClusterAvatar in the profile header

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): align Operator and profile search copy

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): use the layer-group icon in the profile sidebar

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): keep the HTTP status helper private to data-access

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(ui): drive InputSearch with userEvent

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* refactor(clusters): read route ids in the Operator status components

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): cover the platform configuration helpers

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* test(clusters): drop an unused testing import

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* UI tweak

* perf(clusters): debounce profile edits instead of preview requests

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): only mention the search when the sidebar has one

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): report the item modal mount state explicitly

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* chore(clusters): remove profile API response logging

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* fix(clusters): address remaining Cubic and Copilot review feedback on engine v2 (#3063)

* fix(clusters): do not select a disabled layer when none can be opened

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): do not open non-configurable components matched by search

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): keep polling the Operator status while the Operator is being installed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): leave out reverted edits when saving the profile

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): mask sensitive number inputs

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): hide decorative provider icons from assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): cover analytics of the EKS Anywhere access request

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): drop keyboard simulation on a disabled update button

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): show the Operator status in a popover so its action is keyboard reachable

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): cover an enabled layer with nothing to configure

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): give the Operator status popover an accessible name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): hide cloned SVG provider icons from assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): scope the decorative icon assertion to the rendered cluster-add

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): close out the remaining engine v2 review threads (#3064)

* fix(shared): tie catalog input errors to their controls for assistive technologies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): reset the allowed-values select when its value is cleared

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): give the modal close button an accessible name

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(clusters): style the EKS Anywhere card as unavailable until access is granted

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): do not mark a cluster input reset to its default as changed

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(clusters): confirm before leaving the Operator install step

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(clusters): name the install step blocker test after what it verifies

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(shared): derive catalog input error ids per instance

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): compare cluster input edits as the inputs display them

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(clusters): resolve engine v2 build and profile issues

- Ignore test files when generating TanStack routes
- Normalize platform requirement types and provider icon props
- Upgrade React and the TypeScript Axios SDK

* fix(clusters): show resolved values for read-only fields

- Disable read-only profile inputs and display their API-resolved values
- Add regression coverage for the read-only field behavior

* fix(clusters): keep disabled sensitive fields masked

* refactor(clusters): address engine v2 review comments (#3099)

* fix(clusters): keep read-only fields disabled in the array item modal

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(clusters): warn before leaving the profile with unsaved changes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(shared): move isHttpStatus next to the Axios interceptor

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): rename useIsEngineV2Cluster to useIsOperatorManagedCluster

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): default platform configuration hook keys to empty strings

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): move platform configuration hooks next to the other cluster hooks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): move platform configuration utils next to the other cluster utils

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): use the shared Heading and Section in the self-managed creation flow

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): type the creation flow layouts with PropsWithChildren

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): show unmapped Operator violations in a Callout

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(clusters): export the profile tree like the other modules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(catalog): move the catalog variable helpers and input into their own library

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): use cva for the EmptyState size and variant classes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(ui): add HighlightText stories

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): drop the unused Tooltip arrow class and collision padding props

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): control the InputSearch value instead of syncing its default value

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): rename useIsOperatorManagedCluster to useIsOperatorAttached

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(ui): keep the InputSelectSmall accessible name opt-in

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(clusters): simplify the cluster profile layout

- Remove the cluster header and its unused context data
- Add a divider to the profile sidebar

* fix(clusters): show empty state when no settings match search

- Detect when the selected component matches only hidden settings
- Cover the filtered settings empty state

* refactor(clusters): clarify layer is not configurable yet

* refactor(clusters): clarify when the Operator status row is clickable

- Add hover and pointer styling only when the status panel can open
- Cover clickable and unavailable status states in the footer spec

* test(clusters): clarify Operator status row clickability coverage

* fix(clusters): keep profile saving available during checks

- Allow saving while configuration edits are being checked again
- Keep saving blocked when checks fail or report violations or missing inputs

* fix(clusters): keep the refresh error visible when no setting matches the search

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(clusters): describe that the last save verdict holds during rechecks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(schema-fields): rename the catalog lib to a shared schema fields library

The library holds schema-driven field definitions, validation and inputs. It is not tied to
the service catalog and is meant to be shared across domains, so it moves to
@qovery/shared/schema-fields/feature and drops the Catalog and Variable prefixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(ui): render InputSearch specs with the shared test utils

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat(clusters): only show the profile for Engine v2 clusters (#3105)

feat(clusters): only show the profile for clusters attached to the Operator

The Profile tab and route were gated on the feature flag alone, so every cluster had them.
They now also require a self-managed cluster attached to the Qovery Operator, like the
Operator-specific cluster actions. useIsOperatorAttached reports undefined until the flags,
the cluster and its Operator status are loaded, so the route does not redirect too early.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* feat(api-tokens): show last usage in token lists (#3107)

Help users assess token activity directly from organization settings when
reviewing credentials to keep or remove.

Show Last used beside creation details for regular and policy API tokens.
Format the timestamp as a human-readable age relative to when the list
loads, keeping that reference stable across rerenders. Show the exact UTC
timestamp on hover and No recorded usage when the value is null or absent.

Extend the list prop types with optional last_used_at support while the
pinned generated API client does not yet declare the field.

Test relative formatting, placement, hover timestamps, missing values, and
the fixed reference time across rerenders for both lists.

---------

Co-authored-by: Pierre GB <pgerbelot@qovery.com>
Co-authored-by: Melvin Zottola <37779145+mzottola@users.noreply.github.com>
Co-authored-by: Melvin Zottola <mzottola@qovery.com>
Co-authored-by: Théo Grandin <theo.grandin74@gmail.com>
Co-authored-by: Romain Billard <rmnbrd@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Erèbe - Romain Gerard <erebe@erebe.eu>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants