mirror of
https://github.com/stablyai/orca.git
synced 2026-09-27 16:02:35 +00:00
feat(codex): remove "Not now" from account-switch notice (#9613)
* feat(codex): drop "Not now" collapse from account-switch notice The Codex account-switch overlay had a "Not now" button that collapsed the loud dialog into a corner chip via component-local state. Remove the button and all of its collapse state: the useState/useEffect, the CollapsedRestartChip, and the now-dead collapse helpers. buildCodexRestartNoticeKey still backs the focus effect, so the module is renamed codex-restart-overlay-collapse.ts -> codex-restart-notice-key.ts and its tests trimmed to match. The orphaned "Not now" i18n key is pruned from all locale catalogs. * test(codex): lock restart notice actions
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useId, useMemo, useRef, useState } from 'react'
|
||||
import { useEffect, useId, useMemo, useRef } from 'react'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { RefreshCw } from 'lucide-react'
|
||||
import { Button } from '@/components/ui/button'
|
||||
@@ -6,11 +6,7 @@ import { useAppStore } from '../store'
|
||||
import { selectCodexRestartInputs } from './codex-restart-chip-inputs'
|
||||
import { translate } from '@/i18n/i18n'
|
||||
import { shouldFocusMobileDriverAction } from './terminal-pane/mobile-driver-overlay-focus'
|
||||
import {
|
||||
buildCodexRestartNoticeKey,
|
||||
createCodexRestartOverlayCollapseState,
|
||||
getCodexRestartOverlayCollapseState
|
||||
} from './codex-restart-overlay-collapse'
|
||||
import { buildCodexRestartNoticeKey } from './codex-restart-notice-key'
|
||||
|
||||
const EMPTY_TABS: { id: string }[] = []
|
||||
|
||||
@@ -99,16 +95,6 @@ export default function CodexRestartChip({
|
||||
const clearCodexRestartNotice = useAppStore((s) => s.clearCodexRestartNotice)
|
||||
|
||||
const noticeKey = restartNotice ? buildCodexRestartNoticeKey(restartNotice) : null
|
||||
const [collapseState, setCollapseState] = useState(() =>
|
||||
createCodexRestartOverlayCollapseState(noticeKey)
|
||||
)
|
||||
|
||||
const currentCollapseState = getCodexRestartOverlayCollapseState(collapseState, noticeKey)
|
||||
useEffect(() => {
|
||||
// Why: a new account switch must reopen loud mode without updating state
|
||||
// during render, which can trip React's external-store snapshot guard.
|
||||
setCollapseState((state) => getCodexRestartOverlayCollapseState(state, noticeKey))
|
||||
}, [noticeKey])
|
||||
|
||||
if (staleWorktreePtyIds.length === 0 || !restartNotice) {
|
||||
return null
|
||||
@@ -122,22 +108,11 @@ export default function CodexRestartChip({
|
||||
dismissStaleWorktreePtyIds(staleWorktreePtyIds, clearCodexRestartNotice)
|
||||
}
|
||||
|
||||
if (currentCollapseState.collapsed) {
|
||||
return (
|
||||
<CollapsedRestartChip
|
||||
restartNotice={restartNotice}
|
||||
onExpand={() => setCollapseState(createCodexRestartOverlayCollapseState(noticeKey))}
|
||||
onRestart={handleRestart}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<LoudRestartOverlay
|
||||
isVisible={isVisible}
|
||||
noticeKey={noticeKey}
|
||||
restartNotice={restartNotice}
|
||||
onCollapse={() => setCollapseState({ noticeKey, collapsed: true })}
|
||||
onDismiss={handleDismiss}
|
||||
onRestart={handleRestart}
|
||||
/>
|
||||
@@ -148,14 +123,12 @@ function LoudRestartOverlay({
|
||||
isVisible,
|
||||
noticeKey,
|
||||
restartNotice,
|
||||
onCollapse,
|
||||
onDismiss,
|
||||
onRestart
|
||||
}: {
|
||||
isVisible: boolean
|
||||
noticeKey: string | null
|
||||
restartNotice: RestartNotice
|
||||
onCollapse: () => void
|
||||
onDismiss: () => void
|
||||
onRestart: () => void
|
||||
}): React.JSX.Element {
|
||||
@@ -218,9 +191,6 @@ function LoudRestartOverlay({
|
||||
<Button type="button" variant="outline" size="sm" onClick={onDismiss}>
|
||||
{translate('auto.components.CodexRestartChip.6133594b12', 'Keep old account')}
|
||||
</Button>
|
||||
<Button type="button" variant="outline" size="sm" onClick={onCollapse}>
|
||||
{translate('auto.components.CodexRestartChip.b9000fe511', 'Not now')}
|
||||
</Button>
|
||||
<Button ref={restartRef} type="button" variant="default" size="sm" onClick={onRestart}>
|
||||
<RefreshCw />
|
||||
{translate('auto.components.CodexRestartChip.c72a5fb234', 'Restart')}
|
||||
@@ -230,41 +200,3 @@ function LoudRestartOverlay({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function CollapsedRestartChip({
|
||||
restartNotice,
|
||||
onExpand,
|
||||
onRestart
|
||||
}: {
|
||||
restartNotice: RestartNotice
|
||||
onExpand: () => void
|
||||
onRestart: () => void
|
||||
}): React.JSX.Element {
|
||||
return (
|
||||
<div
|
||||
className="absolute right-2 top-2 z-50 flex max-w-[min(100%-1rem,24rem)] items-center gap-1.5 rounded-full border border-border bg-card px-2 py-1 text-xs font-medium text-card-foreground shadow-xs"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
<RefreshCw className="size-3 shrink-0 text-foreground" aria-hidden="true" />
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="xs"
|
||||
className="min-w-0 max-w-[10rem] px-1 font-medium"
|
||||
onClick={onExpand}
|
||||
>
|
||||
<span className="truncate">
|
||||
{translate(
|
||||
'auto.components.CodexRestartChip.a4c8e1b2f7',
|
||||
'Codex is still signed in as {{value0}}',
|
||||
{ value0: restartNotice.previousAccountLabel }
|
||||
)}
|
||||
</span>
|
||||
</Button>
|
||||
<Button type="button" variant="default" size="xs" onClick={onRestart}>
|
||||
{translate('auto.components.CodexRestartChip.c72a5fb234', 'Restart')}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('CodexRestartChip helpers', () => {
|
||||
expect(clearCodexRestartNotice).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('renders a stale Codex restart notice without an external-store update loop', async () => {
|
||||
it('renders only account-resolution actions without an external-store update loop', async () => {
|
||||
useAppStore.setState({
|
||||
tabsByWorktree: {
|
||||
'worktree-1': [
|
||||
@@ -124,5 +124,8 @@ describe('CodexRestartChip helpers', () => {
|
||||
})
|
||||
|
||||
expect(container.textContent).toContain('Codex is still signed in as old@example.com')
|
||||
expect(
|
||||
Array.from(container.querySelectorAll('button'), (button) => button.textContent?.trim())
|
||||
).toEqual(['Keep old account', 'Restart'])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { buildCodexRestartNoticeKey } from './codex-restart-notice-key'
|
||||
|
||||
describe('codex restart notice key', () => {
|
||||
it('builds a stable notice key from account labels', () => {
|
||||
expect(
|
||||
buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account B'
|
||||
})
|
||||
).toBe('Account A\u0000Account B')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
export function buildCodexRestartNoticeKey(args: {
|
||||
previousAccountLabel: string
|
||||
nextAccountLabel: string
|
||||
}): string {
|
||||
return `${args.previousAccountLabel}\u0000${args.nextAccountLabel}`
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
buildCodexRestartNoticeKey,
|
||||
createCodexRestartOverlayCollapseState,
|
||||
getCodexRestartOverlayCollapseState
|
||||
} from './codex-restart-overlay-collapse'
|
||||
|
||||
describe('codex restart overlay collapse', () => {
|
||||
it('builds a stable notice key from account labels', () => {
|
||||
expect(
|
||||
buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account B'
|
||||
})
|
||||
).toBe('Account A\u0000Account B')
|
||||
})
|
||||
|
||||
it('reopens loud mode when the notice key changes', () => {
|
||||
const collapsed = {
|
||||
noticeKey: buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account B'
|
||||
}),
|
||||
collapsed: true
|
||||
}
|
||||
|
||||
expect(
|
||||
getCodexRestartOverlayCollapseState(
|
||||
collapsed,
|
||||
buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account C'
|
||||
})
|
||||
)
|
||||
).toEqual({
|
||||
noticeKey: 'Account A\u0000Account C',
|
||||
collapsed: false
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves collapse state for the same notice key', () => {
|
||||
const noticeKey = buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account B'
|
||||
})
|
||||
const collapsed = { noticeKey, collapsed: true }
|
||||
|
||||
expect(getCodexRestartOverlayCollapseState(collapsed, noticeKey)).toBe(collapsed)
|
||||
})
|
||||
|
||||
it('creates loud mode for a new notice key', () => {
|
||||
const noticeKey = buildCodexRestartNoticeKey({
|
||||
previousAccountLabel: 'Account A',
|
||||
nextAccountLabel: 'Account B'
|
||||
})
|
||||
|
||||
expect(createCodexRestartOverlayCollapseState(noticeKey)).toEqual({
|
||||
noticeKey,
|
||||
collapsed: false
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,32 +0,0 @@
|
||||
export type CodexRestartOverlayCollapseState = {
|
||||
noticeKey: string | null
|
||||
collapsed: boolean
|
||||
}
|
||||
|
||||
export function buildCodexRestartNoticeKey(args: {
|
||||
previousAccountLabel: string
|
||||
nextAccountLabel: string
|
||||
}): string {
|
||||
return `${args.previousAccountLabel}\u0000${args.nextAccountLabel}`
|
||||
}
|
||||
|
||||
export function getCodexRestartOverlayCollapseState(
|
||||
state: CodexRestartOverlayCollapseState,
|
||||
noticeKey: string | null
|
||||
): CodexRestartOverlayCollapseState {
|
||||
return state.noticeKey === noticeKey
|
||||
? state
|
||||
: {
|
||||
noticeKey,
|
||||
collapsed: false
|
||||
}
|
||||
}
|
||||
|
||||
export function createCodexRestartOverlayCollapseState(
|
||||
noticeKey: string | null
|
||||
): CodexRestartOverlayCollapseState {
|
||||
return {
|
||||
noticeKey,
|
||||
collapsed: false
|
||||
}
|
||||
}
|
||||
@@ -769,8 +769,7 @@
|
||||
"9263e75f49": "Codex is using the previous account",
|
||||
"d3e8a1f4b2": "Account switched",
|
||||
"9375620cc3": "Restart this session to use {{value0}}. It stays on the previous account until you do.",
|
||||
"6133594b12": "Keep old account",
|
||||
"b9000fe511": "Not now"
|
||||
"6133594b12": "Keep old account"
|
||||
},
|
||||
"FirstLaunchBanner": {
|
||||
"b9e1b966c7": "Dismiss notice",
|
||||
|
||||
@@ -746,8 +746,7 @@
|
||||
"a4c8e1b2f7": "Codex sigue conectado como {{value0}}",
|
||||
"d3e8a1f4b2": "Cuenta cambiada",
|
||||
"9375620cc3": "Restart this session to use {{value0}}. It stays on the previous account until you do.",
|
||||
"6133594b12": "Keep old account",
|
||||
"b9000fe511": "Not now"
|
||||
"6133594b12": "Keep old account"
|
||||
},
|
||||
"FirstLaunchBanner": {
|
||||
"b9e1b966c7": "Descartar aviso",
|
||||
|
||||
@@ -746,8 +746,7 @@
|
||||
"a4c8e1b2f7": "Codex はまだ {{value0}} としてサインインしています",
|
||||
"d3e8a1f4b2": "アカウントを切り替えました",
|
||||
"9375620cc3": "Restart this session to use {{value0}}. It stays on the previous account until you do.",
|
||||
"6133594b12": "Keep old account",
|
||||
"b9000fe511": "Not now"
|
||||
"6133594b12": "Keep old account"
|
||||
},
|
||||
"FirstLaunchBanner": {
|
||||
"b9e1b966c7": "通知を閉じる",
|
||||
|
||||
@@ -746,8 +746,7 @@
|
||||
"a4c8e1b2f7": "Codex가 아직 {{value0}} 계정으로 로그인되어 있습니다",
|
||||
"d3e8a1f4b2": "계정 전환됨",
|
||||
"9375620cc3": "Restart this session to use {{value0}}. It stays on the previous account until you do.",
|
||||
"6133594b12": "Keep old account",
|
||||
"b9000fe511": "Not now"
|
||||
"6133594b12": "Keep old account"
|
||||
},
|
||||
"FirstLaunchBanner": {
|
||||
"b9e1b966c7": "알림 닫기",
|
||||
|
||||
@@ -746,8 +746,7 @@
|
||||
"a4c8e1b2f7": "Codex 仍以 {{value0}} 身份登录",
|
||||
"d3e8a1f4b2": "账户已切换",
|
||||
"9375620cc3": "Restart this session to use {{value0}}. It stays on the previous account until you do.",
|
||||
"6133594b12": "Keep old account",
|
||||
"b9000fe511": "Not now"
|
||||
"6133594b12": "Keep old account"
|
||||
},
|
||||
"FirstLaunchBanner": {
|
||||
"b9e1b966c7": "关闭通知",
|
||||
|
||||
Reference in New Issue
Block a user