Skip to content

fix: handle duplicate workspace slugs in onboarding#4085

Merged
perkinsjr merged 4 commits intomainfrom
10-08-fix_handle_duplicate_workspace_slugs_in_onboarding
Oct 13, 2025
Merged

fix: handle duplicate workspace slugs in onboarding#4085
perkinsjr merged 4 commits intomainfrom
10-08-fix_handle_duplicate_workspace_slugs_in_onboarding

Conversation

@chronark
Copy link
Collaborator

@chronark chronark commented Oct 8, 2025

What does this PR do?

Refactors the onboarding wizard to fix navigation issues and improve state management.

The main change is in the trpc route, we just check for duplicate slugs and throw a CONFLICT error.
The remaining changes were necessary to retrofit the onboarding wizard to not autoadvance regardless of outcome

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)

How should this be tested?

  • Complete the entire onboarding flow to verify navigation works correctly
  • Test creating a workspace with a duplicate slug to verify error handling
  • Test back/next navigation between steps

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

@changeset-bot
Copy link

changeset-bot bot commented Oct 8, 2025

⚠️ No Changeset found

Latest commit: d6ff756

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Oct 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Oct 10, 2025 1:24pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
engineering Ignored Ignored Preview Oct 10, 2025 1:24pm

Copy link
Collaborator Author

chronark commented Oct 8, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

📝 Walkthrough

Walkthrough

Converts the onboarding wizard to a controlled component, updates onboarding step hooks to accept and call an advance callback wired to a clamped currentStepIndex, adjusts onboarding-content/fallback to use index-based control, and refactors the workspace create TRPC mutation into a transactional flow returning only orgId with duplicate-slug CONFLICT handling.

Changes

Cohort / File(s) Summary
Onboarding content wiring
apps/dashboard/app/new/components/onboarding-content.tsx
Adds local stepCount and a bounds-checked handleStepChange; wires useWorkspaceStep and useKeyCreationStep to accept advance callbacks that call handleStepChange(current + 1); passes currentStepIndex and setCurrentStepIndex to OnboardingWizard (replacing prior onStepChange).
Onboarding fallback wiring
apps/dashboard/app/new/components/onboarding-fallback.tsx
Replaces noop step callbacks with controlled props currentStepIndex and setCurrentStepIndex (setter here is a no-op); uses index-based navigation instead of previous callback placeholders.
Onboarding wizard control model
apps/dashboard/app/new/components/onboarding-wizard.tsx
Converts wizard to controlled model: removes internal currentStepIndex state/effects and onStepChange/onComplete; accepts currentStepIndex and setCurrentStepIndex; delegates Next/Skip to current step handlers and relies on provided setter for navigation.
Workspace step hook
apps/dashboard/app/new/hooks/use-workspace-step.tsx
Signature changed to useWorkspaceStep({ advance }); on successful workspace create, switches org and calls advance(); adds CONFLICT handling for duplicate slug via form.setError; clears slug errors on change; onStepNext now advances when created or submits form when not loading.
Key creation step hook
apps/dashboard/app/new/hooks/use-key-creation-step.tsx
Signature changed to useKeyCreationStep({ advance }); calls advance() after successful key creation; onStepNext submits only when not loading and returns booleans indicating handled progression.
Workspace create mutation
apps/dashboard/lib/trpc/routers/workspace/create.ts
Wraps validation and workspace creation in a DB transaction; adds duplicate-slug check and throws TRPC CONFLICT on duplicate; creates tenant via authProvider.createTenant inside transaction; consolidates error handling and cache invalidation; final response now { orgId } (removed prior workspace/organizationId fields).

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant OC as OnboardingContent
  participant OW as OnboardingWizard (controlled)
  participant WS as useWorkspaceStep
  participant TRPC as trpc.workspace.create
  participant Auth as authProvider
  participant DB as Database

  U->>OW: Click "Next" (Workspace step)
  OW->>WS: call currentStep.onStepNext(currentStepIndex)
  WS->>TRPC: mutate({ name, slug, ... })
  TRPC->>DB: begin transaction
  TRPC->>DB: check existing workspace(s) & duplicate slug
  alt duplicate slug
    DB-->>TRPC: conflict
    TRPC-->>WS: throw CONFLICT
    WS-->>OW: return false (do not advance)
  else ok
    TRPC->>Auth: createTenant()
    TRPC->>DB: insert workspace
    TRPC-->>WS: { orgId }
    WS->>TRPC: switchOrg(orgId)
    WS->>OC: props.advance()
    OC->>OW: setCurrentStepIndex(next)
    WS-->>OW: return true
  end
Loading
sequenceDiagram
  autonumber
  participant U as User
  participant OW as OnboardingWizard (controlled)
  participant KS as useKeyCreationStep

  U->>OW: Click "Next" (Key creation)
  OW->>KS: call currentStep.onStepNext(currentStepIndex)
  alt not loading
    KS->>KS: submit form
    alt success
      KS->>OW: props.advance() -> setCurrentStepIndex(next)
      KS-->>OW: return true
    else failure
      KS-->>OW: return false
    end
  else loading
    KS-->>OW: return false
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

Bug

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The description includes clear sections for the change summary, type of change, testing instructions, and a completed checklist but omits the required “Fixes #” line under the summary heading, which is needed to link this PR to its corresponding issue for tracking. Please add a “Fixes #<issue_number>” line immediately after the summary in the “What does this PR do?” section to reference the issue being addressed and ensure proper tracking.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The pull request title accurately and concisely describes the primary change—handling duplicate workspace slugs during onboarding—using a clear imperative style and correctly omitting extraneous details or emojis.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 10-08-fix_handle_duplicate_workspace_slugs_in_onboarding

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

❤️ Share

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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)

103-108: Back button incorrectly disabled on last step

Users should be able to go back from the last step. Remove isLastStep from disabled condition.

Apply this diff:

           <Button
             className="rounded-lg bg-grayA-3 hover:bg-grayA-4 h-[22px]"
             variant="outline"
             onClick={handleBack}
-            disabled={isFirstStep || isLoading || isLastStep}
+            disabled={isFirstStep || isLoading}
           >
🧹 Nitpick comments (8)
apps/dashboard/app/new/hooks/use-key-creation-step.tsx (2)

50-60: Centralize advance in onSuccess (minor)

You can call props.advance() inside onSuccess and drop it from onSubmit to keep success-side effects in one place.

Apply this diff:

   const createApiAndKey = trpc.workspace.onboarding.useMutation({
     onSuccess: (data) => {
       setApiCreated(true);
       startTransition(() => {
         const params = new URLSearchParams(searchParams?.toString());
         params.set(API_ID_PARAM, data.apiId);
         params.set(KEY_PARAM, data.key);
         router.push(`?${params.toString()}`);
       });
+      // Move step progression here so it only fires on success
+      props.advance();
     },
@@
-      await createApiAndKey.mutateAsync(submitData);
-      props.advance();
+      await createApiAndKey.mutateAsync(submitData);

Also applies to: 99-101


235-241: Boolean returns from onStepNext are unused

OnboardingWizard doesn’t read the return value. Drop boolean returns to avoid confusion.

Apply this diff:

-    onStepNext: apiCreated
-      ? () => true
-      : () => {
-          if (!isLoading) {
-            formRef.current?.requestSubmit();
-          }
-          return false;
-        },
+    onStepNext: apiCreated
+      ? () => {}
+      : () => {
+          if (!isLoading) {
+            formRef.current?.requestSubmit();
+          }
+        },
apps/dashboard/lib/trpc/routers/workspace/create.ts (1)

112-118: Move cache invalidation outside the transaction

invalidateWorkspaceCache is an external side-effect; doing it inside the transaction can cause inconsistencies if the tx aborts.

Apply this diff and add invalidation after the transaction:

-        // Invalidate workspace cache for the new orgId and current user's orgId
-        // The new orgId needs invalidation for consistency (though it's new)
-        // The current user's orgId needs invalidation since they're switching away
-        await invalidateWorkspaceCache(orgId);
-        await invalidateWorkspaceCache(ctx.tenant.id);
-        return orgId;
+        return orgId;
       })
-      .catch((err) => {
+      .catch((err) => {
         if (err instanceof TRPCError) {
           throw err;
         }
         console.error(err);
         throw new TRPCError({
           code: "INTERNAL_SERVER_ERROR",
           message:
             "We are unable to create the workspace. Please try again or contact support@unkey.dev",
         });
       });
 
-    return {
-      orgId,
-    };
+    // Post-commit side effects
+    await Promise.all([
+      invalidateWorkspaceCache(orgId),
+      invalidateWorkspaceCache(ctx.tenant.id),
+    ]);
+    return { orgId };
apps/dashboard/app/new/components/onboarding-content.tsx (2)

16-24: Remove stepCount/useEffect; compute clamp from steps.length

You can avoid extra state and a render by deriving clamp directly from steps.length.

Apply this diff:

-  const [stepCount, setStepCount] = useState(0);
-
-  const handleStepChange = (newStepIndex: number) => {
+  const handleStepChange = (newStepIndex: number) => {
     setCurrentStepIndex(newStepIndex);
   };
-  const clamp = (i: number) => {
-    return Math.max(0, Math.min(stepCount - 1, i));
-  };
+  const clamp = (i: number, total: number) => Math.max(0, Math.min(total - 1, i));
@@
-  // stupid hack to get around the circular dependency
-  // we need the length of steps to determine the number of steps for boundary checking
-  useEffect(() => {
-    setStepCount(steps.length);
-  }, [steps.length]);
+  // No extra state needed; clamp uses steps.length at call sites

And update callers:

-  const workspaceStep = useWorkspaceStep({
-    advance: () => {
-      handleStepChange(clamp(currentStepIndex + 1));
-    },
-  });
+  const workspaceStep = useWorkspaceStep({
+    advance: () => handleStepChange(clamp(currentStepIndex + 1, steps.length)),
+  });
@@
-  const keyCreationStep = useKeyCreationStep({
-    advance: () => handleStepChange(clamp(currentStepIndex + 1)),
-  });
+  const keyCreationStep = useKeyCreationStep({
+    advance: () => handleStepChange(clamp(currentStepIndex + 1, steps.length)),
+  });

Also applies to: 55-60


45-48: Return value from onStepNext is unused

OnboardingWizard ignores boolean returns. Drop the return for clarity.

Apply this diff:

-      onStepNext: () => {
-        setIsConfirmOpen(true);
-        return true;
-      },
+      onStepNext: () => {
+        setIsConfirmOpen(true);
+      },
apps/dashboard/app/new/components/onboarding-wizard.tsx (2)

43-45: Update prop docs to match controlled API

Replace the stale “Callback fired whenever the current step changes” comment with descriptions for currentStepIndex and setCurrentStepIndex.

Apply this diff:

-  /** Callback fired whenever the current step changes */
-  currentStepIndex: number;
-  setCurrentStepIndex: (index: number) => void;
+  /** Zero-based index of the current step (controlled) */
+  currentStepIndex: number;
+  /** Setter to change the current step (controlled) */
+  setCurrentStepIndex: (index: number) => void;

73-74: Optional: support boolean return from onStepNext for compatibility

If onStepNext returns true, optionally advance to the next step to support mixed patterns during migration.

Apply this diff:

-    currentStep.onStepNext?.(currentStepIndex);
+    const res = currentStep.onStepNext?.(currentStepIndex);
+    if (res === true && currentStepIndex < steps.length - 1) {
+      setCurrentStepIndex(currentStepIndex + 1);
+    }

Also adjust the type if desired:

-  onStepNext?: (currentStep: number) => void;
+  onStepNext?: (currentStep: number) => boolean | void;
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)

75-79: Await router.refresh() before advancing or confirm non-blocking intent
The wizard advances immediately after mutateAsync, but switchOrgMutation.onSuccess calls router.refresh() without awaiting it. Since the next step doesn’t fetch workspace data, this won’t break functionality, but you may see a layout flicker. Consider sequencing it explicitly—e.g.:

await switchOrgMutation.mutateAsync(orgId);
await router.refresh();
props.advance();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9775d69 and 67113a7.

📒 Files selected for processing (6)
  • apps/dashboard/app/new/components/onboarding-content.tsx (4 hunks)
  • apps/dashboard/app/new/components/onboarding-fallback.tsx (1 hunks)
  • apps/dashboard/app/new/components/onboarding-wizard.tsx (2 hunks)
  • apps/dashboard/app/new/hooks/use-key-creation-step.tsx (3 hunks)
  • apps/dashboard/app/new/hooks/use-workspace-step.tsx (5 hunks)
  • apps/dashboard/lib/trpc/routers/workspace/create.ts (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
apps/dashboard/app/new/hooks/use-key-creation-step.tsx (1)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)
  • OnboardingStep (5-37)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)
  • OnboardingStep (5-37)
apps/dashboard/app/new/components/onboarding-content.tsx (3)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)
  • useWorkspaceStep (36-199)
apps/dashboard/app/new/hooks/use-key-creation-step.tsx (1)
  • useKeyCreationStep (43-244)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)
  • OnboardingWizard (47-184)
apps/dashboard/lib/trpc/routers/workspace/create.ts (4)
apps/dashboard/lib/db.ts (1)
  • db (5-26)
apps/dashboard/lib/env.ts (1)
  • env (3-52)
internal/db/src/schema/workspaces.ts (1)
  • workspaces (16-104)
internal/id/src/generate.ts (1)
  • newId (35-54)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Build / Build
🔇 Additional comments (7)
apps/dashboard/app/new/components/onboarding-fallback.tsx (1)

60-61: Controlled wiring looks good

Passing currentStepIndex and a no-op setter is appropriate for a static fallback.

apps/dashboard/app/new/hooks/use-key-creation-step.tsx (1)

39-44: Good API evolution: step-local advance callback

Switching the hook to accept an advance(): void prop aligns with the controlled wizard. No issues.

apps/dashboard/app/new/components/onboarding-content.tsx (1)

90-94: Controlled wizard wiring LGTM

Wiring steps + currentStepIndex/setCurrentStepIndex matches the new controlled model.

apps/dashboard/lib/trpc/routers/workspace/create.ts (1)

50-59: Map unique‐constraint violations to TRPC CONFLICT
Extend the existing .catch((err) => …) in apps/dashboard/lib/trpc/routers/workspace/create.ts (and similarly in changeWorkspaceName at lines 119–129) to inspect err.code (e.g. "ER_DUP_ENTRY") or /duplicate/i on err.message and rethrow

.catch((err: unknown & { code?: string; message?: string }) => {
  if (err instanceof TRPCError) throw err;
  const code = (err as any).code;
  const msg = String((err as any).message ?? "");
  if (code === "ER_DUP_ENTRY" || /duplicate/i.test(msg)) {
    throw new TRPCError({ code: "CONFLICT", message: "A workspace with this slug already exists." });
  }
  console.error(err);
  throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "We are unable to create the workspace. Please try again or contact support@unkey.dev" });
});

Verify the Planetscale/Drizzle driver’s duplicate‐error signature to ensure correct matching.

apps/dashboard/app/new/hooks/use-workspace-step.tsx (3)

31-36: LGTM! Clean API for controlled step progression.

The Props type and updated function signature clearly communicate the hook's dependency on a parent-controlled advance callback, aligning well with the PR's goal of preventing auto-advance.


102-104: LGTM! Excellent duplicate slug error handling.

The CONFLICT error handling provides clear feedback through both toast notification and inline field error with auto-focus, ensuring users understand and can easily correct the duplicate slug issue.


165-171: LGTM! Essential for clearing manual CONFLICT errors.

The form.clearErrors("slug") ensures that manually set CONFLICT errors are cleared when the user modifies the slug. Note that validation errors are automatically re-evaluated by react-hook-form due to mode: "onChange", so this primarily benefits the CONFLICT error case.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 8, 2025

Thank you for following the naming conventions for pull request titles! 🙏

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)

193-193: Remove debug console.info.

The debug console statement should be removed per the PR checklist. This was flagged in a previous review.

Apply this diff:

 onStepBack: () => {
-  console.info("Going back from workspace step");
+  // Navigation handled by parent component
 },
🧹 Nitpick comments (1)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)

165-168: Consider simplifying the comment.

The logic is correct—clearing errors when the user modifies the slug prevents stale validation messages. However, the comment could be more concise.

Apply this diff to simplify the comment:

 onChange={(evt) => {
-  // If we don't clear the manually set error, it will persist even if the user clears
-  // or changes the input
+  // Clear stale validation errors when user edits the slug
   form.clearErrors("slug");
   const v = evt.currentTarget.value;
   setSlugManuallyEdited(v.length > 0);
 }}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67113a7 and f03c44b.

📒 Files selected for processing (1)
  • apps/dashboard/app/new/hooks/use-workspace-step.tsx (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)
  • OnboardingStep (5-37)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Test Go API Local / Test
🔇 Additional comments (3)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (3)

31-36: LGTM! Props type and hook signature align with controlled navigation.

The addition of the Props type with an advance callback and the updated hook signature properly support the refactored controlled navigation pattern. This aligns well with the PR objective to prevent auto-advancement and manage step progression explicitly.


75-79: LGTM! Controlled navigation via props.advance().

The refactored onSuccess handler correctly uses the returned orgId, switches the organization context, and then explicitly calls props.advance() to proceed to the next step. This controlled approach prevents the auto-advancement issues mentioned in the PR objectives.


102-104: LGTM! Proper handling of duplicate workspace slugs.

The CONFLICT error branch correctly addresses the primary bug fix in this PR by displaying a toast notification and attaching the error message to the slug field with proper focus. This provides clear user feedback when attempting to create a workspace with a duplicate slug.

Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

Screen.Recording.2025-10-08.at.13.33.10.mov

We need this in apps/dashboard/app/new/hooks/use-workspace-step.tsx otherwise when you go back you are stuck

    onStepNext: () => {
      if (workspaceCreated) {
        props.advance(); // This one
      }
      if (!isLoading) {
        formRef.current?.requestSubmit();
      }
    },

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
apps/dashboard/app/new/components/onboarding-content.tsx (2)

21-28: Use functional state update for advance to avoid stale index

Avoid capturing currentStepIndex; use a functional updater and clamp. This prevents missed increments if multiple async advances occur and removes reliance on the steps closure.

Apply this diff:

-  const workspaceStep = useWorkspaceStep({
-    advance: () => {
-      handleStepChange(currentStepIndex + 1);
-    },
-  });
+  const workspaceStep = useWorkspaceStep({
+    advance: () => {
+      setCurrentStepIndex((i) => Math.min(i + 1, stepInfos.length - 1));
+    },
+  });
-  const keyCreationStep = useKeyCreationStep({
-    advance: () => handleStepChange(currentStepIndex + 1),
-  });
+  const keyCreationStep = useKeyCreationStep({
+    advance: () => setCurrentStepIndex((i) => Math.min(i + 1, stepInfos.length - 1)),
+  });

44-44: Remove no-op return

OnboardingWizard no longer uses onStepNext’s return value. Drop the unused return true for clarity.

-        setIsConfirmOpen(true);
-        return true;
+        setIsConfirmOpen(true);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3fbbf7c and d6ff756.

📒 Files selected for processing (1)
  • apps/dashboard/app/new/components/onboarding-content.tsx (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
apps/dashboard/app/new/components/onboarding-content.tsx (3)
apps/dashboard/app/new/hooks/use-workspace-step.tsx (1)
  • useWorkspaceStep (36-197)
apps/dashboard/app/new/hooks/use-key-creation-step.tsx (1)
  • useKeyCreationStep (43-244)
apps/dashboard/app/new/components/onboarding-wizard.tsx (1)
  • OnboardingWizard (47-184)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test API / API Test Local
  • GitHub Check: Build / Build
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
apps/dashboard/app/new/components/onboarding-content.tsx (2)

16-20: Bounded step setter looks good

Clear, explicit bounds check without extra state. No concerns.


81-85: Controlled wizard wiring LGTM; verify Back behavior

Props are correct. Note: OnboardingWizard disables the Back button on the last step (isLastStep). Confirm this UX is intentional; otherwise, remove that condition so users can go back from the success step.

Copy link
Contributor

@ogzhanolguncu ogzhanolguncu left a comment

Choose a reason for hiding this comment

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

I tested it with duplicated slug and it worked fine I wasn't stuck. LGTM

@mcstepp mcstepp self-assigned this Oct 10, 2025
Copy link
Collaborator

@mcstepp mcstepp left a comment

Choose a reason for hiding this comment

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

👍

@graphite-app
Copy link

graphite-app bot commented Oct 10, 2025

Video gif. A toddler sits at a table with a cracker in her hands. She looks at us with a big excited smile and then grins while giving a big thumbs up. Text, “Thank you!” (Added via Giphy)

@mcstepp mcstepp added this pull request to the merge queue Oct 10, 2025
github-merge-queue bot pushed a commit that referenced this pull request Oct 10, 2025
* fix: handle duplicate workspace slugs in onboarding

* revert: previous attempt to block advancing

* fix: allow advancing if you have gone back before

* chore: use a different hack
@graphite-app
Copy link

graphite-app bot commented Oct 10, 2025

Graphite Automations

"Post a GIF when PR approved" took an action on this PR • (10/10/25)

1 gif was posted to this PR based on Andreas Thomas's automation.

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 10, 2025
@chronark chronark added this pull request to the merge queue Oct 10, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 10, 2025
@chronark chronark added this pull request to the merge queue Oct 11, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Oct 11, 2025
@perkinsjr perkinsjr merged commit c764837 into main Oct 13, 2025
17 checks passed
@perkinsjr perkinsjr deleted the 10-08-fix_handle_duplicate_workspace_slugs_in_onboarding branch October 13, 2025 14:28
@coderabbitai coderabbitai bot mentioned this pull request Nov 12, 2025
18 tasks
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.

4 participants