mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-24 21:41:08 +02:00
fix(x): add Sign in with ChatGPT to onboarding LLM setup
Onboarding's LLM step predates ChatGPT-subscription support, so the option was reachable in the composer and Settings but missing from first-run setup. Mirrors Settings exactly: when the OpenAI provider card is selected, the ChatGPT subscription sign-in block renders directly under the OpenAI API-key field (gated on llmProvider === "openai", same as settings-dialog.tsx), reusing the existing useChatGPT hook / chatgpt:* IPC — a nested block, NOT a standalone provider card. ChatGPT never enters the LlmProviderFlavor union, so the BYOK config/save machinery is untouched. Signing in counts as a connected provider (chatgpt.status.signedIn) so Continue unlocks with no API key, and the block shows the same three-state UI (Sign In / Waiting / Connected + Sign Out) as Settings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
40e450f0ae
commit
ca399561da
2 changed files with 68 additions and 2 deletions
|
|
@ -39,9 +39,14 @@ export function LlmSetupStep({ state }: LlmSetupStepProps) {
|
|||
updateProviderConfig, handleTestAndSaveLlmConfig, handleTestAndAddAnother,
|
||||
connectedFlavors, handleNext, handleBack,
|
||||
upsellDismissed, setUpsellDismissed, handleSwitchToRowboat,
|
||||
chatgpt,
|
||||
} = state
|
||||
|
||||
const isMoreProvider = moreProviders.some(p => p.id === llmProvider)
|
||||
// "Sign in with ChatGPT" (below the OpenAI card) is an alternative to a key:
|
||||
// signing in counts as a connected provider alongside any saved BYOK one,
|
||||
// which is what unlocks Continue when no API key was entered.
|
||||
const hasConnectedProvider = connectedFlavors.size > 0 || chatgpt.status.signedIn
|
||||
// Connect-only, mirroring Settings: entering a key (or base URL) is enough
|
||||
// and the model is resolved silently at save. openai-compatible is the sole
|
||||
// exception with a visible Model field — its /models endpoint often doesn't
|
||||
|
|
@ -188,6 +193,56 @@ export function LlmSetupStep({ state }: LlmSetupStepProps) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* ChatGPT subscription — OAuth sign-in shown under the OpenAI card,
|
||||
mirroring Settings (settings-dialog.tsx, gated on provider ===
|
||||
"openai"). Alternative to an API key: signs in via the shared
|
||||
chatgpt:* path, independent of models.json (the Codex model client
|
||||
consumes the token in core). */}
|
||||
{llmProvider === "openai" && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
ChatGPT Subscription
|
||||
</label>
|
||||
{chatgpt.status.signedIn ? (
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-1.5 text-sm text-green-600 dark:text-green-400 min-w-0">
|
||||
<CheckCircle2 className="size-4 shrink-0" />
|
||||
<span className="truncate">
|
||||
Connected as {chatgpt.status.email ?? "your ChatGPT account"}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="shrink-0 border-destructive/40 text-destructive hover:bg-destructive/10 hover:text-destructive"
|
||||
onClick={chatgpt.signOut}
|
||||
>
|
||||
Sign Out
|
||||
</Button>
|
||||
</div>
|
||||
) : chatgpt.isSigningIn ? (
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
<Loader2 className="size-4 animate-spin" />
|
||||
Waiting for browser…
|
||||
</div>
|
||||
<Button variant="outline" size="sm" className="shrink-0" onClick={chatgpt.cancelSignIn}>
|
||||
Cancel
|
||||
</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Use your ChatGPT Plus/Pro subscription
|
||||
</span>
|
||||
<Button variant="outline" size="sm" className="shrink-0" onClick={chatgpt.signIn}>
|
||||
Sign In
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{showBaseURL && (
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-medium text-muted-foreground">
|
||||
|
|
@ -241,12 +296,12 @@ export function LlmSetupStep({ state }: LlmSetupStepProps) {
|
|||
</Button>
|
||||
<Button
|
||||
onClick={canTest ? handleTestAndSaveLlmConfig : handleNext}
|
||||
disabled={testState.status === "testing" || (!canTest && connectedFlavors.size === 0)}
|
||||
disabled={testState.status === "testing" || (!canTest && !hasConnectedProvider)}
|
||||
className="min-w-[140px]"
|
||||
>
|
||||
{testState.status === "testing" ? (
|
||||
<><Loader2 className="size-4 animate-spin mr-2" />Testing...</>
|
||||
) : (canTest || connectedFlavors.size === 0) ? (
|
||||
) : (canTest || !hasConnectedProvider) ? (
|
||||
"Test & Continue"
|
||||
) : (
|
||||
"Continue"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { useState, useEffect, useCallback } from "react"
|
||||
import { setGoogleCredentials } from "@/lib/google-credentials-store"
|
||||
import { useChatGPT } from "@/hooks/useChatGPT"
|
||||
import { toast } from "sonner"
|
||||
|
||||
export interface ProviderState {
|
||||
|
|
@ -44,6 +45,13 @@ export function useOnboardingState(open: boolean, onComplete: (opts?: { startTou
|
|||
const [connectedFlavors, setConnectedFlavors] = useState<Set<LlmProviderFlavor>>(new Set())
|
||||
const [showMoreProviders, setShowMoreProviders] = useState(false)
|
||||
|
||||
// "Sign in with ChatGPT" (subscription OAuth) is offered below the OpenAI
|
||||
// card, mirroring Settings. It isn't a LlmProviderFlavor — no API key, no
|
||||
// models.json entry — it signs in via the dedicated chatgpt:* IPC (same
|
||||
// path Settings uses) and the Codex model client consumes the token in
|
||||
// core, leaving the BYOK config machinery untouched.
|
||||
const chatgpt = useChatGPT()
|
||||
|
||||
// OAuth provider states
|
||||
const [providers, setProviders] = useState<string[]>([])
|
||||
const [providersLoading, setProvidersLoading] = useState(true)
|
||||
|
|
@ -705,6 +713,9 @@ export function useOnboardingState(open: boolean, onComplete: (opts?: { startTou
|
|||
handleTestAndSaveLlmConfig,
|
||||
handleTestAndAddAnother,
|
||||
|
||||
// ChatGPT subscription sign-in (shown below the OpenAI card)
|
||||
chatgpt,
|
||||
|
||||
// OAuth state
|
||||
providers,
|
||||
providersLoading,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue