Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
import type { RuntimeClientTarget } from '../../../../shared/runtime-client-target'
import { callAntigravityChatSignIn } from '@/runtime/runtime-antigravity-accounts-client'
import { AntigravityChatSignInRow } from './AntigravityChatSignInRow'
import { AntigravityProviderSignInArea } from './AntigravityProviderSignInArea'
import { TooltipProvider } from '../ui/tooltip'

const url = 'https://accounts.google.com/o/oauth2/v2/auth?state=s'
Expand Down Expand Up @@ -157,3 +158,40 @@ it('sends the address pasted from a browser on another computer to the host', as
callbackUrl: pasted
})
})

// A host learns its sign-in only when a chat starts, so after launch it has no answer to show.
it("names the account and why it's needed before the host knows its sign-in", async () => {
const owner = { kind: 'environment', environmentId: 'provider-unanswered' } as const
render(
<AntigravityProviderSignInArea
owner={owner}
label="this computer"
install={{
kind: 'active',
subject: { target: owner, runtimeId: null, agent: 'antigravity' },
removable: true,
snapshot: {
kind: 'known',
state: {
agent: 'antigravity',
revision: 1,
available: true,
version: '1.0.0',
installedVersion: '1.0.0',
installedCurrent: true,
source: 'managed',
operation: null
}
}
}}
/>
)
await act(async () => undefined)
expect(screen.getByText('Account')).toBeTruthy()
expect(screen.getByRole('status').textContent).toBe(
'Chats need an Antigravity sign-in, separate from your agy terminal account.'
)
expect(screen.getByRole('button', { name: 'Sign in' }).hasAttribute('disabled')).toBe(false)
await act(async () => publish(owner, null, 'signedOut'))
expect(screen.getByRole('status').textContent).toMatch(/^Not signed in\./)
})
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,13 @@ export function PastedAddressForm(props: {
}

/** One host's chat sign-in as both Settings layouts show it. `signedOut` is the line for a host
* that answered it is not signed in. */
* that answered it is not signed in; `unanswered` stands in while it has nothing else to say, as a
* host learns its sign-in only when a chat starts or asks to sign in. */
export function useAntigravityChatSignInControls(props: {
owner: RuntimeClientTarget
label: string
signedOut: string
unanswered?: string
disabled: boolean
}) {
const { owner, label } = props
Expand Down Expand Up @@ -235,7 +237,11 @@ export function useAntigravityChatSignInControls(props: {
/** The browser's link, while this client's sign-in waits on it. */
url: ownFlow && flow?.phase === 'waiting' ? (flow.url ?? null) : null,
line:
status === 'known' ? chatSignInLine(flow, auth, openFailed, label, props.signedOut) : null,
status === 'known'
? (chatSignInLine(flow, auth, openFailed, label, props.signedOut) ??
props.unanswered ??
null)
: null,
alert:
error ??
(status === 'readFailed' ? readFailed : null) ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,33 +38,42 @@ export function AntigravityProviderSignInArea(props: {
'settings.chat.providers.antigravityNotSignedIn',
'Not signed in. Chats need an Antigravity sign-in, separate from your agy terminal account.'
),
unanswered: translate(
'settings.chat.providers.antigravitySignInNeeded',
'Chats need an Antigravity sign-in, separate from your agy terminal account.'
),
disabled: antigravityChatSignInBlocked(props.install)
})
const { alert, copy, copyLabel, ownFlow, url } = signIn
// A settled failure says only why; a running sign-in keeps its step beside a copy failure.
const line = alert && !ownFlow ? null : signIn.line
return (
// Indented to the provider's name, past its icon.
<div className="ml-10 space-y-2 rounded-md bg-muted/40 px-3 py-2.5">
{/* The line keeps its height until the host answers, so nothing shifts when it does. */}
<div className="flex min-h-6 items-center gap-2">
<div
role="status"
className="flex min-w-0 flex-1 items-center gap-1.5 text-xs text-muted-foreground"
>
{ownFlow ? <LoadingSpinner className="size-3 shrink-0" /> : null}
<span className="min-w-0 break-words">
{line}
{line && alert ? ' ' : null}
{alert && (
<span role="alert" className="text-destructive">
{alert}
</span>
)}
</span>
<div className="ml-10 space-y-2">
<div className="flex items-center gap-3">
<div className="min-w-0 flex-1">
<p className="text-xs font-medium leading-none">
{translate('settings.chat.providers.antigravityAccount', 'Account')}
</p>
{/* The line keeps its height until the host answers, so nothing shifts when it does. */}
<div
role="status"
className="mt-1 flex min-h-4 items-center gap-1.5 text-xs text-muted-foreground"
>
{ownFlow ? <LoadingSpinner className="size-3 shrink-0" /> : null}
<span className="min-w-0 break-words">
{line}
{line && alert ? ' ' : null}
{alert && (
<span role="alert" className="text-destructive">
{alert}
</span>
)}
</span>
</div>
</div>
{ownFlow ? (
<>
<div className="flex shrink-0 items-center gap-1">
{url && (
<Button size="xs" variant="ghost" onClick={() => void copy.copyText()}>
{copy.status === 'copied' ? <Check /> : <Copy />}
Expand All @@ -74,12 +83,12 @@ export function AntigravityProviderSignInArea(props: {
<Button size="xs" variant="ghost" disabled={signIn.pending} onClick={signIn.cancel}>
{translate('accounts.antigravity.chatCancel', 'Cancel')}
</Button>
</>
</div>
) : (
<Button
size="xs"
// Signed in, the button only switches account, so it steps back from the primary.
variant={signIn.action === 'changeAccount' ? 'ghost' : 'default'}
// Signed in, the button only switches account, so it steps back further.
variant={signIn.action === 'changeAccount' ? 'ghost' : 'outline'}
disabled={signIn.signInDisabled}
onClick={signIn.start}
>
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@
"install": "Install",
"toggleLabel": "Open {{value0}} as a chat",
"antigravityDescription": "Antigravity chats run a server Orca downloads to this host, separate from the agy CLI.",
"antigravityNotSignedIn": "Not signed in. Chats need an Antigravity sign-in, separate from your agy terminal account."
"antigravityNotSignedIn": "Not signed in. Chats need an Antigravity sign-in, separate from your agy terminal account.",
"antigravityAccount": "Account",
"antigravitySignInNeeded": "Chats need an Antigravity sign-in, separate from your agy terminal account."
}
},
"terminal": {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"providers": {
"title": "Proveedores",
"antigravityDescription": "Los chats de Antigravity usan un servidor que Orca descarga en este host, independiente de la CLI de agy.",
"antigravityNotSignedIn": "No has iniciado sesión. Los chats necesitan un inicio de sesión de Antigravity, independiente de tu cuenta de agy en la terminal."
"antigravityNotSignedIn": "No has iniciado sesión. Los chats necesitan un inicio de sesión de Antigravity, independiente de tu cuenta de agy en la terminal.",
"antigravityAccount": "Cuenta",
"antigravitySignInNeeded": "Los chats necesitan un inicio de sesión de Antigravity, independiente de tu cuenta de agy en la terminal."
}
},
"terminal": {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@
"providers": {
"title": "Fournisseurs",
"antigravityDescription": "Les chats Antigravity utilisent un serveur qu’Orca télécharge sur cet hôte, distinct de la CLI agy.",
"antigravityNotSignedIn": "Non connecté. Les discussions nécessitent une connexion Antigravity, distincte de votre compte agy du terminal."
"antigravityNotSignedIn": "Non connecté. Les discussions nécessitent une connexion Antigravity, distincte de votre compte agy du terminal.",
"antigravityAccount": "Compte",
"antigravitySignInNeeded": "Les discussions nécessitent une connexion Antigravity, distincte de votre compte agy du terminal."
}
},
"terminal": {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"providers": {
"title": "プロバイダー",
"antigravityDescription": "Antigravity チャットは、Orca がこのホストにダウンロードするサーバーで動作します。agy CLI とは別です。",
"antigravityNotSignedIn": "サインインしていません。チャットには、ターミナルの agy アカウントとは別の Antigravity サインインが必要です。"
"antigravityNotSignedIn": "サインインしていません。チャットには、ターミナルの agy アカウントとは別の Antigravity サインインが必要です。",
"antigravityAccount": "アカウント",
"antigravitySignInNeeded": "チャットには、ターミナルの agy アカウントとは別の Antigravity サインインが必要です。"
}
},
"terminal": {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"providers": {
"title": "공급자",
"antigravityDescription": "Antigravity 채팅은 Orca가 이 호스트에 다운로드하는 서버에서 실행되며, agy CLI와는 별개입니다.",
"antigravityNotSignedIn": "로그인되어 있지 않습니다. 채팅에는 터미널 agy 계정과 별개인 Antigravity 로그인이 필요합니다."
"antigravityNotSignedIn": "로그인되어 있지 않습니다. 채팅에는 터미널 agy 계정과 별개인 Antigravity 로그인이 필요합니다.",
"antigravityAccount": "계정",
"antigravitySignInNeeded": "채팅에는 터미널 agy 계정과 별개인 Antigravity 로그인이 필요합니다."
}
},
"terminal": {
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/src/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@
"providers": {
"title": "提供方",
"antigravityDescription": "Antigravity 聊天运行在 Orca 下载到此主机的服务器上,与 agy CLI 相互独立。",
"antigravityNotSignedIn": "未登录。聊天需要单独的 Antigravity 登录,与终端中的 agy 帐户分开。"
"antigravityNotSignedIn": "未登录。聊天需要单独的 Antigravity 登录,与终端中的 agy 帐户分开。",
"antigravityAccount": "账户",
"antigravitySignInNeeded": "聊天需要单独的 Antigravity 登录,与终端中的 agy 帐户分开。"
}
},
"terminal": {
Expand Down
Loading