Skip to content

feat(engine-v2): add platform configuration UI - #2817

Open
pggb25 wants to merge 2 commits into
stagingfrom
feat/engine-v2-slice4-platform-configuration
Open

feat(engine-v2): add platform configuration UI#2817
pggb25 wants to merge 2 commits into
stagingfrom
feat/engine-v2-slice4-platform-configuration

Conversation

@pggb25

@pggb25 pggb25 commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Here is a PR for self-managed clusters within the scope of the engine V2 POC.
All changes is under feature flag.

Preview can be found here
https://p80-z9693eb24-z7d62c7cc-gtw.zc531a994.rustrocks.cloud/

Existing test cluster is here
https://p80-z9693eb24-z7d62c7cc-gtw.zc531a994.rustrocks.cloud/organization/460616f0-94da-4d35-b631-6fa4ed08eb9a/cluster/8a494a2b-ce45-4499-a3c2-f5c75fbd38dd/settings/platform

What we reuse from the Service Catalog is the normalized field vocabulary and the generic form renderer: field types, defaults, constraints, sensitivity, local validation, and widget selection.
The change on the Service Catalog side was mainly an extraction: Blueprint-specific field utilities and rendering were moved into shared catalog primitives. Blueprints now adapt their DTOs to those primitives, and Platform Configuration does the same with its own q-core DTOs.
The goal is to share the configuration mechanism while keeping the two domains independent.

Screenshots / Recordings

Adding new "Platform configurations" panel in the edit and creation of a self-managed cluster

Screenshot 2026-07-20 at 10 59 04

The idea of the review is to check the godd separation and the good utilisation of the existing service catalogue feature

Testing

  • Changes tested locally in the relevant Console's pages and Storybooks
  • yarn test or yarn test -u (if you need to regenerate snapshots)
  • yarn format
  • yarn lint

PR Checklist

  • I followed naming, styling, and TypeScript rules (see .cursor/rules)
  • I performed a self-review (diff inspected, dead code removed)
  • I titled the PR using Conventional Commits with a scope when possible (e.g. feat(service): add new Terraform service) - required for semantic-release
  • I only kept necessary comments, written in English (watch for useless AI comments)
  • I involved a designer to validate UI changes if I am not a designer
  • I covered new business logic with tests (unit)
  • I confirmed CI is green (Codecov red can be accepted)
  • I reviewed and executed locally any AI-assisted code

@pggb25
pggb25 force-pushed the feat/engine-v2-slice4-platform-configuration branch 4 times, most recently from 84b9344 to 4234d9b Compare July 15, 2026 12:02
@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.64030% with 209 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.24%. Comparing base (d554e0d) to head (a2a0d1a).
⚠️ Report is 5 commits behind head on staging.

Files with missing lines Patch % Lines
.../platform-configuration/platform-configuration.tsx 0.00% 53 Missing ⚠️
...ster-creation-flow/step-platform/step-platform.tsx 61.53% 8 Missing and 22 partials ⚠️
...n-guide-modal/cluster-installation-guide-modal.tsx 37.03% 4 Missing and 13 partials ⚠️
.../catalog-variable-input/catalog-variable-input.tsx 31.81% 6 Missing and 9 partials ⚠️
...luster-creation-flow/step-summary/step-summary.tsx 52.17% 5 Missing and 6 partials ⚠️
...form-configuration/platform-configuration-utils.ts 81.81% 3 Missing and 7 partials ⚠️
...atform-configuration/hooks/use-cluster-operator.ts 0.00% 9 Missing ⚠️
...b/platform-configuration/platform-configuration.ts 70.83% 7 Missing ⚠️
...s/use-platform-template-component-configuration.ts 0.00% 7 Missing ⚠️
.../cluster-creation-flow/cluster-new/cluster-new.tsx 71.42% 5 Missing and 1 partial ⚠️
... and 16 more
Additional details and impacted files
@@             Coverage Diff             @@
##           staging    #2817      +/-   ##
===========================================
+ Coverage    46.93%   47.24%   +0.31%     
===========================================
  Files         1263     1282      +19     
  Lines        27061    27601     +540     
  Branches      7887     8102     +215     
===========================================
+ Hits         12701    13041     +340     
- Misses       12194    12314     +120     
- Partials      2166     2246      +80     
Flag Coverage Δ
unittests 47.24% <60.64%> (+0.31%) ⬆️

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.

@pggb25
pggb25 force-pushed the feat/engine-v2-slice4-platform-configuration branch 7 times, most recently from 200cce6 to e140985 Compare July 15, 2026 16:51
pggb25 and others added 2 commits July 16, 2026 12:10
- guard operator queries against the undefined PostHog flag state (modal,
  create/settings platform routes) so flag-off orgs never hit operator
  endpoints and refreshes no longer bounce users off the platform step
- make engine-v2 cluster creation idempotent on retry and redirect to the
  platform step when platform data is missing instead of failing silently
- fix bool cluster-input requirements round-trip and keep requirement
  inputs mounted during preview refreshes (no more focus loss per keystroke)
- keep cleared field values empty instead of resurrecting schema defaults;
  omit cleared markers from resolver and save payloads
- make components without catalog fields openable so requirement-only
  components can be configured
- exclude Stop / Upgrade K8s actions for self-managed clusters
- restore bool-before-allowedValues precedence in CatalogVariableInput
  (blueprint regression) with a non-regression test
- key PlatformConfiguration by cluster and re-seed when the template list
  changes; surface binding fetch errors instead of redirecting
- add Back navigation to step-platform error/empty states
- drop dead validationMode/componentsConfigurable props, use ts-pattern
  for enum mappers, import catalog types directly from util-js

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pggb25
pggb25 force-pushed the feat/engine-v2-slice4-platform-configuration branch from e140985 to a2a0d1a Compare July 17, 2026 13:21

@RemiBonnet RemiBonnet left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @pggb25! I added few comments and I think you can probably share with @TheoGrandin74 to check if the UI is ok for him. I added after my comments:

  • I'm not sure why I've an error when I click on the Qovery stack in the creation flow, is it something expected?
Image
  • Label aren't supported right now for this kind of cluster, could we hide it?

}

// These endpoints are not generated by qovery-typescript-axios yet. Keeping the raw
// calls behind this data-access module avoids leaking their transport details into UI code.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When do you want to add it in the qovery-typescript-axios package?

type PlatformComponentConfigurationPreviewRequest,
PlatformConfigurationApi,
} from 'qovery-typescript-axios'
import { isHttpStatus } from '../http/is-http-status'

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure to understand why do you need to return null if it's a 404? Same for cluster-operator.ts file

enabled?: boolean
}

export function useClusterOperatorStatus({ organizationId, clusterId, enabled = true }: ClusterOperatorQueryProps) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You need to have one file per query

<div className="rounded-lg border border-neutral bg-surface-neutral p-5">
<div className="mb-5 flex items-start justify-between gap-3">
<div>
<Heading level={2}>{formatCatalogKey(component.key)}</Heading>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You need to have <Section> component before your Heading

) : null}

{fields.length > 0 ? (
<section className="flex flex-col gap-3">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This one should be <Section>

const { data: binding } = usePlatformBinding({ organizationId, clusterId, suspense: true })
const { mutate: updateBinding, isLoading: isSaving } = useUpdatePlatformBinding()

const [state, setState] = useState<PlatformConfigurationState | null>(() => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you rename it with a more explicit name? platformConfigurationState and setPlatformConfigurationState, in react state is generic

value: CatalogVariableValue | undefined
}

export function CatalogVariableInput({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This component is not enough generic to be in the UI shared library, could you add it in a domain?

)
}

const saveConfiguration = () =>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Inputs that are no longer required remain in customerProvidedInputs, could we filter them against preview.requirements, as we already do in the creation flow?

})}
</Accordion.Root>

<div className="flex justify-between border-t border-neutral pt-4">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can users continue without validating the components of an enabled layer?

const { data: binding } = usePlatformBinding({ organizationId, clusterId, suspense: true })
const { mutate: updateBinding, isLoading: isSaving } = useUpdatePlatformBinding()

const [state, setState] = useState<PlatformConfigurationState | null>(() => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The creation and settings flows duplicate template selection, preview, field updates and payload cleanup, could this shared controller logic live in a domain hook?

const isOperatorGuideLoading =
isFeatureFlagLoading ||
(canUseOperator && (isOperatorStatusLoading || (isOperatorManaged && isOperatorBootstrapLoading)))
// Only a bootstrap failure of a confirmed operator-managed cluster blocks the guide;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should a status request failure fall back to the legacy guide? A transient API error could show incorrect instructions for an operator-managed cluster, I would expect an error state with Retry instead

templateId: string
}

export function PlatformConfiguration({

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Could you add small test for this one?

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