From aa26e4eebbcaa1210a6596883bf35553312d6d05 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 2 Sep 2026 13:21:51 -0700 Subject: [PATCH 1/2] improvement(usage): show up to 50 rows per tab --- apps/sim/ee/organization-usage/constants.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/sim/ee/organization-usage/constants.ts b/apps/sim/ee/organization-usage/constants.ts index 1a56adf9c6a..bee83633473 100644 --- a/apps/sim/ee/organization-usage/constants.ts +++ b/apps/sim/ee/organization-usage/constants.ts @@ -78,13 +78,13 @@ export const USAGE_TAB_EMPTY_COPY: Record = { /** * Rows per breakdown before and after the `Other` row is expanded. * - * The collapsed count keeps a tab to one screen; the expanded one is the contract's - * own ceiling (`usageLimitSchema(50, 10)`), so asking for more would be refused. A - * dimension with more than {@link EXPANDED_ROW_COUNT} distinct rows still shows an - * `Other` row after expanding, which is the honest result rather than a bug. + * Both counts match the contract's ceiling (`usageLimitSchema(50, 10)`), so each tab + * shows up to 50 rows immediately. A dimension with more than + * {@link EXPANDED_ROW_COUNT} distinct rows still shows an `Other` row, which is the + * honest result rather than a bug. */ -export const COLLAPSED_ROW_COUNT = 10 export const EXPANDED_ROW_COUNT = 50 +export const COLLAPSED_ROW_COUNT = EXPANDED_ROW_COUNT export const DEFAULT_USAGE_PRESET = 'current-period' as const export const DEFAULT_USAGE_TAB = USAGE_OVERVIEW_TAB From 8b35fc0447c70119690e0a12c36c38ed6595b6e6 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Wed, 2 Sep 2026 13:28:46 -0700 Subject: [PATCH 2/2] improvement(usage): allow expanded views up to 100 rows --- apps/sim/ee/organization-usage/constants.ts | 13 ++++++----- apps/sim/hooks/queries/organization-usage.ts | 3 ++- .../api/contracts/organization-usage.test.ts | 22 ++++++++++++++++++- .../lib/api/contracts/organization-usage.ts | 8 ++++++- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/apps/sim/ee/organization-usage/constants.ts b/apps/sim/ee/organization-usage/constants.ts index bee83633473..510933e6485 100644 --- a/apps/sim/ee/organization-usage/constants.ts +++ b/apps/sim/ee/organization-usage/constants.ts @@ -1,5 +1,7 @@ import type { ComboboxOption } from '@sim/emcn' import { + ORGANIZATION_USAGE_BREAKDOWN_DEFAULT_LIMIT, + ORGANIZATION_USAGE_BREAKDOWN_MAX_LIMIT, USAGE_WINDOW_PRESETS, type UsageBreakdownDimension, type UsageWindowPreset, @@ -78,13 +80,12 @@ export const USAGE_TAB_EMPTY_COPY: Record = { /** * Rows per breakdown before and after the `Other` row is expanded. * - * Both counts match the contract's ceiling (`usageLimitSchema(50, 10)`), so each tab - * shows up to 50 rows immediately. A dimension with more than - * {@link EXPANDED_ROW_COUNT} distinct rows still shows an `Other` row, which is the - * honest result rather than a bug. + * Each tab shows the contract default immediately, then can request the contract + * ceiling by expanding `Other`. A dimension with more than + * {@link EXPANDED_ROW_COUNT} distinct rows still shows a remainder after expanding. */ -export const EXPANDED_ROW_COUNT = 50 -export const COLLAPSED_ROW_COUNT = EXPANDED_ROW_COUNT +export const COLLAPSED_ROW_COUNT = ORGANIZATION_USAGE_BREAKDOWN_DEFAULT_LIMIT +export const EXPANDED_ROW_COUNT = ORGANIZATION_USAGE_BREAKDOWN_MAX_LIMIT export const DEFAULT_USAGE_PRESET = 'current-period' as const export const DEFAULT_USAGE_TAB = USAGE_OVERVIEW_TAB diff --git a/apps/sim/hooks/queries/organization-usage.ts b/apps/sim/hooks/queries/organization-usage.ts index 1f514c9e568..fe90d792647 100644 --- a/apps/sim/hooks/queries/organization-usage.ts +++ b/apps/sim/hooks/queries/organization-usage.ts @@ -6,6 +6,7 @@ import { getOrganizationUsageBreakdownContract, getOrganizationUsageSummaryContract, listOrganizationUsageEventsContract, + ORGANIZATION_USAGE_BREAKDOWN_DEFAULT_LIMIT, type OrganizationUsageBreakdown, type OrganizationUsageEventPage, type OrganizationUsageSummary, @@ -96,7 +97,7 @@ export function useOrganizationUsageBreakdown( dimension: UsageBreakdownDimension, options: UseBreakdownOptions = {} ) { - const limit = options.limit ?? 10 + const limit = options.limit ?? ORGANIZATION_USAGE_BREAKDOWN_DEFAULT_LIMIT const { workspaceId } = options const queryKey = organizationUsageKeys.breakdown( organizationId ?? '', diff --git a/apps/sim/lib/api/contracts/organization-usage.test.ts b/apps/sim/lib/api/contracts/organization-usage.test.ts index 91b25dbeac1..44e7c1903cd 100644 --- a/apps/sim/lib/api/contracts/organization-usage.test.ts +++ b/apps/sim/lib/api/contracts/organization-usage.test.ts @@ -2,7 +2,10 @@ * @vitest-environment node */ import { describe, expect, it } from 'vitest' -import { organizationUsageEventsQuerySchema } from '@/lib/api/contracts/organization-usage' +import { + organizationUsageBreakdownQuerySchema, + organizationUsageEventsQuerySchema, +} from '@/lib/api/contracts/organization-usage' /** The shared window fields every usage contract extends, exercised through one of them. */ function parseWindow(input: Record) { @@ -68,3 +71,20 @@ describe('organization usage window contract', () => { expect(parseWindow({ timezone: 'Mars/Olympus_Mons' }).success).toBe(false) }) }) + +describe('organization usage breakdown contract', () => { + const baseQuery = { dimension: 'workspace' as const } + + it('defaults to 50 rows', () => { + expect(organizationUsageBreakdownQuerySchema.parse(baseQuery).limit).toBe(50) + }) + + it('allows expansion to 100 rows and refuses larger requests', () => { + expect( + organizationUsageBreakdownQuerySchema.safeParse({ ...baseQuery, limit: 100 }).success + ).toBe(true) + expect( + organizationUsageBreakdownQuerySchema.safeParse({ ...baseQuery, limit: 101 }).success + ).toBe(false) + }) +}) diff --git a/apps/sim/lib/api/contracts/organization-usage.ts b/apps/sim/lib/api/contracts/organization-usage.ts index 5686c1ca61f..7c6d60b0d24 100644 --- a/apps/sim/lib/api/contracts/organization-usage.ts +++ b/apps/sim/lib/api/contracts/organization-usage.ts @@ -40,6 +40,9 @@ export type UsageBreakdownDimension = z.output