mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-09 06:15:21 +02:00
Takes the four tenant onboarding steps to the design, and makes the model choice explicit. **Nothing is preselected on the connect step.** It arrived with a source already chosen, which made the row read as a confirmation rather than a question and let a customer pass the step having touched none of it. The step now opens unanswered and cannot advance until a source is selected in the visible row. Two defects fell out of that, both found by Greptile in review: - A saved draft can name an adapter the row does not show — one the registry dropped, or one in the advanced list. The gate asked `sourcePicked`, which only means "a draft named something", so Next stayed live on a step that had visibly asked nothing and would hire against the hidden name. It now asks `sourceSelected`, read off the visible row, and the snap that replaces an unofferable adapter clears the pick rather than presenting its replacement as chosen. - Cmd+Enter bypassed that gate entirely, because the condition was written out twice and drifted. Both paths now ask one predicate. Also: selection is a fill rather than a border; the input canvas opens only for a chosen source; the close control is gone from every step (nothing downstream of the connect step works until a model is connected); the arc draws to the design's 424px column with a filled 44px name field; the CTA reads "Next" through the arc and "Get started" at the end; the login spinner reads "Preparing..."; the OAuth panels number their fields and show the URL above the code. Storybook: the arc stories waited for a button named "Connect" and had been silently rendering the wrong step since the CTA was renamed. They now wait on the destination heading. Three e2e specs had the same fault and now select a source before advancing. One test was removed rather than replaced — `hydrates again when the same company comes back through onboarding` drove the close control, and three substitutes each passed against a wizard with the behaviour deleted. The reason is recorded where it stood. Known and not fixed here: SidebarCompanyMenu opens the wizard at step 1 for "create a new organization", and with no exit an existing user who changes their mind is trapped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
72 lines
2.9 KiB
TypeScript
72 lines
2.9 KiB
TypeScript
import { ONBOARDING_STORAGE_KEY } from "@/components/OnboardingWizard";
|
|
|
|
/**
|
|
* The onboarding draft, as the wizard stories need to write it.
|
|
*
|
|
* `localStorage` is per-origin, so every story in a Storybook session shares
|
|
* one. A story that seeds a draft and walks away leaves it for the next one:
|
|
* the wizard restores a saved step ahead of whatever step that story asked for,
|
|
* and the reviewer gets a screen they did not click on. So seeding and clearing
|
|
* are a pair, and they live here rather than inline so the pairing is testable.
|
|
*
|
|
* The key is imported rather than restated. It is the wizard's, and a second
|
|
* copy of a storage key is a bug waiting for the first one to be renamed.
|
|
*/
|
|
|
|
export const STORYBOOK_COMPANY_ID = "company-storybook";
|
|
export const STORYBOOK_AGENT_ID = "agent-storybook";
|
|
|
|
/** Where the agent arc begins. Every story in it enters here — see below. */
|
|
export const ONBOARDING_ARC_ENTRY_STEP = 3;
|
|
|
|
/**
|
|
* The draft a run holds when it arrives at the agent arc.
|
|
*
|
|
* It seeds the *entry* step and nothing further on purpose. The wizard offers
|
|
* Back only on a step it walked forward into — `currentStep > entryStep`, and
|
|
* `entryStep` is captured once at mount from this very draft — so a story that
|
|
* seeds step 4 or 5 directly renders those steps permanently without their Back
|
|
* button. Stories that want a later step click their way to it instead.
|
|
*
|
|
* `createdAgentId` is therefore absent rather than seeded: the hire happens for
|
|
* real, through the fixtured route, which is also what keeps step 5's
|
|
* `launchStateIncomplete` guard honest instead of painted over.
|
|
*/
|
|
export function seedOnboardingDraft(): void {
|
|
window.localStorage.setItem(
|
|
ONBOARDING_STORAGE_KEY,
|
|
JSON.stringify({
|
|
step: ONBOARDING_ARC_ENTRY_STEP,
|
|
companyName: "Paperclip Storybook",
|
|
agentName: "Darnold",
|
|
agentRole: "general",
|
|
// No `adapterType`. This draft describes a run standing on step 3, and a
|
|
// run that has not reached the connect step cannot have chosen a source
|
|
// there — seeding one made every arc story arrive with Claude Code already
|
|
// picked, which is precisely the preselection the step was changed to stop
|
|
// doing. Stories that need a source pick one, the way a customer does.
|
|
//
|
|
// (It read `claude_code` before that, which is no adapter at all: the step
|
|
// recovered by falling back, and the hire would have posted a type the
|
|
// server does not know.)
|
|
createdCompanyId: STORYBOOK_COMPANY_ID,
|
|
createdCompanyPrefix: "PAP",
|
|
createdAgentId: "",
|
|
}),
|
|
);
|
|
}
|
|
|
|
export function clearOnboardingDraft(): void {
|
|
window.localStorage.removeItem(ONBOARDING_STORAGE_KEY);
|
|
}
|
|
|
|
export function readOnboardingDraft(): Record<string, unknown> | null {
|
|
const raw = window.localStorage.getItem(ONBOARDING_STORAGE_KEY);
|
|
if (raw === null) return null;
|
|
try {
|
|
return JSON.parse(raw) as Record<string, unknown>;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|