fix(ui): clarify filtered flow viz metrics

This commit is contained in:
Tam Nhu Tran
2026-04-09 17:51:37 -04:00
parent 3687de0625
commit 94eda996e3
5 changed files with 52 additions and 18 deletions
@@ -57,7 +57,6 @@ export function FlowVizHeader({
{pausedAccountsCount > 0 && (
<button
onClick={onTogglePausedAccounts}
aria-pressed={!showPausedAccounts}
className={cn(
'flex items-center gap-1.5 text-xs font-medium transition-all duration-200 px-3 py-1.5 rounded-md border shadow-sm',
showPausedAccounts
@@ -212,6 +212,8 @@ export function AccountFlowViz({
providerColor={providerColor}
totalRequests={totalRequests}
maxRequests={maxRequests}
showVisibleMetrics={!showPausedAccounts && pausedAccountsCount > 0}
hiddenPausedCount={showPausedAccounts ? 0 : pausedAccountsCount}
isDragging={draggingId === 'provider'}
offset={getOffset('provider')}
hoveredAccount={hoveredAccount}
@@ -14,6 +14,8 @@ interface ProviderCardProps {
providerColor: string;
totalRequests: number;
maxRequests: number;
showVisibleMetrics?: boolean;
hiddenPausedCount?: number;
isDragging: boolean;
offset: DragOffset;
hoveredAccount: number | null;
@@ -30,6 +32,8 @@ export function ProviderCard({
providerColor,
totalRequests,
maxRequests,
showVisibleMetrics = false,
hiddenPausedCount = 0,
isDragging,
offset,
hoveredAccount,
@@ -126,11 +130,15 @@ export function ProviderCard({
<div className="space-y-2 relative z-10">
<div className="flex justify-between items-center text-xs">
<span className="text-muted-foreground">{t('flowViz.totalRequests')}</span>
<span className="text-muted-foreground">
{showVisibleMetrics ? t('flowViz.visibleTotalRequests') : t('flowViz.totalRequests')}
</span>
<span className="text-foreground font-mono">{totalRequests.toLocaleString()}</span>
</div>
<div className="flex justify-between items-center text-xs">
<span className="text-muted-foreground">{t('flowViz.accounts')}</span>
<span className="text-muted-foreground">
{showVisibleMetrics ? t('flowViz.visibleAccounts') : t('flowViz.accounts')}
</span>
<span className="text-foreground font-mono">{accounts.length}</span>
</div>
<div className="w-full bg-muted dark:bg-zinc-800/50 h-1 rounded-full mt-2 overflow-hidden">
@@ -142,6 +150,11 @@ export function ProviderCard({
}}
/>
</div>
{showVisibleMetrics && hiddenPausedCount > 0 && (
<div className="text-[10px] text-muted-foreground">
{t('flowViz.excludingPausedAccounts', { count: hiddenPausedCount })}
</div>
)}
</div>
</div>
);
+12
View File
@@ -675,6 +675,9 @@ const resources = {
hideDetails: 'Hide Details',
showPausedAccounts: 'Show Paused ({{count}})',
hidePausedAccounts: 'Hide Paused ({{count}})',
visibleTotalRequests: 'Visible Requests',
visibleAccounts: 'Visible Accounts',
excludingPausedAccounts: 'Excluding {{count}} paused',
resetLayout: 'Reset layout',
provider: 'Provider',
totalRequests: 'Total Requests',
@@ -1990,6 +1993,9 @@ const resources = {
hideDetails: '隐藏详情',
showPausedAccounts: '显示已暂停 ({{count}})',
hidePausedAccounts: '隐藏已暂停 ({{count}})',
visibleTotalRequests: '可见请求数',
visibleAccounts: '可见账号',
excludingPausedAccounts: '已排除 {{count}} 个已暂停',
resetLayout: '重置布局',
provider: '提供商',
totalRequests: '总请求数',
@@ -3351,6 +3357,9 @@ const resources = {
hideDetails: 'Ẩn chi tiết',
showPausedAccounts: 'Hiện tạm dừng ({{count}})',
hidePausedAccounts: 'Ẩn tạm dừng ({{count}})',
visibleTotalRequests: 'Yêu cầu hiển thị',
visibleAccounts: 'Tài khoản hiển thị',
excludingPausedAccounts: 'Đang loại trừ {{count}} tài khoản tạm dừng',
resetLayout: 'Đặt lại bố cục',
provider: 'Nhà cung cấp',
totalRequests: 'Tổng số yêu cầu',
@@ -4737,6 +4746,9 @@ const resources = {
hideDetails: '詳細を隠す',
showPausedAccounts: '一時停止を表示 ({{count}})',
hidePausedAccounts: '一時停止を非表示 ({{count}})',
visibleTotalRequests: '表示中のリクエスト',
visibleAccounts: '表示中のアカウント',
excludingPausedAccounts: '一時停止 {{count}} 件を除外中',
resetLayout: 'レイアウトをリセット',
provider: 'プロバイダー',
totalRequests: '総リクエスト数',
@@ -15,6 +15,11 @@ vi.mock(import('react-i18next'), async (importOriginal) => {
'flowViz.hideDetails': 'Hide Details',
'flowViz.backToProviders': 'Back to providers',
'flowViz.resetLayout': 'Reset layout',
'flowViz.provider': 'Provider',
'flowViz.totalRequests': 'Total Requests',
'flowViz.accounts': 'Accounts',
'flowViz.visibleTotalRequests': 'Visible Requests',
'flowViz.visibleAccounts': 'Visible Accounts',
};
if (key === 'flowViz.showPausedAccounts') {
@@ -25,6 +30,10 @@ vi.mock(import('react-i18next'), async (importOriginal) => {
return `Hide Paused (${options?.count ?? 0})`;
}
if (key === 'flowViz.excludingPausedAccounts') {
return `Excluding ${options?.count ?? 0} paused`;
}
return translations[key] ?? key;
},
}),
@@ -48,10 +57,8 @@ vi.mock('@/components/account/flow-viz/account-card', () => ({
),
}));
vi.mock('@/components/account/flow-viz/provider-card', () => ({
ProviderCard: ({ providerData }: { providerData: ProviderData }) => (
<div data-provider-node>{providerData.accounts.length} visible accounts</div>
),
vi.mock('@/components/shared/provider-icon', () => ({
ProviderIcon: ({ provider }: { provider: string }) => <div>{provider}</div>,
}));
vi.mock('@/components/account/flow-viz/connection-timeline', () => ({
@@ -115,30 +122,31 @@ describe('AccountFlowViz paused account visibility', () => {
expect(screen.getByRole('button', { name: 'Hide Paused (1)' })).toBeInTheDocument();
expect(screen.getByText('active@company.com (active)')).toBeInTheDocument();
expect(screen.getByText('paused@company.com (paused)')).toBeInTheDocument();
expect(screen.getByText('2 visible accounts')).toBeInTheDocument();
expect(screen.getByText('Total Requests')).toBeInTheDocument();
expect(screen.getByText('Accounts')).toBeInTheDocument();
expect(screen.getByText('7')).toBeInTheDocument();
expect(screen.getByText('2')).toBeInTheDocument();
expect(screen.getByText('7 timeline events')).toBeInTheDocument();
expect(screen.getByText('paths:paused-account,active-account')).toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: 'Hide Paused (1)' }));
expect(screen.getByRole('button', { name: 'Show Paused (1)' })).toHaveAttribute(
'aria-pressed',
'true'
);
expect(screen.getByRole('button', { name: 'Show Paused (1)' })).toBeInTheDocument();
expect(screen.getByText('active@company.com (active)')).toBeInTheDocument();
expect(screen.queryByText('paused@company.com (paused)')).not.toBeInTheDocument();
expect(screen.getByText('1 visible accounts')).toBeInTheDocument();
expect(screen.getByText('Visible Requests')).toBeInTheDocument();
expect(screen.getByText('Visible Accounts')).toBeInTheDocument();
expect(screen.getByText('Excluding 1 paused')).toBeInTheDocument();
expect(screen.getByText('3')).toBeInTheDocument();
expect(screen.getByText('1')).toBeInTheDocument();
expect(screen.getByText('3 timeline events')).toBeInTheDocument();
expect(screen.getByText('paths:active-account')).toBeInTheDocument();
await userEvent.click(screen.getByRole('button', { name: 'Show Paused (1)' }));
expect(screen.getByRole('button', { name: 'Hide Paused (1)' })).toHaveAttribute(
'aria-pressed',
'false'
);
expect(screen.getByRole('button', { name: 'Hide Paused (1)' })).toBeInTheDocument();
expect(screen.getByText('paused@company.com (paused)')).toBeInTheDocument();
expect(screen.getByText('2 visible accounts')).toBeInTheDocument();
expect(screen.queryByText('Excluding 1 paused')).not.toBeInTheDocument();
});
it('ignores hidden paused-account drag offsets when deciding whether reset layout should stay visible', async () => {