diff --git a/apps/web/src/components/usage-analytics/UsageAnalyticsDashboard.tsx b/apps/web/src/components/usage-analytics/UsageAnalyticsDashboard.tsx index d0283bd2f9..e4e9a9f689 100644 --- a/apps/web/src/components/usage-analytics/UsageAnalyticsDashboard.tsx +++ b/apps/web/src/components/usage-analytics/UsageAnalyticsDashboard.tsx @@ -28,6 +28,7 @@ import { ActiveKiloclawsTable } from './ActiveKiloclawsTable'; import { UsageDataErrorState } from './UsageDataErrorState'; import { UsageDataPendingState } from './UsageDataPendingState'; import { resolveUsageDashboardState, usageQueryOutcome } from './usageDataState'; +import { usageTableEmptyMessage } from './usageEmptyMessage'; import { PERSONAL_VIEW_ALL_USAGE, PERSONAL_VIEW_PERSONAL_ONLY, @@ -938,7 +939,16 @@ export function UsageAnalyticsDashboard(props: UsageAnalyticsDashboardProps) { title="Detailed Breakdown" columns={tableColumns} data={tableRows} - emptyMessage={tableLoading ? 'Loading usage…' : 'No usage data for this period.'} + emptyMessage={ + isOrgContext + ? tableLoading + ? 'Loading usage…' + : 'No usage data for this period.' + : usageTableEmptyMessage({ + isLoading: tableLoading, + isPersonalContext: !isOrgContext, + }) + } sortable defaultSort={{ key: 'datetime', direction: 'desc' }} headerActions={ diff --git a/apps/web/src/components/usage-analytics/usageEmptyMessage.test.ts b/apps/web/src/components/usage-analytics/usageEmptyMessage.test.ts new file mode 100644 index 0000000000..b538559585 --- /dev/null +++ b/apps/web/src/components/usage-analytics/usageEmptyMessage.test.ts @@ -0,0 +1,33 @@ +import { + ORGANIZATION_USAGE_EMPTY_MESSAGE, + PERSONAL_USAGE_EMPTY_MESSAGE, + usageTableEmptyMessage, +} from './usageEmptyMessage'; + +describe('usageTableEmptyMessage', () => { + it('shows the loading copy while the table query is in flight', () => { + expect(usageTableEmptyMessage({ isLoading: true, isPersonalContext: true })).toBe( + 'Loading usage…' + ); + expect(usageTableEmptyMessage({ isLoading: true, isPersonalContext: false })).toBe( + 'Loading usage…' + ); + }); + + it('shows the new personal copy when a personal account has no usage rows', () => { + expect(usageTableEmptyMessage({ isLoading: false, isPersonalContext: true })).toBe( + 'No usage yet. Your first request will appear here.' + ); + }); + + it('keeps the reworded organization copy for organization usage', () => { + expect(usageTableEmptyMessage({ isLoading: false, isPersonalContext: false })).toBe( + 'No usage data for this period.' + ); + }); + + it('exports the exact personal and organization messages', () => { + expect(PERSONAL_USAGE_EMPTY_MESSAGE).toBe('No usage yet. Your first request will appear here.'); + expect(ORGANIZATION_USAGE_EMPTY_MESSAGE).toBe('No usage data for this period.'); + }); +}); diff --git a/apps/web/src/components/usage-analytics/usageEmptyMessage.ts b/apps/web/src/components/usage-analytics/usageEmptyMessage.ts new file mode 100644 index 0000000000..8eae7612fa --- /dev/null +++ b/apps/web/src/components/usage-analytics/usageEmptyMessage.ts @@ -0,0 +1,14 @@ +export const PERSONAL_USAGE_EMPTY_MESSAGE = 'No usage yet. Your first request will appear here.'; + +export const ORGANIZATION_USAGE_EMPTY_MESSAGE = 'No usage data for this period.'; + +export function usageTableEmptyMessage({ + isLoading, + isPersonalContext, +}: { + isLoading: boolean; + isPersonalContext: boolean; +}): string { + if (isLoading) return 'Loading usage…'; + return isPersonalContext ? PERSONAL_USAGE_EMPTY_MESSAGE : ORGANIZATION_USAGE_EMPTY_MESSAGE; +}