From d9f78ad490ccff3bab4138ef9d4dbbadfde88611 Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sat, 4 Apr 2026 00:04:59 -0400 Subject: [PATCH] refactor(accounts): consolidate continuity guidance layout - replace separate readiness and learning cards with one continuity overview surface - simplify row labels and dialog controls around continuity mode changes - keep localized continuity guidance aligned with the new component structure Refs #904 --- ui/src/components/account/accounts-table.tsx | 55 ++-- .../account/continuity-overview.tsx | 238 ++++++++++++++++++ .../account/continuity-readiness-card.tsx | 140 ----------- .../account/edit-account-context-dialog.tsx | 184 +++++++++----- .../account/history-sync-learning-map.tsx | 202 --------------- ui/src/lib/i18n.ts | 17 +- ui/src/pages/accounts.tsx | 82 +----- .../unit/ui/i18n/language-switcher.test.tsx | 82 ++---- 8 files changed, 432 insertions(+), 568 deletions(-) create mode 100644 ui/src/components/account/continuity-overview.tsx delete mode 100644 ui/src/components/account/continuity-readiness-card.tsx delete mode 100644 ui/src/components/account/history-sync-learning-map.tsx diff --git a/ui/src/components/account/accounts-table.tsx b/ui/src/components/account/accounts-table.tsx index 300a1bb5..42eeb02a 100644 --- a/ui/src/components/account/accounts-table.tsx +++ b/ui/src/components/account/accounts-table.tsx @@ -14,6 +14,7 @@ import { TableRow, } from '@/components/ui/table'; import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; import { AlertDialog, AlertDialogAction, @@ -105,31 +106,39 @@ export function AccountsTable({ data, defaultAccount, groupSummaries }: Accounts const mode = row.original.context_mode || 'isolated'; if (mode === 'shared') { const group = row.original.context_group || 'default'; - const mainLabel = - row.original.continuity_mode === 'deeper' - ? t('accountsTable.sharedGroupDeeper', { group }) - : row.original.continuity_inferred - ? t('accountsTable.sharedGroupLegacy', { group }) - : t('accountsTable.sharedGroupStandard', { group }); - const peerLabel = - row.original.sameGroupPeerCount > 0 - ? t('accountsTable.sameGroupPeerCount', { count: row.original.sameGroupPeerCount }) - : t('accountsTable.noSameGroupPeer'); + const isDeeper = row.original.continuity_mode === 'deeper'; return ( -
-

{mainLabel}

-

{peerLabel}

+
+
+ + {isDeeper ? 'Deeper' : 'Shared'} + + {group} +
+

+ {row.original.sameGroupPeerCount > 0 + ? t('accountsTable.sameGroupPeerCount', { + count: row.original.sameGroupPeerCount, + }) + : t('accountsTable.noSameGroupPeer')} +

); } if (row.original.context_inferred) { return ( -
-

- {t('accountsTable.isolatedLegacy')} -

-

+

+ + Legacy + +

{t('accountsTable.legacyReview')}

@@ -137,9 +146,13 @@ export function AccountsTable({ data, defaultAccount, groupSummaries }: Accounts } return ( -
-

{t('accountsTable.isolated')}

-

{t('accountsTable.noHandoff')}

+
+ + Isolated +
); }, diff --git a/ui/src/components/account/continuity-overview.tsx b/ui/src/components/account/continuity-overview.tsx new file mode 100644 index 00000000..89a1df93 --- /dev/null +++ b/ui/src/components/account/continuity-overview.tsx @@ -0,0 +1,238 @@ +import { + AlertTriangle, + CheckCircle2, + Info, + Link2, + ShieldAlert, + Unlink, + Waves, + ArrowRight, +} from 'lucide-react'; +import { useTranslation } from 'react-i18next'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; + +interface ContinuityOverviewProps { + totalAccounts: number; + isolatedCount: number; + sharedStandardCount: number; + deeperSharedCount: number; + sharedAloneCount: number; + sharedPeerAccountCount: number; // The accounts in a viable group + deeperReadyAccountCount: number; + sharedGroups: string[]; + sharedPeerGroups: string[]; + deeperReadyGroups: string[]; + legacyTargetCount: number; + cliproxyCount: number; +} + +type ReadinessState = + | 'single' + | 'isolated' + | 'shared-alone' + | 'shared-standard' + | 'partial' + | 'ready'; + +const InfoTooltip = ({ titleKey, descKey }: { titleKey: string; descKey: string }) => { + const { t } = useTranslation(); + return ( + + + + + +

{t(titleKey)}

+

{t(descKey)}

+
+
+ ); +}; + +export function ContinuityOverview({ + totalAccounts, + isolatedCount, + sharedStandardCount, + deeperSharedCount, + sharedAloneCount, + sharedPeerAccountCount, + deeperReadyAccountCount, + sharedPeerGroups, + deeperReadyGroups, + legacyTargetCount, + cliproxyCount, +}: ContinuityOverviewProps) { + const { t } = useTranslation(); + + const readiness: ReadinessState = + totalAccounts < 2 + ? 'single' + : sharedPeerGroups.length === 0 + ? isolatedCount === totalAccounts + ? 'isolated' + : 'shared-alone' + : deeperReadyGroups.length === 0 + ? 'shared-standard' + : isolatedCount > 0 || + sharedAloneCount > 0 || + deeperReadyAccountCount < sharedPeerAccountCount || + deeperReadyGroups.length < sharedPeerGroups.length + ? 'partial' + : 'ready'; + + const highlightGroup = deeperReadyGroups[0] || sharedPeerGroups[0] || 'default'; + const hasMixedState = + deeperReadyGroups.length > 0 && + (isolatedCount > 0 || + sharedStandardCount > 0 || + sharedPeerGroups.length > deeperReadyGroups.length); + + const iconMap = { + ready: , + 'shared-standard': , + single: , + isolated: , + 'shared-alone': , + partial: , + }; + + const currentIcon = iconMap[readiness]; + + return ( +
+ {/* Primary Status Bento Box */} + + +
+
+
+ {currentIcon} +
+
+
+

+ {t(`continuityReadiness.messages.${readiness}.title`, { + group: highlightGroup, + })} +

+ + {t(`continuityReadiness.state.${readiness}`)} + +
+

+ {t(`continuityReadiness.messages.${readiness}.description`, { + group: highlightGroup, + count: sharedAloneCount, + })} +

+
+
+
+ +
+ {cliproxyCount > 0 && ( + + {t('historySyncLearningMap.cliproxyManaged', { count: cliproxyCount })} + + )} + {legacyTargetCount > 0 && ( + + {t('historySyncLearningMap.legacyConfirmation', { count: legacyTargetCount })} + + )} + {sharedPeerGroups.length > 0 && deeperReadyGroups.length === 0 && ( + + Recommend: {highlightGroup} + + )} + {hasMixedState && ( + + Partial sync ({highlightGroup}) + + )} +
+
+
+ + {/* Horizontal Progression Chain */} +
+
+
+ + + {t('historySyncLearningMap.isolated')} + + +
+ + {isolatedCount} + +
+ + + +
+
+ + + {t('historySyncLearningMap.shared')} + + +
+ + {sharedStandardCount} + +
+ + + +
+
+ + + {t('historySyncLearningMap.deeper')} + + +
+ + {deeperSharedCount} + +
+
+
+ ); +} diff --git a/ui/src/components/account/continuity-readiness-card.tsx b/ui/src/components/account/continuity-readiness-card.tsx deleted file mode 100644 index 2cd029e5..00000000 --- a/ui/src/components/account/continuity-readiness-card.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { AlertTriangle, CheckCircle2, Link2, ShieldAlert } from 'lucide-react'; -import { useTranslation } from 'react-i18next'; -import { Badge } from '@/components/ui/badge'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; - -interface ContinuityReadinessCardProps { - totalAccounts: number; - isolatedCount: number; - sharedAloneCount: number; - sharedPeerAccountCount: number; - deeperReadyAccountCount: number; - sharedPeerGroups: string[]; - deeperReadyGroups: string[]; -} - -type ReadinessState = - | 'single' - | 'isolated' - | 'shared-alone' - | 'shared-standard' - | 'partial' - | 'ready'; - -export function ContinuityReadinessCard({ - totalAccounts, - isolatedCount, - sharedAloneCount, - sharedPeerAccountCount, - deeperReadyAccountCount, - sharedPeerGroups, - deeperReadyGroups, -}: ContinuityReadinessCardProps) { - const { t } = useTranslation(); - - const readiness: ReadinessState = - totalAccounts < 2 - ? 'single' - : sharedPeerGroups.length === 0 - ? isolatedCount === totalAccounts - ? 'isolated' - : 'shared-alone' - : deeperReadyGroups.length === 0 - ? 'shared-standard' - : isolatedCount > 0 || - sharedAloneCount > 0 || - deeperReadyAccountCount < sharedPeerAccountCount || - deeperReadyGroups.length < sharedPeerGroups.length - ? 'partial' - : 'ready'; - - const highlightGroup = deeperReadyGroups[0] || sharedPeerGroups[0] || 'default'; - const icon = - readiness === 'ready' ? ( - - ) : readiness === 'shared-standard' ? ( - - ) : readiness === 'single' ? ( - - ) : ( - - ); - const stepItems = - readiness === 'single' - ? [ - t('continuityReadiness.singleSteps.addAccount'), - t('continuityReadiness.singleSteps.sameGroupLater'), - t('continuityReadiness.singleSteps.enableDeeperLater'), - t('continuityReadiness.singleSteps.resumeOriginal'), - ] - : [ - t('continuityReadiness.steps.syncBoth'), - t('continuityReadiness.steps.sameGroup', { group: highlightGroup }), - t('continuityReadiness.steps.enableDeeper'), - t('continuityReadiness.steps.resumeOriginal'), - ]; - - return ( - - -
-
- {t('continuityReadiness.title')} - {t('continuityReadiness.description')} -
- - {t(`continuityReadiness.state.${readiness}`)} - -
-
- -
-
-

- {t('continuityReadiness.metrics.isolated')} -

-

{isolatedCount}

-
-
-

- {t('continuityReadiness.metrics.sharedPeers')} -

-

{sharedPeerAccountCount}

-
-
-

- {t('continuityReadiness.metrics.deeperReady')} -

-

{deeperReadyAccountCount}

-
-
- -
-
-
{icon}
-
-

- {t(`continuityReadiness.messages.${readiness}.title`, { group: highlightGroup })} -

-

- {t(`continuityReadiness.messages.${readiness}.description`, { - group: highlightGroup, - count: sharedAloneCount, - })} -

-
-
-
- -
-

{t('continuityReadiness.stepsTitle')}

-
    - {stepItems.map((item) => ( -
  1. {item}
  2. - ))} -
-
-
-
- ); -} diff --git a/ui/src/components/account/edit-account-context-dialog.tsx b/ui/src/components/account/edit-account-context-dialog.tsx index b10b9538..b4dc2aaf 100644 --- a/ui/src/components/account/edit-account-context-dialog.tsx +++ b/ui/src/components/account/edit-account-context-dialog.tsx @@ -10,13 +10,8 @@ import { import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from '@/components/ui/select'; + +import { Unlink, Link2, Waves, ShieldAlert, Info } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import type { AuthAccountRow, SharedGroupSummary } from '@/lib/account-continuity'; import { useUpdateAccountContext } from '@/hooks/use-accounts'; @@ -117,20 +112,47 @@ export function EditAccountContextDialog({
- - -

- {mode === 'shared' - ? t('editAccountContext.sharedModeHint') - : t('editAccountContext.isolatedModeHint')} +

+ +
+
+ + +
+

+ {mode === 'isolated' + ? t('editAccountContext.isolatedModeHint') + : t('editAccountContext.sharedModeHint')}

@@ -155,23 +177,49 @@ export function EditAccountContextDialog({ {mode === 'shared' && (
- - -

- {continuityMode === 'deeper' - ? t('editAccountContext.deeperHint') - : t('editAccountContext.standardHint')} + + +

+

+ {continuityMode === 'standard' + ? t('editAccountContext.standardHint') + : t('editAccountContext.deeperHint')}

)} @@ -180,33 +228,51 @@ export function EditAccountContextDialog({ {t('editAccountContext.credentialsIsolated')}

-
-

- {t('editAccountContext.implicationTitle')} -

-
+
+
{mode === 'isolated' ? ( -

{t('editAccountContext.isolatedImplication')}

+ ) : ( - <> -

{t('editAccountContext.sameGroupRule', { group: normalizedGroup })}

-

- {sameGroupPeerCount > 0 - ? t('editAccountContext.sameGroupPeerCount', { count: sameGroupPeerCount }) - : t('editAccountContext.noSameGroupPeer')} + + )} +

+ {mode === 'isolated' ? ( +

+ {t('editAccountContext.isolatedImplication')}

-

- {continuityMode === 'deeper' - ? sameGroupDeeperPeerCount > 0 - ? t('editAccountContext.deeperReady', { + ) : ( + <> +

+ + {t('editAccountContext.sameGroupRule', { group: normalizedGroup })} + {' '} + {sameGroupPeerCount > 0 + ? t('editAccountContext.sameGroupPeerCount', { count: sameGroupPeerCount }) + : t('editAccountContext.noSameGroupPeer')} +

+ {continuityMode === 'deeper' && ( +

+ {sameGroupDeeperPeerCount > 0 ? ( + t('editAccountContext.deeperReady', { count: sameGroupDeeperPeerCount, }) - : t('editAccountContext.deeperNeedsPeers') - : t('editAccountContext.standardWarning')} -

- - )} -

{t('editAccountContext.resumeOriginalWarning')}

+ ) : ( + + {t('editAccountContext.deeperNeedsPeers')} + + )} +

+ )} + + )} +

+ {t('editAccountContext.resumeOriginalWarning')} +

+
diff --git a/ui/src/components/account/history-sync-learning-map.tsx b/ui/src/components/account/history-sync-learning-map.tsx deleted file mode 100644 index 50071c02..00000000 --- a/ui/src/components/account/history-sync-learning-map.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { useState } from 'react'; -import { - ArrowRight, - ArrowRightLeft, - ChevronDown, - Layers3, - Link2, - Unlink, - Waves, - type LucideIcon, -} from 'lucide-react'; -import { Badge } from '@/components/ui/badge'; -import { Button } from '@/components/ui/button'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; -import { useTranslation } from 'react-i18next'; -import { cn } from '@/lib/utils'; - -interface HistorySyncLearningMapProps { - isolatedCount: number; - sharedStandardCount: number; - deeperSharedCount: number; - sharedGroups: string[]; - sharedPeerGroups: string[]; - deeperReadyGroups: string[]; - legacyTargetCount: number; - cliproxyCount: number; -} - -type StageTone = 'isolated' | 'shared' | 'deeper'; - -function StageTile({ - title, - count, - icon: Icon, - tone, -}: { - title: string; - count: number; - icon: LucideIcon; - tone: StageTone; -}) { - const toneClasses: Record = { - isolated: { - border: 'border-blue-300/60 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10', - icon: 'text-blue-700 dark:text-blue-400', - count: 'text-blue-700 dark:text-blue-400', - }, - shared: { - border: - 'border-emerald-300/60 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10', - icon: 'text-emerald-700 dark:text-emerald-400', - count: 'text-emerald-700 dark:text-emerald-400', - }, - deeper: { - border: - 'border-indigo-300/60 bg-indigo-50/40 dark:border-indigo-900/40 dark:bg-indigo-900/10', - icon: 'text-indigo-700 dark:text-indigo-400', - count: 'text-indigo-700 dark:text-indigo-400', - }, - }; - - return ( -
-
-

{title}

- -
-

{count}

-
- ); -} - -export function HistorySyncLearningMap({ - isolatedCount, - sharedStandardCount, - deeperSharedCount, - sharedGroups, - sharedPeerGroups, - deeperReadyGroups, - legacyTargetCount, - cliproxyCount, -}: HistorySyncLearningMapProps) { - const { t } = useTranslation(); - const [open, setOpen] = useState(false); - const groupsToShow = sharedGroups.length > 0 ? sharedGroups : ['default']; - const highlightGroup = deeperReadyGroups[0] || sharedPeerGroups[0] || groupsToShow[0]; - const hasMixedState = - deeperReadyGroups.length > 0 && - (isolatedCount > 0 || - sharedStandardCount > 0 || - sharedPeerGroups.length > deeperReadyGroups.length); - - return ( - - -
-
- {t('historySyncLearningMap.title')} - - {t('historySyncLearningMap.description')} - -
- {t('historySyncLearningMap.learningMap')} -
-
- - - {cliproxyCount > 0 && ( -
- {t('historySyncLearningMap.cliproxyManaged', { count: cliproxyCount })} -
- )} - -
- -
- -
- -
- -
- -
- -
- {sharedPeerGroups.length === 0 - ? t('historySyncLearningMap.sameGroupRule') - : deeperReadyGroups.length === 0 - ? t('historySyncLearningMap.deeperRecommendation', { group: highlightGroup }) - : hasMixedState - ? t('historySyncLearningMap.partialGroup', { group: highlightGroup }) - : t('historySyncLearningMap.readyGroup', { group: highlightGroup })} -
- - - - - - -
-
-
- -

{t('historySyncLearningMap.modeSwitch')}

-
-

- {t('historySyncLearningMap.modeSwitchDesc')} -

-
- -
-
- -

{t('historySyncLearningMap.historySyncGroup')}

-
-

- {t('historySyncLearningMap.historySyncGroupDesc')} -

-
- {groupsToShow.map((group) => ( - - {group} - - ))} -
-
-
- - {legacyTargetCount > 0 && ( -
- {t('historySyncLearningMap.legacyConfirmation', { count: legacyTargetCount })} -
- )} -
-
-
-
- ); -} diff --git a/ui/src/lib/i18n.ts b/ui/src/lib/i18n.ts index e9bdc9c6..f4cd1e01 100644 --- a/ui/src/lib/i18n.ts +++ b/ui/src/lib/i18n.ts @@ -401,12 +401,10 @@ const resources = { 'Configure how "{{name}}" shares history and continuity with other ccs auth accounts.', syncMode: 'Sync Mode', selectContextMode: 'Select context mode', - isolatedOption: 'isolated (no sync)', - sharedOption: 'shared (sync enabled)', - sharedModeHint: - 'Shared mode reuses workspace context for accounts in the same history sync group.', - isolatedModeHint: - 'Isolated mode keeps this account fully separate from other ccs auth accounts.', + isolatedOption: 'Isolated', + sharedOption: 'Shared', + sharedModeHint: 'Reuses workspace context across accounts in the same history group.', + isolatedModeHint: 'Keeps this account fully separate from other ccs auth accounts.', historySyncGroup: 'History Sync Group', groupPlaceholder: 'default', groupHint: @@ -414,10 +412,9 @@ const resources = { invalidGroup: 'Enter a valid group name that starts with a letter.', continuityDepth: 'Continuity Depth', selectContinuityDepth: 'Select continuity depth', - standardOption: 'standard (projects only)', - deeperOption: 'deeper continuity (advanced)', - deeperHint: - 'Advanced mode also syncs session-env, file-history, shell-snapshots, and todos.', + standardOption: 'Standard', + deeperOption: 'Deeper', + deeperHint: 'Syncs comprehensive session-env, file-history, shell-snapshots, and todos.', standardHint: 'Standard mode syncs project workspace context only.', credentialsIsolated: 'Credentials and .anthropic remain isolated per account in all modes.', implicationTitle: 'What this means after save', diff --git a/ui/src/pages/accounts.tsx b/ui/src/pages/accounts.tsx index c649f611..ddcad6db 100644 --- a/ui/src/pages/accounts.tsx +++ b/ui/src/pages/accounts.tsx @@ -5,19 +5,16 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { AlertTriangle, ArrowRight, ChevronDown, Plus, Users, Zap } from 'lucide-react'; +import { AlertTriangle, ArrowRight, Plus, Users, Zap } from 'lucide-react'; import { AccountsTable } from '@/components/account/accounts-table'; -import { ContinuityReadinessCard } from '@/components/account/continuity-readiness-card'; +import { ContinuityOverview } from '@/components/account/continuity-overview'; import { CreateAuthProfileDialog } from '@/components/account/create-auth-profile-dialog'; -import { HistorySyncLearningMap } from '@/components/account/history-sync-learning-map'; import { CopyButton } from '@/components/ui/copy-button'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'; import { ScrollArea } from '@/components/ui/scroll-area'; import { useAccounts, useConfirmLegacyAccountPolicies } from '@/hooks/use-accounts'; -import { cn } from '@/lib/utils'; import { useTranslation } from 'react-i18next'; export function AccountsPage() { @@ -26,7 +23,6 @@ export function AccountsPage() { const { data, isLoading } = useAccounts(); const confirmLegacyMutation = useConfirmLegacyAccountPolicies(); const [createDialogOpen, setCreateDialogOpen] = useState(false); - const [guideOpen, setGuideOpen] = useState(false); const authAccounts = data?.accounts || []; const cliproxyCount = data?.cliproxyCount || 0; @@ -146,50 +142,6 @@ export function AccountsPage() {
)} - - - - - - - - - -
-

- {t('accountsPage.sharedStandard')} -

-

{t('accountsPage.sharedStandardDesc')}

-
-
-

- {t('accountsPage.sharedDeeper')} -

-

{t('accountsPage.sharedDeeperDesc')}

-
-
-

- {t('accountsPage.isolated')} -

-

{t('accountsPage.isolatedDesc')}

-
-
-
-
-
- {t('accountsPage.quickCommands')} @@ -235,20 +187,14 @@ export function AccountsPage() {
- - - - - - {t('accountsPage.accountMatrix')} diff --git a/ui/tests/unit/ui/i18n/language-switcher.test.tsx b/ui/tests/unit/ui/i18n/language-switcher.test.tsx index 84be5f7e..d8618b21 100644 --- a/ui/tests/unit/ui/i18n/language-switcher.test.tsx +++ b/ui/tests/unit/ui/i18n/language-switcher.test.tsx @@ -1,9 +1,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { render, screen, userEvent, waitFor } from '@tests/setup/test-utils'; import i18n from '@/lib/i18n'; -import { ContinuityReadinessCard } from '@/components/account/continuity-readiness-card'; +import { ContinuityOverview } from '@/components/account/continuity-overview'; import { LanguageSwitcher } from '@/components/layout/language-switcher'; -import { HistorySyncLearningMap } from '@/components/account/history-sync-learning-map'; import { TabNavigation } from '@/pages/settings/components/tab-navigation'; import { getInitialLocale, @@ -138,97 +137,50 @@ describe('Dashboard i18n', () => { expect(screen.getByText('思考')).toBeInTheDocument(); }); - it('renders Japanese history sync guidance without fallback English copy', async () => { - await i18n.changeLanguage('ja'); - - render( - - ); - - expect(screen.getByText('履歴同期の仕組み')).toBeInTheDocument(); - expect( - screen.getByText( - 'グループ「default」は良い状態ですが、他のアカウントやグループでは同グループ設定や拡張継続性がまだ不足しています。' - ) - ).toBeInTheDocument(); - expect( - screen.getByText('1 件の CLIProxy Claude Pool アカウントは、CLIProxy ページで管理します。') - ).toBeInTheDocument(); - - await userEvent.click( - screen.getByRole('button', { name: '詳細を表示: グループ、切り替え、レガシーポリシー' }) - ); - - expect( - screen.getByText('2 件のレガシーアカウントで明示的な確認がまだ必要です。') - ).toBeInTheDocument(); - }); - - it('renders Japanese continuity readiness card without fallback English copy', async () => { - await i18n.changeLanguage('ja'); - - render( - - ); - - expect(screen.getByText('アカウント間再開チェック')).toBeInTheDocument(); - expect(screen.getByText('現在、アカウント間再開はオフです。')).toBeInTheDocument(); - }); - - it('uses single-account-specific next steps in the readiness card', async () => { + it('uses single-account-specific next steps in the continuity overview', async () => { await i18n.changeLanguage('en'); render( - ); expect( screen.getByText( - 'Create a second ccs auth account before planning any cross-account handoff.' + 'Cross-account handoff does not apply yet. Add another auth account before configuring shared continuity.' ) ).toBeInTheDocument(); - expect( - screen.queryByText('Open Sync on both accounts, not just the one you are switching into.') - ).not.toBeInTheDocument(); }); it('pluralizes the shared-alone readiness copy', async () => { await i18n.changeLanguage('en'); render( - ); @@ -237,9 +189,9 @@ describe('Dashboard i18n', () => { ).toBeInTheDocument(); }); - it.each(SUPPORTED_LOCALES.filter((locale) => locale !== 'en'))( + it.each(SUPPORTED_LOCALES.filter((locale: string) => locale !== 'en'))( 'keeps %s translation keys in parity with en and preserves placeholders', - (locale) => { + (locale: string) => { const resources = i18n.options.resources as | Record }> | undefined;