feat(onboarding): Wire ScmProjectDetailsCore into single-view project creation#117213
Conversation
ee4d952 to
5aef02d
Compare
f91d3de to
46332c9
Compare
5aef02d to
2e2119a
Compare
46332c9 to
4b53f99
Compare
2e2119a to
61db678
Compare
4b53f99 to
d9a5db4
Compare
d9a5db4 to
f2840ce
Compare
f2840ce to
eb70229
Compare
eb70229 to
b12223e
Compare
8f81c42 to
c6e56a2
Compare
e4ff029 to
df14bd1
Compare
c6e56a2 to
63dd544
Compare
|
bugbot run |
…d core (#117209) ## TLDR Splits the SCM onboarding project-details step into a reusable `useScmProjectDetails` hook plus a presentational `ScmProjectDetailsCore`, so the SCM-first project-creation flow can reuse it and place its own Create button. No behavior change; the existing spec passes unchanged. ## Details - `useScmProjectDetails` owns the form state, the create-project + repo-link flow, the reuse ("nothing changed") short-circuit, and the field/create analytics, routed by an `analyticsFlow` prop. It also supports a no-access member path (`allowMemberWithoutTeam`), off by default. - `ScmProjectDetailsCore` is the presentational name / team / alert-frequency form. It fires the `step_viewed` analytics when shown and hides the team selector for no-access members. Keeping the submit handler in the hook (rather than a render-prop) means each host renders its own Create button wherever it wants, decoupled from where the fields render. - `ScmProjectDetails` (onboarding) is now a thin wrapper: the step header plus the fixed footer with the Back and Create buttons. This is the VDY-76 equivalent of the `ScmPlatformFeaturesCore` extraction (#116624). ## Stack - **PR 1 (this):** Extract project-details form into a hook and core - [PR 2](#117325): Keep getting-started rendered while back nav deletes - [PR 3](#117333): Drive the project-details form from host state - [PR 4](#117213): Wire into single-view project creation - [PR 5](#117341): Commit the auto-detected platform to the host - [PR 6](#117342): Explain the disabled Create CTA in the SCM wizard Refs VDY-76
ba70807 to
ece92a8
Compare
92f270f to
b52dc19
Compare
…#117325) ## TLDR Keeps the getting-started page rendered when its project disappears from the projects store mid-session, reserving the not-found redirect for projects that were never found. This stops the back nav's project deletion from bouncing to the create-project page without the referrer and project query params. ## Details - The back nav from getting-started (`PlatformDocHeader.handleGoBack`) deletes inactive projects before navigating to the create-project page tagged with `?referrer=getting-started&project=<id>`. The deletion order is deliberate: downstream flows rely on the projects store being updated before they mount (see the equivalent comment in onboarding's `useBackActions`). - The DELETE updates the store while getting-started is still mounted, so its project-not-found fallback fired first and redirected to the create-project page bare, racing the tagged replace navigation. Classic project creation tolerates this reactively (see the delayed route replace regression test in `createProject.spec.tsx`), but the params still arrive a full request roundtrip late, and the single-view flow in PR 3 restores a saved wizard session from them, which made the race visible as a flash of reset state. - Getting-started now latches the last project found for the current slug and keeps rendering it if it vanishes from the store, so the only navigation away is the back nav's own tagged replace. A project deleted from another tab now leaves the docs page in place instead of bouncing immediately, which seems less surprising. ## Stack - [PR 1](#117209): Extract project-details form into a hook and core (merged) - **PR 2 (this):** Keep getting-started rendered while back nav deletes - [PR 3](#117333): Drive the project-details form from host state - [PR 4](#117213): Wire into single-view project creation - [PR 5](#117341): Commit the auto-detected platform to the host - [PR 6](#117342): Explain the disabled Create CTA in the SCM wizard Refs VDY-76
ece92a8 to
e45dbe6
Compare
b52dc19 to
bd25648
Compare
) ## TLDR Makes the SCM project-details hook fully host-driven: the form state lives with the caller (`projectDetailsForm` plus `onProjectDetailsFormChange`, where absent fields derive their defaults), and completion is reported through a single `onComplete` carrying the created project and the submitted form. Prepares the hook for the single-view project-creation host, which keeps it mounted across platform changes and needs clears to actually reach the fields. ## Details - Previously the hook seeded internal `useState` once at mount from the host's saved form, an artifact of the step component it was extracted from, which remounts on every onboarding navigation. A host that stays mounted (the single-view wizard) could clear its form without the live fields noticing. - Controlled now: absent fields fall back to derived defaults (platform-based name, first admin team, default alert config), so a cleared form re-derives by construction. Covered by a new regression test. - The unchanged-return reuse check compares against the form captured at mount (a restored session's saved values), since the live prop can no longer be its own baseline. - The three completion callbacks (`onProjectCreated`, completion-time `onProjectDetailsFormChange`, `onComplete`) collapse into one `onComplete({project, projectDetailsForm})`. On a successful submit they always fired together, so no host could observe a meaningful intermediate state. The reuse path now reports the reused project and form, which match what the host already has. - The onboarding step holds the live form in local state seeded from the context, which keeps the context to submitted values only: a step remount cannot adopt unsubmitted edits as the reuse baseline, and abandoned edits are discarded on navigation, matching the step's previous behavior and classic createProject. The completion payload still flows to the existing context setters, so observable onboarding behavior is unchanged. ## Stack - [PR 1](#117209): Extract project-details form into a hook and core (merged) - [PR 2](#117325): Keep getting-started rendered while back nav deletes (merged) - **PR 3 (this):** Drive the project-details form from host state - [PR 4](#117213): Wire into single-view project creation - [PR 5](#117341): Commit the auto-detected platform to the host - [PR 6](#117342): Explain the disabled Create CTA in the SCM wizard Refs VDY-76
… creation Replace the project-details placeholder in the SCM-first project-creation wizard with the project-details form, completing the single-view create flow. - Drive the Project details section with useScmProjectDetails and the presentational ScmProjectDetailsCore. - Render the Create CTA as an always-present page-level footer, so the primary action is available regardless of which steps are revealed (disabled until a platform and details are ready), alongside ProjectCreationErrorAlert. - Persist the project-details form to the wizard session state on every change (persistFormOnChange) so navigating away and back restores it, matching the repository/platform/feature selections. Cleared when the platform or repository changes. Onboarding keeps its snapshot-on-create model, whose reuse check relies on it. - On success, navigate to the new project's getting-started page and clear the wizard session. - Pass allowMemberWithoutTeam so a member with no admin team can still create a project with no team, matching classic project creation. Messaging-integration alerts remain out of scope (VDY-50). Refs VDY-76
The back nav from getting-started can mount the create-project page before its replace navigation appends the referrer/project query params (the POP fires first, and deleting an inactive project triggers a bare redirect). The once-only mount gate then wiped the persisted wizard and never re-evaluated, so the session was lost despite the params landing in the URL moments later. Replace the mount gate with the pattern classic createProject uses for autofill: snapshot the completed session when a project is created, and compute the return condition reactively from the location query. The wizard itself is keyed on the restore so mount-seeded form state re-reads the restored session, and in-progress state is now in-memory only since the snapshot covers the only round trip that needs persistence.
The project-details hook now reports completion through a single onComplete carrying the created project and the submitted form, so the wizard no longer needs to accumulate those pieces in state and defer its snapshot-and-navigate to an effect waiting for the writes to commit. Snapshot the completed session and navigate synchronously, dropping the pendingNavigation effect, the slug ref, and the two setState handlers.
The hook's form is now controlled by the host, so the wizard owns the live form in its state and clearing it on a platform or repo change actually resets the fields, instead of only affecting what a future restore would see.
An optimistic repository (empty id, see useScmRepoSelection) can be in wizard state at completion when the user creates the project before the repo resolution lands. Persisting it strands the restored session's platform detection in a permanent pending state, since the query can only fetch with a real id. Snapshot the session without it; the committed platform and features still restore.
bd25648 to
42515d2
Compare
Drop the center justification from the project, team, and alert header rows and the alert description, so the section content aligns to the start of the available width instead of being centered.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ca15cfc. Configure here.
| ); | ||
| }, | ||
| [wizardState, navigate, organization] | ||
| ); |
There was a problem hiding this comment.
Create enables duplicate projects
Medium Severity
After a successful create, handleComplete only persists to session storage and navigates; it never updates in-memory createdProjectSlug. The page-level Create button becomes enabled again once the mutation finishes, but useScmProjectDetails still treats the flow as a first-time create, so another click can POST a second project before navigation unmounts the wizard.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit ca15cfc. Configure here.
## TLDR Commits the auto-detected platform to the host in the platform-features core instead of only deriving it for display. In the single-view project-creation flow there is no Continue boundary to commit it later, so accepting the detected platform left the wizard without a platform: the project name never defaulted and the Create CTA stayed disabled. ## Details - The core rendered `selectedPlatform?.key ?? detectedPlatformKey` but only called `onPlatformChange` on explicit picks. The onboarding step compensates with a fallback commit in its Continue handler; the single-view flow has no equivalent, so detection-only sessions never populated `selectedPlatform`. - The commit now happens in the same once-per-repo effect that fires the `scm_platform_selected` analytics, with the same guards: skipped when the user already picked, re-armed on repo change. It does not call `onClearProjectDetailsForm`, so a restored form is not cleared. - The onboarding step's fallback commit becomes a no-op and stays as belt and braces. ## Stack - [PR 1](#117209): Extract project-details form into a hook and core (merged) - [PR 2](#117325): Keep getting-started rendered while back nav deletes (merged) - [PR 3](#117333): Drive the project-details form from host state - [PR 4](#117213): Wire into single-view project creation - **PR 5 (this):** Commit the auto-detected platform to the host - [PR 6](#117342): Explain the disabled Create CTA in the SCM wizard Refs VDY-76


TLDR
Wires the SCM project-details form into the single-view project-creation flow: a Project details section plus an always-present, page-level Create CTA that creates the project and navigates to its getting-started page. Includes parity with classic project creation for members with no admin team. Messaging-integration alerts are deferred to VDY-50.
Details
useScmProjectDetailsand the presentationalScmProjectDetailsCore.ProjectCreationErrorAlert.projectDetailsFormto the wizard state and clears it when the platform or repository changes (resolving the two standing TODOs).makeProjectsPathname.referrer/projectquery params (mirroring classiccreateProjectautofill) since the back nav can deliver them after mount.allowMemberWithoutTeam: when the viewer has no admin team and can't create one, the team selector is hidden and the project is created with no team (backend assigns one), matching classiccreateProject. Off in onboarding.Stack
Refs VDY-76