onboarding: data-plane picker in the signup form - #2045
Conversation
…onboarding The authenticated dataPlanes query returns nothing for a brand-new signup (no grants yet), so the onboarding plane picker needs the control-plane API's unauthenticated publicDataPlanes query instead.
…rd claims Adds a plane picker between the organization name field and the survey, backed by the unauthenticated publicDataPlanes query (a brand-new signup has no grants yet, so the authenticated dataPlanes query returns nothing). Auto-preselects aws-us-east-1-c1 (falling back to the first available plane) so submitting without touching the picker still records an explicit, valid choice; fails safe to no picker + an omitted claim if the plane list can't be loaded, letting the backend apply its own default. generateUserClaim now forwards requestedDataPlane only when set, never as an explicit null, so older backends that don't know the field are unaffected. Also registers PublicDataPlane in the urql cache's keys config (alongside the existing DataPlane entry) to silence a normalization warning for the new unkeyed type. Verified end-to-end against a real local stack: picker lists the seeded public plane, auto-selects it, and a completed registration produced a storage_mappings row with the picked plane in data_planes.
- Move PublicDataPlaneNode + a named toPublicDataPlaneNode transform into src/api/gql/dataPlanes.ts, alongside the existing DataPlaneNode / toDataPlaneNode pair the sibling useDataPlanes() hook uses. The hook previously defined its own type and inlined an identity transform, diverging from where this codebase already models data-plane nodes. - Destructure betaOnboard's generateUserClaim args by name instead of indexing (args[0], args[1], args[2]) — same positional-args signature (shared across all directive types), just clearer at the read site. - Rename DataPlaneSelector's PREFERRED_DEFAULT to DEFAULT_PUBLIC_DATA_PLANE, matching the backend's constant of the same meaning and making the value's type (a plane name) obvious from the name. No behavior change: tsc and lint both pass clean.
The Organization Name field overrides the 2px theme default to borderRadius: 3 (6px). The picker sat right below it inheriting the theme default, so the two adjacent inputs had visibly different corners. Apply the same override.
- Sort options by cloudProvider then region: groupBy only groups correctly when the list is ordered by group, which previously worked only because plane names embed the provider. - Extract the region/name label used by both getOptionLabel and renderOption so the two can't drift. - Drop isOptionEqualToValue; value is always drawn from options, so MUI's default reference comparison already matches. - Hoist the input sx to a module const, and reuse hasLength for the claim's non-empty check.
⚪ Code HealthNo change to the dead-code surface. 48 Unused files
64 Unused exports
26 Unused exported types
14 Unused exported enum members
5 Unused dependencies
3 Unused devDependencies
|
CI's Check Quality runs prettier, which I hadn't run locally. Formatting only, no functional change.
Issues
estuary/sre#29 (Phase 2 — tracked in a roadmap doc, not an estuary/ui issue)
Changes
sre#29
DataPlaneSelectorto the signup form (BetaOnboard.tsx), between the organization name field and the survey. It's backed by the existing unauthenticatedpublicDataPlanesquery, which this PR consumes for the first time — the authenticateddataPlanesquery returns nothing for a brand-new signup, since there are no grants yet.ops/dp/public/aws-us-east-1-c1when it's available, falling back to the first plane otherwise, so submitting without touching the picker still records an explicit, valid choice.requestedDataPlanerather than sending it as an explicit null, so the backend falls back to its own default instead of the signup form breaking.betaOnboarddirective'sgenerateUserClaimto forwardrequestedDataPlaneonly when it's set, so backends that don't know the field yet aren't affected.usePublicDataPlanes()hook andPublicDataPlaneNodetype, following the existinguseDataPlanes()/DataPlaneNodepattern already in the codebase.Options show the region and the full catalog name together, and group by cloud provider. The catalog name is deliberate rather than noise: nothing stops two public planes sharing a region (already true for GCP), so the name is what makes the choice unambiguous.
This depends on estuary/flow#3318 merging and deploying first. The agent rejects unknown claim fields, so if this ships before that one is live, every signup fails with
invalidClaims. Merging flow isn't sufficient on its own — an old agent still running will reject the claim.Tests
Manually tested
I ran a full signup through the real onboarding form against a local flow stack. The picker listed the seeded public planes grouped by cloud provider, auto-selected the platform default, and a completed registration produced the correct
storage_mappingsrow with the picked plane recorded as the tenant's default.I repeated this against a synthetic AWS-shaped plane with
COLOCATED_TRIAL_BUCKETSenabled on the backend. The resulting storage mapping showed the derived S3 bucket, confirming the picker's choice flows through correctly end to end.I also checked what happens against a real, older backend that predates this feature: the query fails with a clear GraphQL error, the picker just doesn't render, and the rest of the form stays fully usable. No crash.
Finally, with the companion PR's migration applied, a data plane marked
closeddisappears from the picker's options — the list and the backend agree on what's selectable.Automated tests
tsc --noEmitandnpm run lintboth pass clean. I didn't add new unit tests since this is UI wiring around an already-tested backend contract; flagging that for reviewer input rather than assuming it's fine.Playwright tests ran locally
Screenshots