Skip to content

Commit 7b6a509

Browse files
committed
Add superuser benchmark console with selected-user execution
1 parent b06f81f commit 7b6a509

44 files changed

Lines changed: 31177 additions & 287 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { benchmarkAvailabilityContract } from '@/lib/api/contracts/benchmarks'
2+
import {
3+
defineInternalJsonRoute,
4+
internalOrchestrationErrorPolicy,
5+
internalRateLimits,
6+
internalSessionAuth,
7+
} from '@/lib/api/server/routes'
8+
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
9+
import { benchmarkAvailability } from '@/lib/benchmarks/application/selection'
10+
11+
export const GET = defineInternalJsonRoute({
12+
contract: benchmarkAvailabilityContract,
13+
auth: internalSessionAuth,
14+
operation: benchmarkOperations.availability,
15+
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-selection' }),
16+
errorPolicy: internalOrchestrationErrorPolicy,
17+
mapInput: () => ({}),
18+
useCase: benchmarkAvailability,
19+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { benchmarkUsersContract } from '@/lib/api/contracts/benchmarks'
2+
import {
3+
defineInternalJsonRoute,
4+
internalOrchestrationErrorPolicy,
5+
internalRateLimits,
6+
internalSessionAuth,
7+
} from '@/lib/api/server/routes'
8+
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
9+
import { listBenchmarkUsers } from '@/lib/benchmarks/application/selection'
10+
11+
export const GET = defineInternalJsonRoute({
12+
contract: benchmarkUsersContract,
13+
auth: internalSessionAuth,
14+
operation: benchmarkOperations.users,
15+
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-selection' }),
16+
errorPolicy: internalOrchestrationErrorPolicy,
17+
mapInput: ({ params, query }) => ({ organizationId: params.id, ...query }),
18+
useCase: listBenchmarkUsers,
19+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { benchmarkWorkspacesContract } from '@/lib/api/contracts/benchmarks'
2+
import {
3+
defineInternalJsonRoute,
4+
internalOrchestrationErrorPolicy,
5+
internalRateLimits,
6+
internalSessionAuth,
7+
} from '@/lib/api/server/routes'
8+
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
9+
import { listBenchmarkWorkspaces } from '@/lib/benchmarks/application/selection'
10+
11+
export const GET = defineInternalJsonRoute({
12+
contract: benchmarkWorkspacesContract,
13+
auth: internalSessionAuth,
14+
operation: benchmarkOperations.workspaces,
15+
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-selection' }),
16+
errorPolicy: internalOrchestrationErrorPolicy,
17+
mapInput: ({ params, query }) => ({ organizationId: params.id, ...query }),
18+
useCase: listBenchmarkWorkspaces,
19+
})
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { benchmarkOrganizationsContract } from '@/lib/api/contracts/benchmarks'
2+
import {
3+
defineInternalJsonRoute,
4+
internalOrchestrationErrorPolicy,
5+
internalRateLimits,
6+
internalSessionAuth,
7+
} from '@/lib/api/server/routes'
8+
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
9+
import { listBenchmarkOrganizations } from '@/lib/benchmarks/application/selection'
10+
11+
export const GET = defineInternalJsonRoute({
12+
contract: benchmarkOrganizationsContract,
13+
auth: internalSessionAuth,
14+
operation: benchmarkOperations.organizations,
15+
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-selection' }),
16+
errorPolicy: internalOrchestrationErrorPolicy,
17+
mapInput: ({ query }) => query,
18+
useCase: listBenchmarkOrganizations,
19+
})

‎apps/sim/app/api/organizations/[id]/benchmarks/[benchmarkId]/route.ts‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import {
99
internalRateLimits,
1010
internalSessionAuth,
1111
} from '@/lib/api/server/routes'
12+
import { requireBenchmarkOperator } from '@/lib/benchmarks/application/access'
1213
import { deleteBenchmark, getBenchmark, updateBenchmark } from '@/lib/benchmarks/application/cases'
1314
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
14-
import { requireBenchmarkEnabled } from '@/lib/benchmarks/config'
1515

1616
export const GET = defineInternalJsonRoute({
1717
contract: getBenchmarkContract,
@@ -21,7 +21,9 @@ export const GET = defineInternalJsonRoute({
2121
reason: 'The owner polls bounded benchmark artifacts under current source access',
2222
}),
2323
errorPolicy: internalOrchestrationErrorPolicy,
24-
beforeParse: () => requireBenchmarkEnabled(),
24+
beforeParse: async ({ principal }) => {
25+
await requireBenchmarkOperator(principal)
26+
},
2527
mapInput: ({ params }) => ({ organizationId: params.id, benchmarkId: params.benchmarkId }),
2628
useCase: getBenchmark,
2729
})
@@ -32,7 +34,9 @@ export const PATCH = defineInternalJsonRoute({
3234
operation: benchmarkOperations.update,
3335
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-update' }),
3436
errorPolicy: internalOrchestrationErrorPolicy,
35-
beforeParse: () => requireBenchmarkEnabled(),
37+
beforeParse: async ({ principal }) => {
38+
await requireBenchmarkOperator(principal)
39+
},
3640
mapInput: ({ params, body: { version, ...patch } }) => ({
3741
organizationId: params.id,
3842
benchmarkId: params.benchmarkId,
@@ -48,7 +52,9 @@ export const DELETE = defineInternalJsonRoute({
4852
operation: benchmarkOperations.delete,
4953
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-delete' }),
5054
errorPolicy: internalOrchestrationErrorPolicy,
51-
beforeParse: () => requireBenchmarkEnabled(),
55+
beforeParse: async ({ principal }) => {
56+
await requireBenchmarkOperator(principal)
57+
},
5258
mapInput: ({ params, body }) => ({
5359
organizationId: params.id,
5460
benchmarkId: params.benchmarkId,

‎apps/sim/app/api/organizations/[id]/benchmarks/[benchmarkId]/run/route.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
internalRateLimits,
66
internalSessionAuth,
77
} from '@/lib/api/server/routes'
8+
import { requireBenchmarkOperator } from '@/lib/benchmarks/application/access'
89
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
910
import { runBenchmarkStage } from '@/lib/benchmarks/application/run-stage'
10-
import { requireBenchmarkEnabled } from '@/lib/benchmarks/config'
1111

1212
export const maxDuration = 660
1313

@@ -20,7 +20,9 @@ export const POST = defineInternalJsonRoute({
2020
config: { maxTokens: 10, refillRate: 2, refillIntervalMs: 60_000 },
2121
}),
2222
errorPolicy: internalOrchestrationErrorPolicy,
23-
beforeParse: () => requireBenchmarkEnabled(),
23+
beforeParse: async ({ principal }) => {
24+
await requireBenchmarkOperator(principal)
25+
},
2426
mapInput: ({ params, body }) => ({
2527
organizationId: params.id,
2628
benchmarkId: params.benchmarkId,

‎apps/sim/app/api/organizations/[id]/benchmarks/[benchmarkId]/runs/[runId]/route.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import {
55
internalRateLimits,
66
internalSessionAuth,
77
} from '@/lib/api/server/routes'
8+
import { requireBenchmarkOperator } from '@/lib/benchmarks/application/access'
89
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
910
import { getBenchmarkRun, reviewBenchmarkRun } from '@/lib/benchmarks/application/runs'
10-
import { requireBenchmarkEnabled } from '@/lib/benchmarks/config'
1111

1212
export const GET = defineInternalJsonRoute({
1313
contract: getBenchmarkRunContract,
1414
auth: internalSessionAuth,
1515
operation: benchmarkOperations.readRun,
1616
rateLimit: internalRateLimits.none({ reason: 'Owner-only bounded benchmark run snapshot' }),
1717
errorPolicy: internalOrchestrationErrorPolicy,
18-
beforeParse: () => requireBenchmarkEnabled(),
18+
beforeParse: async ({ principal }) => {
19+
await requireBenchmarkOperator(principal)
20+
},
1921
mapInput: ({ params }) => ({
2022
organizationId: params.id,
2123
benchmarkId: params.benchmarkId,
@@ -30,7 +32,9 @@ export const PATCH = defineInternalJsonRoute({
3032
operation: benchmarkOperations.reviewRun,
3133
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-review' }),
3234
errorPolicy: internalOrchestrationErrorPolicy,
33-
beforeParse: () => requireBenchmarkEnabled(),
35+
beforeParse: async ({ principal }) => {
36+
await requireBenchmarkOperator(principal)
37+
},
3438
mapInput: ({ params, body }) => ({
3539
organizationId: params.id,
3640
benchmarkId: params.benchmarkId,

‎apps/sim/app/api/organizations/[id]/benchmarks/[benchmarkId]/runs/route.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import {
55
internalRateLimits,
66
internalSessionAuth,
77
} from '@/lib/api/server/routes'
8+
import { requireBenchmarkOperator } from '@/lib/benchmarks/application/access'
89
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
910
import { listBenchmarkRuns } from '@/lib/benchmarks/application/runs'
10-
import { requireBenchmarkEnabled } from '@/lib/benchmarks/config'
1111

1212
export const GET = defineInternalJsonRoute({
1313
contract: listBenchmarkRunsContract,
1414
auth: internalSessionAuth,
1515
operation: benchmarkOperations.listRuns,
1616
rateLimit: internalRateLimits.none({ reason: 'Owner-only paginated benchmark run summaries' }),
1717
errorPolicy: internalOrchestrationErrorPolicy,
18-
beforeParse: () => requireBenchmarkEnabled(),
18+
beforeParse: async ({ principal }) => {
19+
await requireBenchmarkOperator(principal)
20+
},
1921
mapInput: ({ params, query }) => ({
2022
organizationId: params.id,
2123
benchmarkId: params.benchmarkId,

‎apps/sim/app/api/organizations/[id]/benchmarks/route.ts‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ import {
55
internalRateLimits,
66
internalSessionAuth,
77
} from '@/lib/api/server/routes'
8+
import { requireBenchmarkOperator } from '@/lib/benchmarks/application/access'
89
import { createBenchmark, listBenchmarks } from '@/lib/benchmarks/application/cases'
910
import { benchmarkOperations } from '@/lib/benchmarks/application/operations'
10-
import { requireBenchmarkEnabled } from '@/lib/benchmarks/config'
1111

1212
export const GET = defineInternalJsonRoute({
1313
contract: listBenchmarksContract,
@@ -17,7 +17,9 @@ export const GET = defineInternalJsonRoute({
1717
reason: 'Private benchmark metadata uses bounded pagination under current membership',
1818
}),
1919
errorPolicy: internalOrchestrationErrorPolicy,
20-
beforeParse: () => requireBenchmarkEnabled(),
20+
beforeParse: async ({ principal }) => {
21+
await requireBenchmarkOperator(principal)
22+
},
2123
mapInput: ({ params, query }) => ({ organizationId: params.id, ...query }),
2224
useCase: listBenchmarks,
2325
})
@@ -28,7 +30,9 @@ export const POST = defineInternalJsonRoute({
2830
operation: benchmarkOperations.create,
2931
rateLimit: internalRateLimits.user({ bucketName: 'benchmark-create' }),
3032
errorPolicy: internalOrchestrationErrorPolicy,
31-
beforeParse: () => requireBenchmarkEnabled(),
33+
beforeParse: async ({ principal }) => {
34+
await requireBenchmarkOperator(principal)
35+
},
3236
mapInput: ({ params, body }) => ({ organizationId: params.id, ...body }),
3337
useCase: createBenchmark,
3438
})
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
'use client'
2+
3+
import { useState } from 'react'
4+
import { Chip, ChipCombobox, ChipLink } from '@sim/emcn'
5+
import { useQueryStates } from 'nuqs'
6+
import {
7+
benchmarkConsoleParams,
8+
benchmarkConsoleUrlOptions,
9+
emptyBenchmarkSelection,
10+
} from '@/app/benchmark/search-params'
11+
import { Benchmark } from '@/app/o/[organizationId]/benchmark/benchmark'
12+
import {
13+
useBenchmarkOrganizations,
14+
useBenchmarkUsers,
15+
useBenchmarkWorkspaces,
16+
} from '@/hooks/queries/benchmarks'
17+
import { useDebounce } from '@/hooks/use-debounce'
18+
19+
export function BenchmarkConsole() {
20+
const [{ organizationId, runAsUserId }, setParams] = useQueryStates(
21+
benchmarkConsoleParams,
22+
benchmarkConsoleUrlOptions
23+
)
24+
const [organizationSearch, setOrganizationSearch] = useState('')
25+
const [userSearch, setUserSearch] = useState('')
26+
const organizations = useBenchmarkOrganizations(
27+
useDebounce(organizationSearch, 250),
28+
organizationId
29+
)
30+
const users = useBenchmarkUsers(organizationId, useDebounce(userSearch, 250), runAsUserId)
31+
const workspaces = useBenchmarkWorkspaces(organizationId, runAsUserId)
32+
const selectedOrganization = organizations.data?.pages[0]?.selected
33+
const organizationOptions = [
34+
...(selectedOrganization ? [selectedOrganization] : []),
35+
...(organizations.data?.pages
36+
.flatMap((page) => page.organizations)
37+
.filter((org) => org.id !== selectedOrganization?.id) ?? []),
38+
]
39+
const selectedUser = users.data?.pages[0]?.selected
40+
const userOptions = [
41+
...(selectedUser ? [selectedUser] : []),
42+
...(users.data?.pages
43+
.flatMap((page) => page.users)
44+
.filter((user) => user.id !== selectedUser?.id) ?? []),
45+
]
46+
const error = organizations.error ?? users.error ?? workspaces.error
47+
48+
return (
49+
<main className='workspace-root min-h-screen bg-[var(--bg)] text-[var(--text-body)]'>
50+
<div className='mx-auto flex w-full max-w-chat flex-col gap-5 px-6 pt-8'>
51+
<div className='flex items-center justify-between gap-4'>
52+
<h1 className='text-[var(--text-primary)] text-lg'>Benchmarks</h1>
53+
<ChipLink href='/account/settings/admin'>Back to settings</ChipLink>
54+
</div>
55+
<p className='text-[var(--text-muted)] text-small'>
56+
Run a benchmark with a user’s enterprise access. Your admin session stays unchanged.
57+
</p>
58+
<div className='grid gap-4 sm:grid-cols-2'>
59+
<div className='flex flex-col gap-2'>
60+
<label htmlFor='benchmark-organization' className='text-small'>
61+
Organization
62+
</label>
63+
<ChipCombobox
64+
id='benchmark-organization'
65+
aria-label='Organization'
66+
value={organizationId}
67+
options={organizationOptions.map((org) => ({ value: org.id, label: org.name }))}
68+
placeholder='Select an organization'
69+
searchable
70+
isLoading={organizations.isLoading}
71+
onSearchChange={setOrganizationSearch}
72+
onChange={(value) =>
73+
setParams({ organizationId: value, runAsUserId: null, ...emptyBenchmarkSelection })
74+
}
75+
/>
76+
{organizations.hasNextPage && (
77+
<Chip
78+
disabled={organizations.isFetchingNextPage}
79+
onClick={() => organizations.fetchNextPage()}
80+
>
81+
Load more organizations
82+
</Chip>
83+
)}
84+
</div>
85+
<div className='flex flex-col gap-2'>
86+
<label htmlFor='benchmark-user' className='text-small'>
87+
Run as user
88+
</label>
89+
<ChipCombobox
90+
key={organizationId}
91+
id='benchmark-user'
92+
aria-label='Run as user'
93+
value={runAsUserId}
94+
options={userOptions.map((user) => ({
95+
value: user.id,
96+
label: `${user.name} (${user.email})`,
97+
}))}
98+
placeholder='Select a user'
99+
searchable
100+
isLoading={users.isLoading}
101+
disabled={!organizationId}
102+
onSearchChange={setUserSearch}
103+
onChange={(value) => setParams({ runAsUserId: value, ...emptyBenchmarkSelection })}
104+
/>
105+
{users.hasNextPage && (
106+
<Chip disabled={users.isFetchingNextPage} onClick={() => users.fetchNextPage()}>
107+
Load more users
108+
</Chip>
109+
)}
110+
</div>
111+
</div>
112+
{runAsUserId && (
113+
<p className='text-[var(--text-muted)] text-small'>
114+
Running as {selectedUser?.email ?? runAsUserId}. Normal permissions and billing for this
115+
organization apply. Reports are private to you.
116+
</p>
117+
)}
118+
{error && (
119+
<p role='alert' className='text-[var(--text-error)] text-small'>
120+
{error.message}
121+
</p>
122+
)}
123+
</div>
124+
{organizationId && runAsUserId && workspaces.data && !workspaces.error && (
125+
<Benchmark
126+
key={`${organizationId}:${runAsUserId}`}
127+
organizationId={organizationId}
128+
runAsUserId={runAsUserId}
129+
canPlan={workspaces.data.pages[0]?.canPlan ?? false}
130+
/>
131+
)}
132+
</main>
133+
)
134+
}

0 commit comments

Comments
 (0)