mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 10:16:49 +00:00
fix(accounts-ui): condense sync guidance and remove redundant controls
This commit is contained in:
@@ -24,7 +24,7 @@ import {
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { Check, CheckCheck, Link2, Pencil, RotateCcw, Trash2, Unlink } from 'lucide-react';
|
||||
import { Check, CheckCheck, Pencil, RotateCcw, Trash2 } from 'lucide-react';
|
||||
import { EditAccountContextDialog } from '@/components/account/edit-account-context-dialog';
|
||||
import {
|
||||
useSetDefaultAccount,
|
||||
@@ -137,51 +137,22 @@ export function AccountsTable({ data, defaultAccount }: AccountsTableProps) {
|
||||
deleteMutation.isPending ||
|
||||
updateContextMutation.isPending;
|
||||
const isCliproxy = row.original.type === 'cliproxy';
|
||||
const isShared = row.original.context_mode === 'shared';
|
||||
const hasLegacyInference =
|
||||
row.original.context_inferred || row.original.continuity_inferred;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-1">
|
||||
{!isCliproxy && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-8 px-2"
|
||||
disabled={isPending}
|
||||
onClick={() => setContextTarget(row.original)}
|
||||
title="Edit context mode"
|
||||
>
|
||||
<Pencil className="w-4 h-4" />
|
||||
</Button>
|
||||
)}
|
||||
{!isCliproxy && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-8 px-2"
|
||||
disabled={isPending}
|
||||
onClick={() =>
|
||||
updateContextMutation.mutate({
|
||||
name: row.original.name,
|
||||
context_mode: isShared ? 'isolated' : 'shared',
|
||||
context_group: isShared ? undefined : row.original.context_group || 'default',
|
||||
continuity_mode: isShared ? undefined : 'standard',
|
||||
})
|
||||
}
|
||||
title={isShared ? 'Switch to isolated mode' : 'Switch to shared mode'}
|
||||
onClick={() => setContextTarget(row.original)}
|
||||
title="Edit sync mode, group, and continuity depth"
|
||||
>
|
||||
{isShared ? (
|
||||
<>
|
||||
<Unlink className="w-3 h-3 mr-1" />
|
||||
Unlink
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Link2 className="w-3 h-3 mr-1" />
|
||||
Link
|
||||
</>
|
||||
)}
|
||||
<Pencil className="w-3.5 h-3.5 mr-1" />
|
||||
Sync
|
||||
</Button>
|
||||
)}
|
||||
{!isCliproxy && hasLegacyInference && (
|
||||
@@ -270,7 +241,7 @@ export function AccountsTable({ data, defaultAccount }: AccountsTableProps) {
|
||||
created: 'w-[150px]',
|
||||
last_used: 'w-[150px]',
|
||||
context: 'w-[170px]',
|
||||
actions: 'w-[340px]',
|
||||
actions: 'w-[290px]',
|
||||
}[header.id] || 'w-auto';
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
ArrowRight,
|
||||
ArrowRightLeft,
|
||||
ChevronDown,
|
||||
Layers3,
|
||||
Link2,
|
||||
Unlink,
|
||||
@@ -8,7 +10,9 @@ import {
|
||||
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 { cn } from '@/lib/utils';
|
||||
|
||||
interface HistorySyncLearningMapProps {
|
||||
@@ -17,51 +21,49 @@ interface HistorySyncLearningMapProps {
|
||||
deeperSharedCount: number;
|
||||
sharedGroups: string[];
|
||||
legacyTargetCount: number;
|
||||
cliproxyCount: number;
|
||||
}
|
||||
|
||||
type StageTone = 'isolated' | 'shared' | 'deeper';
|
||||
|
||||
function StageCard({
|
||||
function StageTile({
|
||||
title,
|
||||
count,
|
||||
icon: Icon,
|
||||
tone,
|
||||
description,
|
||||
}: {
|
||||
title: string;
|
||||
count: number;
|
||||
icon: LucideIcon;
|
||||
tone: StageTone;
|
||||
description: string;
|
||||
}) {
|
||||
const toneClasses: Record<StageTone, { card: string; icon: string; count: string }> = {
|
||||
const toneClasses: Record<StageTone, { border: string; icon: string; count: string }> = {
|
||||
isolated: {
|
||||
card: 'border-blue-300/60 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10',
|
||||
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: {
|
||||
card: 'border-emerald-300/60 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10',
|
||||
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: {
|
||||
card: 'border-indigo-300/60 bg-indigo-50/40 dark:border-indigo-900/40 dark:bg-indigo-900/10',
|
||||
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 (
|
||||
<div className={cn('rounded-md border p-3', toneClasses[tone].card)}>
|
||||
<div className={cn('rounded-md border p-2.5', toneClasses[tone].border)}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<p className="text-sm font-semibold">{title}</p>
|
||||
<Icon className={cn('h-4 w-4', toneClasses[tone].icon)} />
|
||||
<p className="text-xs font-semibold">{title}</p>
|
||||
<Icon className={cn('h-3.5 w-3.5', toneClasses[tone].icon)} />
|
||||
</div>
|
||||
<p className={cn('mt-1 text-2xl font-mono font-semibold', toneClasses[tone].count)}>
|
||||
{count}
|
||||
</p>
|
||||
<p className="mt-1 text-xs text-muted-foreground">{description}</p>
|
||||
<p className={cn('mt-1 text-lg font-mono font-semibold', toneClasses[tone].count)}>{count}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -72,91 +74,93 @@ export function HistorySyncLearningMap({
|
||||
deeperSharedCount,
|
||||
sharedGroups,
|
||||
legacyTargetCount,
|
||||
cliproxyCount,
|
||||
}: HistorySyncLearningMapProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const groupsToShow = sharedGroups.length > 0 ? sharedGroups : ['default'];
|
||||
|
||||
return (
|
||||
<Card className="border-dashed">
|
||||
<CardHeader className="pb-3">
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<CardTitle className="text-base">How History Sync Works</CardTitle>
|
||||
<div>
|
||||
<CardTitle className="text-base">How History Sync Works</CardTitle>
|
||||
<CardDescription className="mt-1">
|
||||
Isolated -> Shared -> Deeper. Use <code>Sync</code> per row for all changes.
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Badge variant="outline">Learning Map</Badge>
|
||||
</div>
|
||||
<CardDescription>
|
||||
Accounts can move between modes at any time. Link/unlink is instant; Edit gives full
|
||||
control of group and continuity depth.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-3 lg:grid-cols-[1fr_auto_1fr_auto_1fr] lg:items-center">
|
||||
<StageCard
|
||||
title="Isolated"
|
||||
count={isolatedCount}
|
||||
icon={Unlink}
|
||||
tone="isolated"
|
||||
description="No shared history with other accounts."
|
||||
/>
|
||||
<div className="hidden lg:flex justify-center text-muted-foreground">
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</div>
|
||||
<StageCard
|
||||
title="Shared (Standard)"
|
||||
count={sharedStandardCount}
|
||||
icon={Link2}
|
||||
tone="shared"
|
||||
description="Shared project context only."
|
||||
/>
|
||||
<div className="hidden lg:flex justify-center text-muted-foreground">
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</div>
|
||||
<StageCard
|
||||
title="Shared (Deeper)"
|
||||
count={deeperSharedCount}
|
||||
icon={Waves}
|
||||
tone="deeper"
|
||||
description="Adds continuity data: session-env/file-history/todos/shell-snapshots."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 lg:grid-cols-2">
|
||||
<div className="rounded-md border bg-muted/20 p-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<ArrowRightLeft className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-semibold">Mode Switch Actions</p>
|
||||
</div>
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
<Badge variant="secondary">Link: Isolated -> Shared</Badge>
|
||||
<Badge variant="secondary">Unlink: Shared -> Isolated</Badge>
|
||||
<Badge variant="secondary">Edit: Group + Deeper</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border bg-muted/20 p-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Layers3 className="h-4 w-4 text-muted-foreground" />
|
||||
<p className="text-sm font-semibold">History Sync Group</p>
|
||||
</div>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Accounts in the same group share the same project context bucket. Group names are
|
||||
user-defined lanes, with <code>default</code> as fallback.
|
||||
</p>
|
||||
<div className="mt-2 flex flex-wrap gap-2">
|
||||
{groupsToShow.map((group) => (
|
||||
<Badge key={group} variant="outline" className="font-mono text-[11px]">
|
||||
{group}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{legacyTargetCount > 0 && (
|
||||
<div className="rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:text-amber-300">
|
||||
{legacyTargetCount} legacy account
|
||||
{legacyTargetCount > 1 ? 's still need' : ' still needs'} explicit confirmation. Use{' '}
|
||||
<strong>Confirm Legacy Policies</strong> in Action Center.
|
||||
<CardContent className="space-y-3">
|
||||
{cliproxyCount > 0 && (
|
||||
<div className="rounded-md border border-blue-300/60 bg-blue-50/40 px-3 py-2 text-xs text-blue-800 dark:border-blue-900/40 dark:bg-blue-900/10 dark:text-blue-300">
|
||||
{cliproxyCount} CLIProxy Claude pool account{cliproxyCount > 1 ? 's are' : ' is'}
|
||||
managed in Action Center / CLIProxy page.
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="grid gap-2 sm:grid-cols-[1fr_auto_1fr_auto_1fr] sm:items-center">
|
||||
<StageTile title="Isolated" count={isolatedCount} icon={Unlink} tone="isolated" />
|
||||
<div className="hidden sm:flex justify-center text-muted-foreground">
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</div>
|
||||
<StageTile title="Shared" count={sharedStandardCount} icon={Link2} tone="shared" />
|
||||
<div className="hidden sm:flex justify-center text-muted-foreground">
|
||||
<ArrowRight className="h-4 w-4" />
|
||||
</div>
|
||||
<StageTile title="Deeper" count={deeperSharedCount} icon={Waves} tone="deeper" />
|
||||
</div>
|
||||
|
||||
<Collapsible open={open} onOpenChange={setOpen}>
|
||||
<CollapsibleTrigger asChild>
|
||||
<Button variant="ghost" className="h-auto w-full justify-between px-0 py-0 text-xs">
|
||||
<span className="text-muted-foreground">
|
||||
Show details: groups, switching, and legacy policy
|
||||
</span>
|
||||
<ChevronDown className={cn('h-4 w-4 transition-transform', open && 'rotate-180')} />
|
||||
</Button>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="pt-2">
|
||||
<div className="grid gap-2 lg:grid-cols-2">
|
||||
<div className="rounded-md border bg-muted/20 p-2.5 text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<ArrowRightLeft className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<p className="font-semibold">Mode Switch</p>
|
||||
</div>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Sync dialog lets users move between isolated/shared and choose deeper continuity.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="rounded-md border bg-muted/20 p-2.5 text-xs">
|
||||
<div className="flex items-center gap-2">
|
||||
<Layers3 className="h-3.5 w-3.5 text-muted-foreground" />
|
||||
<p className="font-semibold">History Sync Group</p>
|
||||
</div>
|
||||
<p className="mt-1 text-muted-foreground">
|
||||
Same group means shared project context lane. Default fallback is{' '}
|
||||
<code>default</code>.
|
||||
</p>
|
||||
<div className="mt-2 flex flex-wrap gap-1.5">
|
||||
{groupsToShow.map((group) => (
|
||||
<Badge key={group} variant="outline" className="font-mono text-[10px]">
|
||||
{group}
|
||||
</Badge>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{legacyTargetCount > 0 && (
|
||||
<div className="mt-2 rounded-md border border-amber-500/50 bg-amber-500/10 px-3 py-2 text-xs text-amber-800 dark:text-amber-300">
|
||||
{legacyTargetCount} legacy account
|
||||
{legacyTargetCount > 1 ? 's still need' : ' still needs'} explicit confirmation.
|
||||
</div>
|
||||
)}
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
|
||||
+19
-142
@@ -10,11 +10,8 @@ import {
|
||||
ArrowRight,
|
||||
ChevronDown,
|
||||
ChevronLeft,
|
||||
Link2,
|
||||
Plus,
|
||||
Unlink,
|
||||
Users,
|
||||
Waves,
|
||||
Zap,
|
||||
} from 'lucide-react';
|
||||
import { AccountsTable } from '@/components/account/accounts-table';
|
||||
@@ -23,82 +20,11 @@ import { HistorySyncLearningMap } from '@/components/account/history-sync-learni
|
||||
import { CopyButton } from '@/components/ui/copy-button';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
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 type { LucideIcon } from 'lucide-react';
|
||||
|
||||
type MetricTone = 'default' | 'shared' | 'deeper' | 'isolated';
|
||||
|
||||
function MetricTile({
|
||||
label,
|
||||
value,
|
||||
icon: Icon,
|
||||
tone = 'default',
|
||||
}: {
|
||||
label: string;
|
||||
value: number;
|
||||
icon: LucideIcon;
|
||||
tone?: MetricTone;
|
||||
}) {
|
||||
const toneClasses: Record<MetricTone, { border: string; icon: string }> = {
|
||||
default: {
|
||||
border: 'border-border',
|
||||
icon: 'text-primary',
|
||||
},
|
||||
shared: {
|
||||
border: 'border-emerald-300/60 dark:border-emerald-900/40',
|
||||
icon: 'text-emerald-700 dark:text-emerald-400',
|
||||
},
|
||||
deeper: {
|
||||
border: 'border-indigo-300/60 dark:border-indigo-900/40',
|
||||
icon: 'text-indigo-700 dark:text-indigo-400',
|
||||
},
|
||||
isolated: {
|
||||
border: 'border-blue-300/60 dark:border-blue-900/40',
|
||||
icon: 'text-blue-700 dark:text-blue-400',
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-md border bg-card px-3 py-2.5', toneClasses[tone].border)}>
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<span className="text-[11px] uppercase tracking-wide text-muted-foreground">{label}</span>
|
||||
<Icon className={cn('h-3.5 w-3.5', toneClasses[tone].icon)} />
|
||||
</div>
|
||||
<p className={cn('mt-1 text-xl font-mono font-semibold', toneClasses[tone].icon)}>{value}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StrategyCard({
|
||||
title,
|
||||
description,
|
||||
variant,
|
||||
}: {
|
||||
title: string;
|
||||
description: string;
|
||||
variant: 'auth' | 'pool';
|
||||
}) {
|
||||
const variantClasses =
|
||||
variant === 'auth'
|
||||
? 'border-emerald-300/70 bg-emerald-50/40 dark:border-emerald-900/40 dark:bg-emerald-900/10'
|
||||
: 'border-blue-300/70 bg-blue-50/40 dark:border-blue-900/40 dark:bg-blue-900/10';
|
||||
const titleClasses =
|
||||
variant === 'auth'
|
||||
? 'text-emerald-800 dark:text-emerald-300'
|
||||
: 'text-blue-800 dark:text-blue-300';
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-md border px-3 py-2.5', variantClasses)}>
|
||||
<p className={cn('text-sm font-semibold', titleClasses)}>{title}</p>
|
||||
<p className="mt-1 text-xs text-muted-foreground">{description}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function AccountsPage() {
|
||||
const navigate = useNavigate();
|
||||
@@ -164,40 +90,7 @@ export function AccountsPage() {
|
||||
</div>
|
||||
|
||||
<ScrollArea className="flex-1">
|
||||
<div className="p-3 space-y-4">
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Snapshot
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<MetricTile label="Total" value={authAccounts.length} icon={Users} />
|
||||
<MetricTile label="Shared" value={sharedCount} icon={Link2} tone="shared" />
|
||||
<MetricTile label="Deeper" value={deeperSharedCount} icon={Waves} tone="deeper" />
|
||||
<MetricTile
|
||||
label="Isolated"
|
||||
value={isolatedCount}
|
||||
icon={Unlink}
|
||||
tone="isolated"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Strategy Lanes
|
||||
</p>
|
||||
<StrategyCard
|
||||
variant="auth"
|
||||
title="Lane A: ccs auth continuity"
|
||||
description="Isolation-first accounts with explicit shared/deeper controls per profile."
|
||||
/>
|
||||
<StrategyCard
|
||||
variant="pool"
|
||||
title="Lane B: CLIProxy Claude pool"
|
||||
description="OAuth pool routing for lower manual account switching."
|
||||
/>
|
||||
</section>
|
||||
|
||||
<div className="p-3 space-y-3">
|
||||
{hasLegacyFollowUp && (
|
||||
<section className="space-y-2">
|
||||
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
||||
@@ -238,19 +131,14 @@ export function AccountsPage() {
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
|
||||
{!hasLegacyFollowUp && (
|
||||
<div className="rounded-md border bg-background px-3 py-2 text-xs text-muted-foreground">
|
||||
No legacy follow-up pending. Manage pool auth from Action Center.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
|
||||
<div className="p-3 border-t bg-background text-xs text-muted-foreground">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>Standard shared</span>
|
||||
<span className="font-mono">{sharedStandardCount}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mt-1">
|
||||
<span>CLIProxy hidden</span>
|
||||
<span className="font-mono">{cliproxyCount}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main workspace */}
|
||||
@@ -275,39 +163,26 @@ export function AccountsPage() {
|
||||
This table is intentionally scoped to
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
accounts. Use
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">Link</code>/
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">Unlink</code>
|
||||
for quick policy changes and pencil edit for advanced group/deeper settings.
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">Sync</code>
|
||||
for mode/group/depth changes.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex-1 min-h-0 p-5 space-y-4 overflow-y-auto">
|
||||
{cliproxyCount > 0 && (
|
||||
<Alert variant="info">
|
||||
<Zap className="h-4 w-4" />
|
||||
<AlertTitle>CLIProxy pool accounts are managed in their own page</AlertTitle>
|
||||
<AlertDescription>
|
||||
{cliproxyCount} OAuth account{cliproxyCount > 1 ? 's are' : ' is'} available in
|
||||
CLIProxy. This table only covers local
|
||||
<code className="mx-1 rounded bg-muted px-1 py-0.5">ccs auth</code>
|
||||
profiles.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<HistorySyncLearningMap
|
||||
isolatedCount={isolatedCount}
|
||||
sharedStandardCount={sharedStandardCount}
|
||||
deeperSharedCount={deeperSharedCount}
|
||||
sharedGroups={sharedGroups}
|
||||
legacyTargetCount={legacyTargetCount}
|
||||
cliproxyCount={cliproxyCount}
|
||||
/>
|
||||
|
||||
<Card className="flex flex-col">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-lg">Account Matrix</CardTitle>
|
||||
<CardDescription>
|
||||
Shared total: {sharedCount}. Actions now include quick link/unlink plus legacy
|
||||
Shared total: {sharedCount}. Actions include Sync settings and legacy
|
||||
confirmation.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
@@ -493,12 +368,14 @@ export function AccountsPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<MetricTile label="Total" value={authAccounts.length} icon={Users} />
|
||||
<MetricTile label="Shared" value={sharedCount} icon={Link2} tone="shared" />
|
||||
<MetricTile label="Deeper" value={deeperSharedCount} icon={Waves} tone="deeper" />
|
||||
<MetricTile label="Isolated" value={isolatedCount} icon={Unlink} tone="isolated" />
|
||||
</div>
|
||||
<HistorySyncLearningMap
|
||||
isolatedCount={isolatedCount}
|
||||
sharedStandardCount={sharedStandardCount}
|
||||
deeperSharedCount={deeperSharedCount}
|
||||
sharedGroups={sharedGroups}
|
||||
legacyTargetCount={legacyTargetCount}
|
||||
cliproxyCount={cliproxyCount}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<CardHeader className="pb-3">
|
||||
|
||||
Reference in New Issue
Block a user