({ slug }: { slug: string })
| 455 | | { phase: "error"; message: string }; |
| 456 | |
| 457 | function ConnectStep({ slug }: { slug: string }) { |
| 458 | const router = useRouter(); |
| 459 | const [view, setView] = useState<ConnectStepStateView>({ phase: "loading" }); |
| 460 | const [tileBusy, setTileBusy] = useState<string | null>(null); |
| 461 | const [advancing, setAdvancing] = useState(false); |
| 462 | const connectionsHref = projectHref(slug, "/connections"); |
| 463 | |
| 464 | useEffect(() => { |
| 465 | let cancelled = false; |
| 466 | (async () => { |
| 467 | const result = await getConnectStepStateAction(slug); |
| 468 | if (cancelled) return; |
| 469 | if (!result.ok) { |
| 470 | setView({ phase: "error", message: result.error }); |
| 471 | return; |
| 472 | } |
| 473 | setView({ phase: "loaded", state: result.state }); |
| 474 | })(); |
| 475 | return () => { |
| 476 | cancelled = true; |
| 477 | }; |
| 478 | }, [slug]); |
| 479 | |
| 480 | async function onConnectTile(tile: RecommendedTile) { |
| 481 | setTileBusy(tile.mcp_key); |
| 482 | try { |
| 483 | const result = await startMcpConnect({ |
| 484 | mcp_key: tile.mcp_key, |
| 485 | // After OAuth lands, route through the matching account-picker |
| 486 | // step. That step auto-skips if the bearer covers a single |
| 487 | // account/property; otherwise it shows a picker. Both paths |
| 488 | // ultimately redirect back to /onboarding?step=connect so the |
| 489 | // user can continue adding tools. |
| 490 | return_to: `/onboarding?step=${tile.account_step}&slug=${encodeURIComponent(slug)}`, |
| 491 | }); |
| 492 | if (!result.ok) { |
| 493 | toast.error(result.error); |
| 494 | setTileBusy(null); |
| 495 | return; |
| 496 | } |
| 497 | window.location.href = result.authorize_url; |
| 498 | } catch (err) { |
| 499 | toast.error(err instanceof Error ? err.message : String(err)); |
| 500 | setTileBusy(null); |
| 501 | } |
| 502 | } |
| 503 | |
| 504 | function onPickAccount(tile: RecommendedTile) { |
| 505 | router.push( |
| 506 | `/onboarding?step=${tile.account_step}&slug=${encodeURIComponent(slug)}`, |
| 507 | ); |
| 508 | } |
| 509 | |
| 510 | async function onDone() { |
| 511 | setAdvancing(true); |
| 512 | // The setup step waits for ensureProjectAgents (CMO + any specialists |
| 513 | // provisioned by the connect-time hooks) and only then routes the user |
| 514 | // into the CMO task workspace. Going through it instead of the direct |
nothing calls this directly
no test coverage detected