mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-15 18:21:09 +00:00
fix(ui): blur account identity badges in privacy mode
This commit is contained in:
@@ -192,6 +192,7 @@ export function AccountSurfaceCard({
|
||||
<span
|
||||
className={cn(
|
||||
'text-[8px] font-semibold px-1.5 py-0.5 rounded-md shrink-0',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getTierBadgeClass(effectiveTier)
|
||||
)}
|
||||
>
|
||||
@@ -204,6 +205,7 @@ export function AccountSurfaceCard({
|
||||
title={effectiveCodexBadge.label}
|
||||
className={cn(
|
||||
'text-[8px] font-semibold px-1.5 py-0.5 rounded-md border shrink-0',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getCompactDetailBadgeClass(effectiveCodexBadge.audience)
|
||||
)}
|
||||
>
|
||||
@@ -215,6 +217,7 @@ export function AccountSurfaceCard({
|
||||
title={identity.audienceLabel}
|
||||
className={cn(
|
||||
'text-[8px] font-semibold px-1.5 py-0.5 rounded-md shrink-0',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getAudienceBadgeClass(identity.audience)
|
||||
)}
|
||||
>
|
||||
@@ -226,6 +229,7 @@ export function AccountSurfaceCard({
|
||||
title={identity.detailLabel ?? identity.compactDetailLabel}
|
||||
className={cn(
|
||||
'text-[8px] font-semibold px-1.5 py-0.5 rounded-md border shrink-0',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getCompactDetailBadgeClass(identity.audience)
|
||||
)}
|
||||
>
|
||||
@@ -260,6 +264,7 @@ export function AccountSurfaceCard({
|
||||
<span
|
||||
className={cn(
|
||||
'absolute -bottom-0.5 -right-0.5 text-[7px] font-bold uppercase px-1 py-px rounded ring-1 ring-background',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
effectiveTier === 'ultra'
|
||||
? 'bg-violet-500/20 text-violet-600 dark:bg-violet-500/30 dark:text-violet-300'
|
||||
: 'bg-yellow-500/20 text-yellow-700 dark:bg-yellow-500/25 dark:text-yellow-400'
|
||||
@@ -292,6 +297,7 @@ export function AccountSurfaceCard({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getAudienceBadgeClass(effectiveCodexBadge.audience)
|
||||
)}
|
||||
>
|
||||
@@ -303,6 +309,7 @@ export function AccountSurfaceCard({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
getAudienceBadgeClass(identity.audience)
|
||||
)}
|
||||
>
|
||||
@@ -310,7 +317,10 @@ export function AccountSurfaceCard({
|
||||
</Badge>
|
||||
)}
|
||||
{!isCompact && normalizedProvider !== 'codex' && identity.detailLabel && (
|
||||
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn('text-[10px] h-4 px-1.5', privacyMode && PRIVACY_BLUR_CLASS)}
|
||||
>
|
||||
{identity.detailLabel}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -53,6 +53,7 @@ export function AccountStep({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
codexBadge.audience === 'business'
|
||||
? 'bg-sky-500/12 text-sky-700 dark:text-sky-300'
|
||||
: codexBadge.audience === 'free'
|
||||
@@ -67,6 +68,7 @@ export function AccountStep({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
identity.audience === 'business'
|
||||
? 'bg-sky-500/12 text-sky-700 dark:text-sky-300'
|
||||
: identity.audience === 'free'
|
||||
@@ -78,7 +80,10 @@ export function AccountStep({
|
||||
</Badge>
|
||||
) : null}
|
||||
{!codexBadge?.label && identity.detailLabel && (
|
||||
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn('text-[10px] h-4 px-1.5', privacyMode && PRIVACY_BLUR_CLASS)}
|
||||
>
|
||||
{identity.detailLabel}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -89,6 +89,7 @@ export function VariantStep({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
selectedCodexBadge.audience === 'business'
|
||||
? 'bg-sky-500/12 text-sky-700 dark:text-sky-300'
|
||||
: selectedCodexBadge.audience === 'free'
|
||||
@@ -103,6 +104,7 @@ export function VariantStep({
|
||||
variant="outline"
|
||||
className={cn(
|
||||
'text-[10px] h-4 px-1.5 border-transparent',
|
||||
privacyMode && PRIVACY_BLUR_CLASS,
|
||||
selectedAccountIdentity.audience === 'business'
|
||||
? 'bg-sky-500/12 text-sky-700 dark:text-sky-300'
|
||||
: selectedAccountIdentity.audience === 'free'
|
||||
@@ -114,7 +116,10 @@ export function VariantStep({
|
||||
</Badge>
|
||||
) : null}
|
||||
{!selectedCodexBadge?.label && selectedAccountIdentity?.detailLabel && (
|
||||
<Badge variant="outline" className="text-[10px] h-4 px-1.5">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className={cn('text-[10px] h-4 px-1.5', privacyMode && PRIVACY_BLUR_CLASS)}
|
||||
>
|
||||
{selectedAccountIdentity.detailLabel}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { render, screen } from '@tests/setup/test-utils';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { AccountStep } from '@/components/setup/wizard/steps/account-step';
|
||||
import { VariantStep } from '@/components/setup/wizard/steps/variant-step';
|
||||
import type { OAuthAccount } from '@/lib/api-client';
|
||||
|
||||
const businessAccount: OAuthAccount = {
|
||||
id: 'victim@example.com#04a0f049-team',
|
||||
email: 'victim@example.com',
|
||||
provider: 'gemini',
|
||||
isDefault: false,
|
||||
tokenFile: 'gemini-victim@example.com-04a0f049-team.json',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
|
||||
describe('setup account identity privacy', () => {
|
||||
it('blurs account metadata badges in the account selection step', () => {
|
||||
render(
|
||||
<AccountStep
|
||||
accounts={[businessAccount]}
|
||||
privacyMode={true}
|
||||
onSelect={vi.fn()}
|
||||
onAddNew={vi.fn()}
|
||||
onBack={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('victim@example.com')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Business')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Workspace 04a0f049')).toHaveClass('blur-[4px]');
|
||||
});
|
||||
|
||||
it('blurs account metadata badges in the variant step', () => {
|
||||
render(
|
||||
<VariantStep
|
||||
selectedProvider="gemini"
|
||||
catalog={{ models: [{ id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro' }] }}
|
||||
selectedAccount={businessAccount}
|
||||
variantName="gemini"
|
||||
modelName="gemini-2.5-pro"
|
||||
isPending={false}
|
||||
privacyMode={true}
|
||||
onVariantNameChange={vi.fn()}
|
||||
onModelChange={vi.fn()}
|
||||
onBack={vi.fn()}
|
||||
onSkip={vi.fn()}
|
||||
onCreate={vi.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('victim@example.com')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Business')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Workspace 04a0f049')).toHaveClass('blur-[4px]');
|
||||
});
|
||||
});
|
||||
@@ -146,4 +146,42 @@ describe('AccountSurfaceCard', () => {
|
||||
expect(screen.queryByText('Pers')).not.toBeInTheDocument();
|
||||
expect(screen.queryByTitle('Free')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('blurs detailed account identity metadata when privacy mode is enabled', () => {
|
||||
render(
|
||||
<AccountSurfaceCard
|
||||
mode="detailed"
|
||||
provider="gemini"
|
||||
accountId="victim@example.com#04a0f049-team"
|
||||
email="victim@example.com"
|
||||
displayEmail="victim@example.com"
|
||||
tokenFile="gemini-victim@example.com-04a0f049-team.json"
|
||||
privacyMode={true}
|
||||
showQuota={false}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('victim@example.com')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Business')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Workspace 04a0f049')).toHaveClass('blur-[4px]');
|
||||
});
|
||||
|
||||
it('blurs compact account identity metadata when privacy mode is enabled', () => {
|
||||
render(
|
||||
<AccountSurfaceCard
|
||||
mode="compact"
|
||||
provider="gemini"
|
||||
accountId="victim@example.com#04a0f049-team"
|
||||
email="victim@example.com"
|
||||
displayEmail="victim@example.com"
|
||||
tokenFile="gemini-victim@example.com-04a0f049-team.json"
|
||||
privacyMode={true}
|
||||
showQuota={false}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(screen.getByText('victim@example.com')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('Biz')).toHaveClass('blur-[4px]');
|
||||
expect(screen.getByText('04a0f049')).toHaveClass('blur-[4px]');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user