@acarmisc/backstage-plugin-litellm 0.32.0 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -66
- package/dist/components/KeyFormDialog.d.ts +0 -2
- package/dist/components/LiteLLMBudgetGauges.d.ts +0 -1
- package/dist/components/ManageTeamDialog.d.ts +10 -1
- package/dist/components/keyFormHelpers.d.ts +0 -1
- package/dist/hooks/useCopyToClipboard.d.ts +0 -5
- package/dist/index.cjs.js +272 -225
- package/dist/index.cjs.js.map +4 -4
- package/dist/index.d.ts +2 -3
- package/dist/index.esm.js +283 -237
- package/dist/index.esm.js.map +4 -4
- package/package.json +4 -10
- package/dist/components/GenerateKeyDialog.d.ts +0 -21
- package/dist/permissions.d.ts +0 -1
package/dist/index.cjs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/profileCache.ts", "../src/api.ts", "../src/routes.ts", "../src/components/ui/tokens.tsx", "../src/components/ui/charts.tsx", "../src/components/ui/pills.tsx", "../src/components/ui/surfaces.tsx", "../src/components/ui/Meter.tsx", "../src/components/ui/Gauge.tsx", "../src/components/ui/index.ts", "../src/components/GenerateKeyButton.tsx", "../src/components/DashboardHeader.tsx", "../src/hooks/useCopyToClipboard.ts", "../src/hooks/useLiteLLMProfile.ts", "../src/hooks/index.ts", "../src/keyLabels.ts", "../src/format.ts", "../src/keyFilter.ts", "../src/components/KeysTable.tsx", "../src/keyFormValidation.ts", "../src/components/keyFormHelpers.ts", "../src/components/KeySnippets.tsx", "../src/components/KeyFormDialog.tsx", "../src/components/ManageTeamDialog.tsx", "../src/budget.ts", "../src/components/UsageStats.tsx", "../src/widgetState.ts", "../src/components/BudgetLimitList.tsx", "../src/routeHelpers.ts", "../src/components/LiteLLMBudgetWidget.tsx", "../src/components/TeamUsage.tsx", "../src/components/ModelsTable.tsx", "../src/components/AuditLog.tsx", "../src/dates.ts", "../src/
|
|
4
|
-
"sourcesContent": ["/**\n * A per-API-instance promise cache with TTL and single-flight deduplication.\n * Used to memoize the profile hook's result and reduce redundant fetches.\n *\n * Each API instance gets its own cache entry; entries expire after a TTL.\n * Concurrent callers for the same key within the TTL share a single promise\n * and wait for its result rather than issuing parallel requests.\n *\n * Injectable clock for testing.\n */\n\nimport { LiteLlmApiInterface } from './api';\n\nexport interface Clock {\n now(): number;\n}\n\nexport const systemClock: Clock = {\n now: () => Date.now(),\n};\n\nexport interface ProfileCacheEntry {\n result: unknown;\n timestamp: number;\n}\n\n/**\n * Inflight tracker for single-flight deduplication.\n * Maps a key \u2192 a promise that resolves when the fetch completes.\n */\ninterface InflightEntry {\n promise: Promise<unknown>;\n resolveTime: number;\n}\n\nexport class ProfileCache {\n private cache = new WeakMap<LiteLlmApiInterface, Record<string, ProfileCacheEntry>>();\n private inflight = new WeakMap<LiteLlmApiInterface, Record<string, InflightEntry>>();\n private ttlMs: number;\n private clock: Clock;\n\n constructor(ttlMs: number = 30_000, clock: Clock = systemClock) {\n this.ttlMs = ttlMs;\n this.clock = clock;\n }\n\n /**\n * Fetch or return a cached value. If a concurrent call with the same key\n * is in-flight, wait for it rather than issuing a parallel request.\n *\n * @param api The API instance (cache is scoped to it).\n * @param key A string key for the result (e.g., 'profile' or a team ID).\n * @param fetcher A thunk that returns the value to cache.\n * @returns The cached value (hit or miss) or the result of fetcher().\n */\n async memoize<T>(\n api: LiteLlmApiInterface,\n key: string,\n fetcher: () => Promise<T>,\n ): Promise<T> {\n const now = this.clock.now();\n\n // Check if there's a valid cached entry.\n const cached = this.cache.get(api)?.[key];\n if (cached && now - cached.timestamp < this.ttlMs) {\n return cached.result as T;\n }\n\n // Check if there's an inflight promise we can reuse (but not if it failed).\n const inflight = this.inflight.get(api)?.[key];\n if (inflight && now - inflight.resolveTime < this.ttlMs) {\n return inflight.promise as Promise<T>;\n }\n\n // Fetch and cache, with single-flight protection.\n // Errors are not cached, so each retry fetches fresh.\n const promise = fetcher()\n .then(result => {\n // Cache the successful result.\n if (!this.cache.has(api)) this.cache.set(api, {});\n this.cache.get(api)![key] = { result, timestamp: this.clock.now() };\n return result;\n })\n .catch(err => {\n // Don't cache failures; remove the inflight entry so the next call retries.\n const inflightEntries = this.inflight.get(api);\n if (inflightEntries) {\n delete inflightEntries[key];\n }\n throw err;\n });\n\n // Track the inflight request.\n if (!this.inflight.has(api)) this.inflight.set(api, {});\n this.inflight.get(api)![key] = { promise, resolveTime: this.clock.now() };\n\n return promise as Promise<T>;\n }\n\n /**\n * Invalidate all cached entries for an API instance, including inflight requests.\n */\n invalidate(api: LiteLlmApiInterface): void {\n this.cache.delete(api);\n this.inflight.delete(api);\n }\n\n /**\n * Invalidate every profile entry (`profile`, `profile-userInfo`,\n * `profile-keys`, ...) and its in-flight promise, leaving unrelated keys alone.\n */\n invalidateProfile(api: LiteLlmApiInterface): void {\n const isProfileKey = (k: string) => k === 'profile' || k.startsWith('profile-');\n for (const store of [this.cache.get(api), this.inflight.get(api)]) {\n if (!store) continue;\n for (const k of Object.keys(store)) {\n if (isProfileKey(k)) delete store[k];\n }\n }\n }\n}\n\n// Singleton cache instance shared by all hooks using the same API ref.\nexport const profileCacheInstance = new ProfileCache();\n", "import { createApiRef, type FetchApi, type DiscoveryApi } from '@backstage/frontend-plugin-api';\nimport {\n UserInfo,\n VirtualKey,\n ModelInfo,\n UsageMetrics,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n UpdateKeyRequest,\n AuditLogsParams,\n PaginatedAuditLogs,\n LiteLlmConfig,\n VectorStoreInfo,\n McpServerInfo,\n CreateTeamRequest,\n CreateTeamResponse,\n UpdateTeamRequest,\n} from './types';\nimport { profileCacheInstance } from './profileCache';\n\nexport class ApiError extends Error {\n body: unknown;\n status: number;\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n\nexport interface LiteLlmApiInterface {\n getUserInfo(): Promise<UserInfo>;\n listKeys(): Promise<VirtualKey[]>;\n generateKey(request: GenerateKeyRequest): Promise<GenerateKeyResponse>;\n updateKey(keyId: string, request: UpdateKeyRequest): Promise<VirtualKey>;\n deleteKey(keyId: string): Promise<{ success: boolean }>;\n blockKey(keyId: string): Promise<void>;\n unblockKey(keyId: string): Promise<void>;\n resetKeySpend(keyId: string): Promise<void>;\n pruneExpiredKeys(): Promise<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }>;\n listModels(): Promise<ModelInfo[]>;\n getTeams(): Promise<TeamInfo[]>;\n getManagedTeams(): Promise<TeamInfo[]>;\n addTeamMember(\n teamId: string,\n body: { userEntityRef: string; maxBudgetInTeam?: number },\n ): Promise<TeamInfo>;\n removeTeamMember(teamId: string, userEntityRef: string): Promise<TeamInfo>;\n getVectorStores(): Promise<VectorStoreInfo[]>;\n setTeamKnowledgeBases(teamId: string, vectorStores: string[]): Promise<TeamInfo>;\n getMcpServers(): Promise<McpServerInfo[]>;\n setTeamMcpServers(teamId: string, mcpServers: string[]): Promise<TeamInfo>;\n getUsage(startDate: string, endDate: string): Promise<UsageMetrics>;\n getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics>;\n getAuditLogs(params: AuditLogsParams): Promise<PaginatedAuditLogs>;\n getConfig(): Promise<LiteLlmConfig>;\n createTeam(request: CreateTeamRequest): Promise<CreateTeamResponse>;\n updateTeam(teamId: string, request: UpdateTeamRequest): Promise<TeamInfo>;\n}\n\nexport const liteLlmApiRef = createApiRef<LiteLlmApiInterface>({\n id: 'plugin.litellm.api',\n});\n\nexport type ExpiryStatus = 'expired' | 'soon' | 'ok';\n\nexport function expiryStatus(expiresAt?: string): ExpiryStatus | null {\n if (!expiresAt) return null;\n const diff = new Date(expiresAt).getTime() - Date.now();\n const days = diff / (1000 * 60 * 60 * 24);\n if (days < 0) return 'expired';\n if (days < 7) return 'soon';\n return 'ok';\n}\n\nexport class LiteLlmApi implements LiteLlmApiInterface {\n private fetchApi: FetchApi;\n private base: string | DiscoveryApi;\n\n /**\n * @param base A DiscoveryApi (the plugin base URL is resolved per request via\n * `discoveryApi.getBaseUrl('litellm')`) or a fixed base URL/path string.\n */\n constructor(fetchApi: FetchApi, base: string | DiscoveryApi = '/api/litellm') {\n this.fetchApi = fetchApi;\n this.base = base;\n }\n\n private async basePath(): Promise<string> {\n return typeof this.base === 'string'\n ? this.base\n : this.base.getBaseUrl('litellm');\n }\n\n private async throwIfNotOk(response: Response): Promise<void> {\n if (!response.ok) {\n let body: unknown;\n try { body = await response.json(); } catch { body = await response.text().catch(() => ''); }\n const errorText =\n typeof body === 'object' && body && typeof (body as any).error === 'string'\n ? (body as any).error\n : undefined;\n // Validation failures carry the reason in `details` (\"max_budget: must not\n // exceed 100\"); without it the user would only see \"Invalid request body\".\n const details =\n typeof body === 'object' && body && typeof (body as any).details === 'string'\n ? (body as any).details\n : undefined;\n let message = `${response.status} ${response.statusText}`;\n if (errorText) {\n message = details ? `${errorText}: ${details}` : errorText;\n }\n throw new ApiError(message, response.status, body);\n }\n }\n\n private async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${await this.basePath()}${path}`, window.location.origin);\n if (params) {\n Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value));\n }\n const response = await this.fetchApi.fetch(url.toString());\n await this.throwIfNotOk(response);\n return response.json();\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async del<T>(path: string): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async patch<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async put<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n // User identity is resolved server-side from the Backstage Bearer token.\n // No user_id param needed on the frontend.\n async getUserInfo(): Promise<UserInfo> {\n return this.get<UserInfo>('/user/info');\n }\n\n async listKeys(): Promise<VirtualKey[]> {\n return this.get<VirtualKey[]>('/keys');\n }\n\n async generateKey(request: GenerateKeyRequest): Promise<GenerateKeyResponse> {\n return this.post<GenerateKeyResponse>('/keys/generate', request);\n }\n\n async updateKey(keyId: string, request: UpdateKeyRequest): Promise<VirtualKey> {\n return this.post<VirtualKey>(`/keys/${encodeURIComponent(keyId)}/update`, request);\n }\n\n async deleteKey(keyId: string): Promise<{ success: boolean }> {\n return this.del<{ success: boolean }>(`/keys/${encodeURIComponent(keyId)}`);\n }\n\n async blockKey(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/block`, {});\n }\n\n async unblockKey(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/unblock`, {});\n }\n\n async resetKeySpend(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/reset_spend`, {});\n }\n\n async pruneExpiredKeys(): Promise<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }> {\n return this.post<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }>(\n '/keys/prune-expired',\n {},\n );\n }\n\n async getAuditLogs(params: AuditLogsParams): Promise<PaginatedAuditLogs> {\n const strParams: Record<string, string> = {};\n if (params.page !== undefined) strParams.page = String(params.page);\n if (params.page_size !== undefined) strParams.page_size = String(params.page_size);\n if (params.start_date) strParams.start_date = params.start_date;\n if (params.end_date) strParams.end_date = params.end_date;\n if (params.action) strParams.action = params.action;\n if (params.table_name) strParams.table_name = params.table_name;\n if (params.changed_by) strParams.changed_by = params.changed_by;\n return this.get<PaginatedAuditLogs>('/audit', strParams);\n }\n\n async listModels(): Promise<ModelInfo[]> {\n return this.get<ModelInfo[]>('/models');\n }\n\n async getTeams(): Promise<TeamInfo[]> {\n return this.get<TeamInfo[]>('/teams');\n }\n\n // Teams whose owning_group the caller administers (server-scoped). Distinct\n // from getTeams(), which returns only the teams the caller is a member of.\n async getManagedTeams(): Promise<TeamInfo[]> {\n return this.get<TeamInfo[]>('/teams/managed');\n }\n\n async addTeamMember(\n teamId: string,\n body: { userEntityRef: string; maxBudgetInTeam?: number },\n ): Promise<TeamInfo> {\n return this.post<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/members`,\n body,\n );\n }\n\n async removeTeamMember(\n teamId: string,\n userEntityRef: string,\n ): Promise<TeamInfo> {\n return this.del<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/members?userEntityRef=${encodeURIComponent(\n userEntityRef,\n )}`,\n );\n }\n\n // Vector stores (knowledge bases) the caller may attach \u2014 already filtered\n // server-side to the operator's allowlist.\n async getVectorStores(): Promise<VectorStoreInfo[]> {\n return this.get<VectorStoreInfo[]>('/vector-stores');\n }\n\n async setTeamKnowledgeBases(\n teamId: string,\n vectorStores: string[],\n ): Promise<TeamInfo> {\n return this.put<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/knowledge-bases`,\n { vector_stores: vectorStores },\n );\n }\n\n async getMcpServers(): Promise<McpServerInfo[]> {\n return this.get<McpServerInfo[]>('/mcp-servers');\n }\n\n async setTeamMcpServers(\n teamId: string,\n mcpServers: string[],\n ): Promise<TeamInfo> {\n return this.put<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/mcp-servers`,\n { mcp_servers: mcpServers },\n );\n }\n\n async getUsage(startDate: string, endDate: string): Promise<UsageMetrics> {\n return this.get<UsageMetrics>('/usage', { start_date: startDate, end_date: endDate });\n }\n\n async getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics> {\n return this.get<UsageMetrics>(`/teams/${encodeURIComponent(teamId)}/usage`, {\n start_date: startDate,\n end_date: endDate,\n });\n }\n\n async getConfig(): Promise<LiteLlmConfig> {\n return this.get<LiteLlmConfig>('/config');\n }\n\n async createTeam(request: CreateTeamRequest): Promise<CreateTeamResponse> {\n return this.post<CreateTeamResponse>('/teams', request);\n }\n\n async updateTeam(teamId: string, request: UpdateTeamRequest): Promise<TeamInfo> {\n return this.patch<TeamInfo>(`/teams/${encodeURIComponent(teamId)}`, request);\n }\n}\n", "import { createRouteRef } from '@backstage/frontend-plugin-api';\n\nexport const rootRouteRef = createRouteRef();\n", "import { alpha, useTheme } from '@mui/material/styles';\nimport type { Theme } from '@mui/material/styles';\n\n// \u2500\u2500 formatting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** `2026-08-16` \u2192 `Aug 16`. Falls back to the raw value for anything else. */\nexport const fmtDateShort = (value: string): string => {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value ?? '');\n if (!m) return value;\n return `${MONTHS[Number(m[2]) - 1]} ${Number(m[3])}`;\n};\n\n/** 54253484 \u2192 `54.3M`. Keeps axis labels from swallowing the plot area. */\nexport const fmtCompact = (n: number): string => {\n const v = n ?? 0;\n const abs = Math.abs(v);\n if (abs >= 1e9) return `${(v / 1e9).toFixed(abs >= 1e10 ? 0 : 1)}B`;\n if (abs >= 1e6) return `${(v / 1e6).toFixed(abs >= 1e7 ? 0 : 1)}M`;\n if (abs >= 1e3) return `${(v / 1e3).toFixed(abs >= 1e4 ? 0 : 1)}K`;\n return String(Math.round(v));\n};\n\n/** Compact currency for axis ticks \u2014 `$24`, `$1.2K`. */\nexport const fmtUsdCompact = (n: number): string => {\n const v = n ?? 0;\n if (Math.abs(v) >= 1000) return `$${fmtCompact(v)}`;\n if (Math.abs(v) >= 10) return `$${v.toFixed(0)}`;\n return `$${v.toFixed(2)}`;\n};\n\n// \u2500\u2500 chart palette \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Categorical ramp, ordered so neighbouring series stay distinguishable. */\nexport const CHART_COLORS = [\n '#6366F1', // indigo\n '#14B8A6', // teal\n '#F59E0B', // amber\n '#EC4899', // pink\n '#38BDF8', // sky\n '#84CC16', // lime\n '#F97316', // orange\n '#A855F7', // violet\n] as const;\n\n/** Fixed colours for series that carry meaning rather than identity. */\nexport const SERIES = {\n input: '#6366F1',\n output: '#14B8A6',\n success: '#0d9488',\n failure: '#ea580c',\n spend: '#F59E0B',\n budget: '#ea580c',\n} as const;\n\nconst OTHER_COLOR = '#94A3B8';\n\n/** Stable colour per series name, so a model keeps its colour across charts. */\nexport function chartColor(name: string): string {\n if (name === 'Other') return OTHER_COLOR;\n let h = 5381;\n for (let i = 0; i < name.length; i++) h = ((h << 5) + h + name.charCodeAt(i)) >>> 0;\n return CHART_COLORS[h % CHART_COLORS.length];\n}\n\n/** Axis / grid / legend props shared by every chart, derived from the theme. */\nexport function useChartTheme() {\n const theme = useTheme();\n const tickFill = theme.palette.text.secondary;\n return {\n grid: {\n stroke: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.12 : 0.08),\n strokeDasharray: '2 4',\n vertical: false,\n },\n axis: {\n tick: { fontSize: 11, fill: tickFill },\n tickLine: false,\n axisLine: { stroke: alpha(theme.palette.text.primary, 0.12) },\n },\n legend: {\n wrapperStyle: {\n fontSize: 11,\n color: tickFill,\n paddingTop: 8,\n },\n iconType: 'circle' as const,\n iconSize: 8,\n },\n cursor: { fill: alpha(theme.palette.text.primary, 0.05) },\n };\n}\n\n\n// \u2500\u2500 status pills \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type Tone = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'accent';\n\nexport function toneColor(theme: Theme, tone: Tone): string {\n switch (tone) {\n case 'success': return theme.palette.success.main;\n case 'warning': return theme.palette.warning.main;\n case 'danger': return theme.palette.error.main;\n case 'info': return theme.palette.info.main;\n case 'accent': return theme.palette.primary.main;\n default: return theme.palette.text.secondary;\n }\n}\n\n", "import { FC } from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { fmtDateShort } from './tokens';\n\ninterface ChartTooltipProps {\n active?: boolean;\n label?: string | number;\n payload?: Array<{ name?: string; value?: number; color?: string; dataKey?: string | number }>;\n /** Formats each series value; defaults to a localised integer. */\n valueFormatter?: (value: number) => string;\n /** Formats the header; defaults to the short date form. */\n labelFormatter?: (label: string) => string;\n /** Drop zero-valued series \u2014 useful for stacked charts with many series. */\n hideZero?: boolean;\n}\n\n/**\n * Recharts' default tooltip is an opaque white card with a hard border \u2014 it\n * disappears on dark themes. This one uses the theme's own surface tokens.\n */\nexport const ChartTooltip: FC<ChartTooltipProps> = ({\n active,\n label,\n payload,\n valueFormatter = (v: number) => v.toLocaleString(),\n labelFormatter = fmtDateShort,\n hideZero = false,\n}) => {\n if (!active || !payload?.length) return null;\n const rows = payload.filter(\n p => p.value !== undefined && p.value !== null && (!hideZero || p.value !== 0),\n );\n if (!rows.length) return null;\n return (\n <Paper\n elevation={8}\n sx={{\n px: 1.5,\n py: 1,\n borderRadius: 1.5,\n border: '1px solid',\n borderColor: 'divider',\n minWidth: 150,\n pointerEvents: 'none',\n }}\n >\n <Typography\n variant=\"caption\"\n sx={{ display: 'block', fontWeight: 700, mb: 0.75, letterSpacing: '0.02em' }}\n >\n {typeof label === 'string' ? labelFormatter(label) : label}\n </Typography>\n {rows.map((row, i) => (\n <Box\n key={`${row.dataKey ?? row.name ?? i}`}\n sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: i === 0 ? 0 : 0.5 }}\n >\n <Box\n sx={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n bgcolor: row.color,\n flexShrink: 0,\n }}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ flex: 1, mr: 1.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {row.name}\n </Typography>\n <Typography variant=\"caption\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>\n {valueFormatter(row.value as number)}\n </Typography>\n </Box>\n ))}\n </Paper>\n );\n};\n\n/**\n * Colour key rendered outside the SVG. Recharts' own `<Legend>` cannot ellipsize,\n * so a handful of fully-qualified model names (\"bedrock/eu.anthropic.\u2026\") wrap\n * into a ragged block that eats the plot area.\n */\nexport const SeriesLegend: FC<{ series: Array<{ name: string; color: string }> }> = ({\n series,\n}) => (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 0.5,\n columnGap: 2,\n rowGap: 0.5,\n mt: 1.5,\n }}\n >\n {series.map(s => (\n <Box key={s.name} sx={{ display: 'flex', alignItems: 'center', gap: 0.75, minWidth: 0 }}>\n <Box\n sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: s.color, flexShrink: 0 }}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n title={s.name}\n sx={{\n fontSize: 11,\n maxWidth: 190,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {s.name}\n </Typography>\n </Box>\n ))}\n </Box>\n);\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport { alpha } from '@mui/material/styles';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * A soft status badge. Deliberately *not* MUI's filled `Chip` \u2014 host themes\n * tend to render those as saturated pills, and a table with one screaming\n * orange pill per row is unreadable. Tinted background, hairline border,\n * squared-off corners.\n */\nexport const StatusPill: FC<{\n label: ReactNode;\n tone?: Tone;\n /** Show the leading tone dot. */\n dot?: boolean;\n title?: string;\n sx?: SxProps<Theme>;\n}> = ({ label, tone = 'neutral', dot = true, title, sx }) => (\n <Box\n component=\"span\"\n title={title}\n sx={[\n theme => {\n const c = toneColor(theme, tone);\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 0.625,\n height: 22,\n px: 0.875,\n borderRadius: '6px',\n border: '1px solid',\n borderColor: alpha(c, tone === 'neutral' ? 0.25 : 0.35),\n bgcolor: alpha(c, tone === 'neutral' ? 0.06 : 0.12),\n color: tone === 'neutral' ? theme.palette.text.secondary : c,\n fontSize: 11.5,\n fontWeight: 600,\n lineHeight: 1,\n letterSpacing: '0.01em',\n whiteSpace: 'nowrap',\n maxWidth: '100%',\n };\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n {dot && (\n <Box\n component=\"span\"\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, tone),\n flexShrink: 0,\n })}\n />\n )}\n <Box component=\"span\" sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {label}\n </Box>\n </Box>\n);\n\n/** Quiet monospace tag for identifiers: model names, team slugs, roles. */\nexport const TagChip: FC<{ label: ReactNode; title?: string; mono?: boolean }> = ({\n label,\n title,\n mono = true,\n}) => (\n <Box\n component=\"span\"\n title={title}\n sx={theme => ({\n display: 'inline-flex',\n alignItems: 'center',\n height: 20,\n px: 0.75,\n borderRadius: '5px',\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.08 : 0.05),\n color: theme.palette.text.secondary,\n fontFamily: mono ? 'ui-monospace, SFMono-Regular, Menlo, monospace' : undefined,\n fontSize: 11,\n lineHeight: 1,\n whiteSpace: 'nowrap',\n maxWidth: 220,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n })}\n >\n {label}\n </Box>\n);\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { alpha } from '@mui/material/styles';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n// \u2500\u2500 surfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Page-level surface with a consistent title row. */\nexport const SectionCard: FC<{\n title?: ReactNode;\n subtitle?: ReactNode;\n actions?: ReactNode;\n /** Set when the body renders its own edge-to-edge content (e.g. a table). */\n flush?: boolean;\n children: ReactNode;\n}> = ({ title, subtitle, actions, flush = false, children }) => (\n <Paper sx={{ borderRadius: 2, overflow: 'hidden' }}>\n {(title || actions) && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n flexWrap: 'wrap',\n px: 2.5,\n py: 2,\n }}\n >\n <Box sx={{ minWidth: 0 }}>\n <Typography variant=\"h6\" sx={{ lineHeight: 1.2 }}>{title}</Typography>\n {subtitle && (\n <Typography variant=\"caption\" color=\"text.secondary\">{subtitle}</Typography>\n )}\n </Box>\n {actions && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n {actions}\n </Box>\n )}\n </Box>\n )}\n <Box sx={flush ? undefined : { px: 2.5, pb: 2.5, pt: title ? 0 : 2.5 }}>{children}</Box>\n </Paper>\n);\n\n/** Bordered frame around a single chart, with its own caption row. */\nexport const ChartCard: FC<{\n title: ReactNode;\n meta?: ReactNode;\n height?: number;\n children: ReactNode;\n}> = ({ title, meta, height = 240, children }) => (\n // The plot area must have an explicit height, never a flex-derived one:\n // Recharts' ResponsiveContainer measures its parent, so a parent that sizes\n // itself from its children instead spins in a measure/resize loop.\n <Paper variant=\"outlined\" sx={{ p: 2, borderRadius: 2, height: '100%' }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 1, mb: 1.5, flexWrap: 'wrap' }}>\n <Typography\n variant=\"subtitle2\"\n sx={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase' }}\n >\n {title}\n </Typography>\n {meta && (\n <Typography variant=\"caption\" color=\"text.secondary\">{meta}</Typography>\n )}\n </Box>\n <Box sx={{ height, width: '100%' }}>{children}</Box>\n </Paper>\n);\n\n// \u2500\u2500 metrics \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MetricDef {\n label: string;\n value: string;\n hint?: string;\n tone?: Tone;\n}\n\n/**\n * KPI row rendered as one framed strip divided into cells, rather than four\n * loose cards. Cells share a baseline grid so the numbers line up even when\n * only some of them carry a hint.\n */\nexport const MetricStrip: FC<{ metrics: MetricDef[] }> = ({ metrics }) => (\n <Paper\n variant=\"outlined\"\n sx={{\n borderRadius: 2,\n display: 'grid',\n gridTemplateColumns: { xs: '1fr 1fr', md: `repeat(${metrics.length}, 1fr)` },\n overflow: 'hidden',\n }}\n >\n {metrics.map((m, i) => (\n <Box\n key={m.label}\n sx={theme => ({\n px: 2.5,\n py: 2,\n borderLeft: i === 0 ? 0 : '1px solid',\n borderTop: 0,\n borderColor: 'divider',\n [theme.breakpoints.down('md')]: {\n borderLeft: i % 2 === 0 ? 0 : '1px solid',\n borderTop: i < 2 ? 0 : '1px solid',\n borderColor: 'divider',\n },\n })}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.875, mb: 0.75 }}>\n <Box\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, m.tone ?? 'accent'),\n flexShrink: 0,\n })}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n {m.label}\n </Typography>\n </Box>\n <Typography\n sx={{ fontSize: 26, fontWeight: 700, lineHeight: 1.15, fontVariantNumeric: 'tabular-nums' }}\n >\n {m.value}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 0.5, minHeight: 16 }}\n >\n {m.hint ?? '\u00A0'}\n </Typography>\n </Box>\n ))}\n </Paper>\n);\n\n/** Label + value pair used inside cards. */\nexport const Stat: FC<{ label: string; value: ReactNode }> = ({ label, value }) => (\n <Box sx={{ minWidth: 0 }}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 10.5, fontWeight: 600, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n {label}\n </Typography>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', mt: 0.25 }}\n >\n {value}\n </Typography>\n </Box>\n);\n\n\n// \u2500\u2500 segmented control \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Secondary navigation inside a card. Hand-rolled rather than a second set of\n * `Tabs` so it reads as subordinate to the page tabs instead of competing\n * with them, and so host theme overrides on `MuiTab` don't leak in.\n */\nexport function SegmentedControl<T extends string>({\n value,\n onChange,\n options,\n}: {\n value: T;\n onChange: (value: T) => void;\n options: Array<{ value: T; label: string }>;\n}) {\n return (\n <Box\n role=\"tablist\"\n sx={theme => ({\n display: 'inline-flex',\n gap: 0.25,\n p: 0.375,\n borderRadius: 1.5,\n border: '1px solid',\n borderColor: theme.palette.divider,\n })}\n >\n {options.map(opt => {\n const selected = opt.value === value;\n return (\n <ButtonBase\n key={opt.value}\n role=\"tab\"\n aria-selected={selected}\n onClick={() => onChange(opt.value)}\n sx={theme => ({\n px: 1.5,\n height: 28,\n borderRadius: 1,\n fontSize: 13,\n fontWeight: selected ? 700 : 500,\n // Tint the selection with the accent rather than swapping in a\n // surface colour: on a dark theme `background.paper` sits *behind*\n // the track, so the selected chip would read as recessed.\n color: selected ? theme.palette.primary.main : theme.palette.text.secondary,\n bgcolor: selected\n ? alpha(theme.palette.primary.main, theme.palette.mode === 'dark' ? 0.2 : 0.11)\n : 'transparent',\n transition: theme.transitions.create(['background-color', 'color']),\n '&:hover': {\n color: selected ? theme.palette.primary.main : theme.palette.text.primary,\n bgcolor: selected\n ? alpha(theme.palette.primary.main, theme.palette.mode === 'dark' ? 0.26 : 0.15)\n : alpha(theme.palette.text.primary, 0.05),\n },\n })}\n >\n {opt.label}\n </ButtonBase>\n );\n })}\n </Box>\n );\n}\n\n// \u2500\u2500 tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Shared table chrome: quiet uppercase headers, hairline row rules, a hover\n * highlight, and tabular figures so numeric columns align.\n */\nexport const dataTableSx: SxProps<Theme> = theme => ({\n // Element selectors, not `.MuiTableCell-head`: host apps may set a MUI\n // classname prefix (Backstage ships `v5-`), which breaks global class targeting.\n '& thead th': {\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: '0.07em',\n textTransform: 'uppercase',\n color: theme.palette.text.secondary,\n backgroundColor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.04 : 0.02),\n borderBottom: `1px solid ${theme.palette.divider}`,\n whiteSpace: 'nowrap',\n paddingTop: theme.spacing(1.25),\n paddingBottom: theme.spacing(1.25),\n },\n '& tbody td': {\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.6)}`,\n paddingTop: theme.spacing(1.25),\n paddingBottom: theme.spacing(1.25),\n fontVariantNumeric: 'tabular-nums',\n },\n '& tbody tr:last-of-type td': {\n borderBottom: 0,\n },\n '& tbody tr:hover': {\n backgroundColor: alpha(theme.palette.text.primary, 0.03),\n },\n});\n\n/** Muted icon button that only picks up its semantic colour on hover. */\nexport const quietIconButtonSx = (tone: Tone = 'neutral'): SxProps<Theme> => theme => ({\n color: theme.palette.text.secondary,\n '&:hover': {\n color: toneColor(theme, tone),\n bgcolor: alpha(toneColor(theme, tone), 0.1),\n },\n});\n\n/** Centered empty / loading state for a card body. */\nexport const EmptyState: FC<{\n message: string;\n hint?: string;\n height?: number;\n action?: ReactNode;\n}> = ({ message, hint, height, action }) => (\n <Box\n sx={{\n height,\n minHeight: height ? undefined : 120,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 1,\n textAlign: 'center',\n py: 3,\n }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">{message}</Typography>\n {hint && <Typography variant=\"caption\" color=\"text.secondary\">{hint}</Typography>}\n {action}\n </Box>\n);\n\n", "import { FC } from 'react';\nimport Box from '@mui/material/Box';\nimport { alpha } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * Progress meter with an explicitly drawn track. MUI's `LinearProgress` tints\n * its track from the bar colour, which makes an empty bar look full.\n */\nexport const Meter: FC<{\n value: number;\n tone?: Tone;\n height?: number;\n /** Optional aria-label for accessibility. */\n ariaLabel?: string;\n}> = ({\n value,\n tone = 'accent',\n height = 5,\n ariaLabel,\n}) => {\n const clamped = Math.max(0, Math.min(100, value));\n const isOverCap = value > 100;\n\n return (\n <Box>\n <Box\n sx={theme => ({\n height,\n borderRadius: height,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.12 : 0.08),\n overflow: 'hidden',\n })}\n role=\"meter\"\n aria-valuenow={clamped}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n aria-valuetext={isOverCap ? `${Math.round(value)}% \u2014 over cap` : undefined}\n >\n <Box\n sx={theme => ({\n height: '100%',\n width: `${clamped}%`,\n borderRadius: height,\n bgcolor: toneColor(theme, tone),\n transition: theme.transitions.create('width'),\n })}\n />\n </Box>\n {isOverCap && (\n <Box\n sx={{\n textAlign: 'center',\n fontSize: 10,\n fontWeight: 600,\n color: 'text.primary',\n mt: 0.25,\n }}\n >\n Over cap\n </Box>\n )}\n </Box>\n );\n};\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { alpha } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * Ring gauge for at-a-glance ratios. Hand-drawn SVG rather than MUI's\n * `CircularProgress`: the track has to stay a neutral hairline (MUI tints it\n * from the bar colour, so an empty ring reads as full), and the value may\n * legitimately exceed 100% \u2014 the arc clamps at a full turn while the centre\n * label keeps the real number.\n */\nexport const Gauge: FC<{\n /** Share consumed, 0..100+ (unclamped for the label). */\n value: number;\n tone?: Tone;\n /** Outer diameter in px. */\n size?: number;\n /** Ring thickness in px. */\n thickness?: number;\n /** Centre content; defaults to the rounded percentage. */\n label?: ReactNode;\n /** Small caption under the value, inside the ring. */\n caption?: ReactNode;\n /** Optional aria-label for accessibility. */\n ariaLabel?: string;\n}> = ({ value, tone = 'accent', size = 72, thickness = 6, label, caption, ariaLabel }) => {\n const clamped = Math.max(0, Math.min(100, value ?? 0));\n const r = (size - thickness) / 2;\n const c = 2 * Math.PI * r;\n const dash = (clamped / 100) * c;\n const isOverCap = value > 100;\n\n return (\n <Box\n sx={theme => ({\n position: 'relative',\n width: size,\n height: size,\n color: toneColor(theme, tone),\n })}\n role=\"meter\"\n aria-valuenow={clamped}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n aria-valuetext={isOverCap ? `${Math.round(value)}% \u2014 over cap` : undefined}\n >\n <Box\n component=\"svg\"\n viewBox={`0 0 ${size} ${size}`}\n width={size}\n height={size}\n sx={{ display: 'block', transform: 'rotate(-90deg)' }}\n >\n <Box\n component=\"circle\"\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n strokeWidth={thickness}\n sx={theme => ({\n stroke: alpha(\n theme.palette.text.primary,\n theme.palette.mode === 'dark' ? 0.14 : 0.09,\n ),\n })}\n />\n <Box\n component=\"circle\"\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n strokeWidth={thickness}\n strokeLinecap=\"round\"\n strokeDasharray={`${dash} ${c - dash}`}\n sx={theme => ({\n stroke: 'currentColor',\n transition: theme.transitions.create('stroke-dasharray'),\n })}\n />\n </Box>\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n }}\n >\n {/* Past 100% the number stays visible \u2014 a wide \"Over cap\" word in a\n small ring both overflows and collides with the stroke, so the\n status is spelled out in the row that owns the gauge instead. */}\n <Typography\n sx={{\n fontSize: size <= 64 ? 15 : 18,\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n color: isOverCap ? 'currentColor' : 'text.primary',\n }}\n >\n {label ?? `${Math.round(value)}%`}\n </Typography>\n {caption && (\n <Typography\n variant=\"caption\"\n sx={{\n fontSize: 9.5,\n color: 'text.secondary',\n mt: 0.25,\n whiteSpace: 'nowrap',\n }}\n >\n {caption}\n </Typography>\n )}\n </Box>\n </Box>\n );\n};\n\n", "export * from './tokens';\nexport * from './charts';\nexport * from './pills';\nexport * from './surfaces';\nexport * from './Meter';\nexport * from './Gauge';\n", "import { FC } from 'react';\nimport Button from '@mui/material/Button';\nimport { Add } from '@mui/icons-material';\nimport { Link } from '@backstage/core-components';\n\n/**\n * The single \"create a key\" call-to-action used everywhere in the plugin \u2014\n * the plugin page (header, keys table) and the homepage budget card all\n * render this instead of their own inline `Button`, so the copy, icon and\n * styling stay identical.\n */\nexport interface GenerateKeyButtonProps {\n /** Deep-link target (e.g. `/litellm?generate=1`). Ignored when `onClick` is set. */\n to?: string;\n /** Click handler. Takes precedence over `to` when both are given. */\n onClick?: () => void;\n /** Override the default `Generate New Key` copy (e.g. empty-state variants). */\n label?: string;\n /** Button size \u2014 card footers use `small`, page headers the default. */\n size?: 'small' | 'medium' | 'large';\n /** Stretch to the container width (card-footers). Defaults to false. */\n fullWidth?: boolean;\n /** Disabled state (e.g. until the account data loads). A disabled `to` renders inert. */\n disabled?: boolean;\n}\n\nexport const GenerateKeyButton: FC<GenerateKeyButtonProps> = ({\n to,\n onClick,\n label = 'Generate New Key',\n size,\n fullWidth = false,\n disabled = false,\n}) => {\n if (onClick && !disabled) {\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n onClick={onClick}\n >\n {label}\n </Button>\n );\n }\n if (to && !disabled) {\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n component={Link}\n to={to}\n >\n {label}\n </Button>\n );\n }\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n disabled\n >\n {label}\n </Button>\n );\n};\n", "import { FC, ReactNode, useMemo } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Paper from '@mui/material/Paper';\nimport Divider from '@mui/material/Divider';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport { alpha } from '@mui/material/styles';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { expiryStatus } from '../api';\nimport { TagChip, Tone } from './ui';\nimport { GenerateKeyButton } from './GenerateKeyButton';\n\ninterface DashboardHeaderProps {\n userInfo: UserInfo;\n teams: TeamInfo[];\n keys: VirtualKey[];\n loading: boolean;\n keysError?: Error;\n onGenerateKeyClick: () => void;\n onNavigateToFilter?: (filter: 'expired' | 'expiring') => void;\n /** Page tab bar, rendered flush with the bottom edge of the header card. */\n tabs?: ReactNode;\n}\n\n/** Two initials from an email or username, for the identity badge. */\nfunction initials(name: string): string {\n const local = name.split('@')[0] ?? name;\n const parts = local.split(/[.\\-_\\s]+/).filter(Boolean);\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();\n return local.slice(0, 2).toUpperCase();\n}\n\nconst CountStat: FC<{\n value: number | null;\n label: string;\n tone: Tone;\n clickable?: boolean;\n onClick?: () => void;\n}> = ({ value, label, tone, clickable, onClick }) => {\n // Zero counts stay grey: only a real expiry deserves a colour.\n // Null indicates a fetch error and displays as \"\u2013\" without a coloured dot.\n const active = value !== null && value > 0;\n const display = value === null ? '\u2013' : value;\n const isClickable = clickable && active && onClick;\n\n const content = (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Box\n aria-hidden=\"true\"\n sx={theme => ({\n width: 7,\n height: 7,\n borderRadius: '50%',\n flexShrink: 0,\n bgcolor: active\n ? (tone === 'danger' && theme.palette.error.main) ||\n (tone === 'warning' && theme.palette.warning.main) ||\n theme.palette.primary.main\n : alpha(theme.palette.text.primary, 0.25),\n })}\n />\n <Typography\n component=\"span\"\n sx={{\n fontSize: 15,\n fontWeight: 700,\n lineHeight: 1,\n fontVariantNumeric: 'tabular-nums',\n ...(isClickable && { cursor: 'pointer', textDecoration: 'underline' }),\n }}\n >\n {display}\n </Typography>\n <Typography\n component=\"span\"\n color=\"text.secondary\"\n sx={{\n fontSize: 11,\n fontWeight: 600,\n letterSpacing: '0.07em',\n textTransform: 'uppercase',\n ...(isClickable && { cursor: 'pointer' }),\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n\n if (isClickable) {\n return (\n <ButtonBase onClick={onClick} sx={{ borderRadius: 0.5, px: 0.5, py: 0.25 }}>\n {content}\n </ButtonBase>\n );\n }\n\n return content;\n};\n\nexport const DashboardHeader: FC<DashboardHeaderProps> = ({\n userInfo,\n teams,\n keys,\n loading,\n keysError,\n onGenerateKeyClick,\n onNavigateToFilter,\n tabs,\n}) => {\n const counts = useMemo(() => {\n if (keysError) {\n return { total: null, expired: null, expiringSoon: null };\n }\n const expired = keys.filter(k => expiryStatus(k.expires_at) === 'expired').length;\n const expiringSoon = keys.filter(k => expiryStatus(k.expires_at) === 'soon').length;\n return { total: keys.length, expired, expiringSoon };\n }, [keys, keysError]);\n\n const displayName = userInfo.user_email ?? userInfo.email ?? userInfo.user_id;\n\n return (\n <Paper sx={{ borderRadius: 2, overflow: 'hidden' }}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 2,\n flexWrap: 'wrap',\n px: 2.5,\n pt: 2.5,\n pb: 2,\n }}\n >\n <Box\n sx={theme => ({\n width: 44,\n height: 44,\n borderRadius: 1.5,\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette.primary.main, 0.12),\n color: theme.palette.primary.main,\n fontSize: 15,\n fontWeight: 700,\n letterSpacing: '0.02em',\n })}\n >\n {initials(displayName)}\n </Box>\n\n <Box sx={{ flexGrow: 1, minWidth: 220 }}>\n <Typography variant=\"h6\" sx={{ lineHeight: 1.25, wordBreak: 'break-word' }}>\n {displayName}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {userInfo.user_id}\n </Typography>\n\n <Box sx={{ display: 'flex', gap: 0.75, flexWrap: 'wrap', mt: 1, minHeight: 20 }}>\n {loading ? (\n <Skeleton variant=\"rounded\" width={140} height={20} />\n ) : (\n teams.map(team => (\n <TagChip\n key={team.team_id}\n label={team.team_alias || team.team_id}\n title={team.team_id}\n />\n ))\n )}\n </Box>\n </Box>\n\n <GenerateKeyButton onClick={onGenerateKeyClick} />\n </Box>\n\n <Divider />\n\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 2.5,\n flexWrap: 'wrap',\n px: 2.5,\n py: 1.5,\n }}\n >\n <CountStat value={counts.total} label=\"keys\" tone=\"accent\" />\n <Divider orientation=\"vertical\" flexItem sx={{ my: 0.25 }} aria-hidden=\"true\" />\n <CountStat\n value={counts.expired}\n label=\"expired\"\n tone=\"danger\"\n clickable\n onClick={() => onNavigateToFilter?.('expired')}\n />\n <Divider orientation=\"vertical\" flexItem sx={{ my: 0.25 }} aria-hidden=\"true\" />\n <CountStat\n value={counts.expiringSoon}\n label=\"expiring soon\"\n tone=\"warning\"\n clickable\n onClick={() => onNavigateToFilter?.('expiring')}\n />\n </Box>\n\n {tabs && (\n <>\n <Divider />\n <Box sx={{ px: 1 }}>{tabs}</Box>\n </>\n )}\n </Paper>\n );\n};\n", "import { useState, useEffect, useRef } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { alertApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Pure helper: determine if the Clipboard API is available.\n */\nexport function isClipboardApiAvailable(): boolean {\n return typeof navigator !== 'undefined' && !!navigator.clipboard?.writeText;\n}\n\n/**\n * Pure helper: fallback copy via textarea and document.execCommand.\n * Returns true if successful, false otherwise.\n */\nexport function fallbackCopyToClipboard(text: string): boolean {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n textarea.style.pointerEvents = 'none';\n document.body.appendChild(textarea);\n try {\n textarea.select();\n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n return success;\n } catch {\n document.body.removeChild(textarea);\n return false;\n }\n}\n\n/**\n * Pure helper: create a timer for the copied state.\n * Returns the timer ID so the caller can manage cleanup.\n */\nexport function startCopiedTimer(\n onCopiedChange: (copied: boolean) => void,\n durationMs: number = 2000,\n): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n onCopiedChange(false);\n }, durationMs);\n}\n\n/**\n * Hook: copy text to clipboard with visual feedback.\n *\n * @returns {copy, copied, error} - async copy function, copied state, and error if any\n *\n * - `copy(text)`: async function that copies text and returns true if successful\n * - `copied`: true for 2s after successful copy, then resets\n * - `error`: error object if copy failed; shows via alertApi\n *\n * Uses navigator.clipboard.writeText with fallback to textarea + execCommand.\n */\nexport function useCopyToClipboard(): {\n copy: (text: string) => Promise<boolean>;\n copied: boolean;\n error: Error | null;\n} {\n const alertApi = useApi(alertApiRef);\n const [copied, setCopied] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Clear timer on unmount\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const copy = async (text: string): Promise<boolean> => {\n // Clear any existing timer\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n setError(null);\n\n try {\n if (isClipboardApiAvailable()) {\n await navigator.clipboard.writeText(text);\n } else {\n const success = fallbackCopyToClipboard(text);\n if (!success) {\n throw new Error('Clipboard copy failed');\n }\n }\n setCopied(true);\n timerRef.current = startCopiedTimer(setCopied, 2000);\n return true;\n } catch (err) {\n const copyError = err instanceof Error ? err : new Error('Copy to clipboard failed');\n setError(copyError);\n alertApi.post({\n message: 'Could not copy to clipboard',\n severity: 'error',\n });\n return false;\n }\n };\n\n return { copy, copied, error };\n}\n", "/**\n * Unified hook for fetching the user's LiteLLM profile: userInfo, teams, keys, models, and config.\n * Results are cached per API instance with a 30s TTL and single-flight deduplication.\n * Callers can invalidate the cache after mutations to ensure fresh data.\n */\n\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { liteLlmApiRef, LiteLlmApiInterface } from '../api';\nimport { UserInfo, TeamInfo, VirtualKey, ModelInfo, LiteLlmConfig } from '../types';\nimport { profileCacheInstance, ProfileCache } from '../profileCache';\n\nexport interface LiteLLMProfileResult {\n userInfo: UserInfo | null;\n teams: TeamInfo[];\n keys: VirtualKey[];\n models: ModelInfo[];\n config: LiteLlmConfig | null;\n loading: boolean;\n error: string | null;\n retry: () => void;\n}\n\ninterface ProfileData {\n userInfo: UserInfo | null;\n teams: TeamInfo[];\n keys: VirtualKey[];\n models: ModelInfo[];\n config: LiteLlmConfig | null;\n}\n\n/**\n * Fetch the complete user profile (userInfo, teams, keys, models, config).\n * Results are cached with a 30s TTL and single-flight deduplication per API instance.\n * Call the returned `retry()` after mutations to invalidate the cache.\n */\nexport function useLiteLLMProfile(cache: ProfileCache = profileCacheInstance): LiteLLMProfileResult {\n const api = useApi(liteLlmApiRef);\n const [data, setData] = useState<ProfileData>({\n userInfo: null,\n teams: [],\n keys: [],\n models: [],\n config: null,\n });\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const retryCounterRef = useRef(0);\n\n const fetchProfile = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [userInfo, teams, keys, models, config] = await Promise.all([\n cache.memoize(api, 'profile-userInfo', () => api.getUserInfo()),\n cache.memoize(api, 'profile-teams', () => api.getTeams()),\n cache.memoize(api, 'profile-keys', () => api.listKeys()),\n cache.memoize(api, 'profile-models', () => api.listModels()),\n cache.memoize(api, 'profile-config', () => api.getConfig()),\n ]);\n\n setData({ userInfo, teams, keys, models, config });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n }, [api, cache]);\n\n useEffect(() => {\n fetchProfile();\n }, [api, fetchProfile]);\n\n const retry = useCallback(() => {\n cache.invalidateProfile(api);\n retryCounterRef.current++;\n fetchProfile();\n }, [api, cache, fetchProfile]);\n\n return {\n ...data,\n loading,\n error,\n retry,\n };\n}\n\n/**\n * Invalidate the profile cache for an API instance after a mutation\n * (e.g., after creating/updating/deleting a key or team).\n *\n * @param api The API instance to invalidate.\n * @param cache The cache instance (defaults to the singleton).\n */\nexport function invalidateLiteLLMProfile(\n api: LiteLlmApiInterface,\n cache: ProfileCache = profileCacheInstance,\n): void {\n cache.invalidateProfile(api);\n}\n", "export { useCopyToClipboard } from './useCopyToClipboard';\nexport { useLiteLLMProfile, invalidateLiteLLMProfile } from './useLiteLLMProfile';\nexport type { LiteLLMProfileResult } from './useLiteLLMProfile';\n", "import type { VirtualKey } from './types';\n\n/**\n * Returns a display label for a key: alias if present, otherwise the masked key.\n * Handles missing alias and odd/short masked strings gracefully.\n */\nexport function keyDisplayLabel(key: VirtualKey): string {\n if (key.key_alias) {\n return key.key_alias;\n }\n return key.key || '\u2014';\n}\n\n/**\n * Extracts the last 4 characters from a key's masked value.\n * Returns empty string if the key is shorter than 4 chars.\n */\nexport function keyLast4(key: VirtualKey): string {\n if (!key.key || key.key.length < 4) {\n return '';\n }\n return key.key.slice(-4);\n}\n\n/**\n * Generates the confirmation copy for pruning expired keys.\n * Handles singular and plural correctly.\n */\nexport function pruneCopy(n: number): string {\n if (n === 1) {\n return 'Remove 1 expired key from the list. It already doesn\\'t work.';\n }\n return `Remove ${n} expired keys from the list. They already don't work.`;\n}\n\n/** Outcome of one permission check: granted, refused, or still loading (neither). */\nexport interface PermissionState {\n allowed: boolean;\n denied: boolean;\n}\n\n/**\n * Label and enabled-state of the row's block/unblock button. Blocking needs the\n * key-manage permission; unblocking needs the dedicated unblock permission (the\n * server does not let owners lift a block on their own say-so). \"No permission\"\n * wording only appears after a real denial, never while permissions load.\n */\nexport function blockButtonState(\n blocked: boolean | undefined,\n manage: PermissionState,\n unblock: PermissionState,\n): { label: string; disabled: boolean } {\n if (blocked) {\n return {\n label: unblock.denied ? 'No permission to unblock keys' : 'Unblock key',\n disabled: !unblock.allowed,\n };\n }\n return {\n label: manage.denied\n ? 'No permission to block keys'\n : 'Block key \\u2014 suspends without revoking',\n disabled: !manage.allowed,\n };\n}\n", "const currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n});\n\n/**\n * Format a number as USD currency with 2 decimals. Non-zero values below\n * one cent render as `<$0.01`. Zero, null, undefined, or NaN render as `$0.00`.\n * Negative values keep the leading minus sign.\n */\nexport const fmtUsd = (n: number | null | undefined): string => {\n if (n === null || n === undefined || Number.isNaN(n)) {\n return '$0.00';\n }\n if (n === 0) {\n return '$0.00';\n }\n // Non-zero values below one cent\n const abs = Math.abs(n);\n if (abs > 0 && abs < 0.01) {\n return n < 0 ? '-<$0.01' : '<$0.01';\n }\n return currencyFormatter.format(n);\n};\n\nexport const fmtInt = (n: number) => (n ?? 0).toLocaleString();\n\n/**\n * Format a count for display, showing \"\u2013\" when the value is null or undefined.\n * Used to indicate that data failed to load, distinct from a zero count.\n */\nexport const formatCount = (n: number | null | undefined): string => {\n return n === null || n === undefined ? '\u2013' : fmtInt(n);\n};\n\n/**\n * Estimate how many tokens a USD budget buys at a given per-token price.\n * Returns null when the price is missing or non-positive.\n */\nexport const estimateTokensFromBudget = (budget: number, pricePerToken?: number): number | null => {\n if (!pricePerToken || pricePerToken <= 0 || !budget || budget <= 0) return null;\n return Math.floor(budget / pricePerToken);\n};\n\n/**\n * Format TPM and RPM limits for display. When neither limit is set (both null/undefined),\n * returns 'Unlimited'. Otherwise returns formatted values with 'Unlimited' for the missing limit.\n * Uses fmtInt for digit grouping.\n */\nexport const fmtLimits = (tpm: number | null | undefined, rpm: number | null | undefined): string => {\n const tpmStr = tpm ? fmtInt(tpm) : 'Unlimited';\n const rpmStr = rpm ? fmtInt(rpm) : 'Unlimited';\n if (tpmStr === 'Unlimited' && rpmStr === 'Unlimited') {\n return 'Unlimited';\n }\n return `${tpmStr} / ${rpmStr}`;\n};\n\nexport interface ModelInfo {\n model_name: string;\n}\n\nexport interface UsageModelBreakdown {\n total_spend: number;\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\n/**\n * Filter models to only those that have usage data in the given period.\n * Keeps 'all' as a first option and extracts model names from the full list,\n * then filters to only those present in the usage breakdown.\n */\nexport const modelsWithUsage = (\n usage: { usage_by_model?: Record<string, UsageModelBreakdown> } | null,\n models: ModelInfo[],\n): string[] => {\n if (!usage?.usage_by_model) {\n return models.map(m => m.model_name);\n }\n const usedNames = Object.keys(usage.usage_by_model);\n const modelsInUsage = new Set(usedNames);\n const known = models.map(m => m.model_name);\n // Keep the accessible-models order, then append models that appear in usage\n // but are no longer listed (e.g. removed from the proxy since) so they can\n // still be filtered on.\n return [\n ...known.filter(name => modelsInUsage.has(name)),\n ...usedNames.filter(name => !known.includes(name)),\n ];\n};\n", "/**\n * Pure filtering functions for key lists.\n */\n\nimport { VirtualKey } from './types';\nimport { expiryStatus } from './api';\n\nexport type KeyFilterType = 'expired' | 'expiring' | undefined;\n\n/**\n * Filter keys by expiry status.\n * @param keys List of keys to filter\n * @param filter Filter type: 'expired', 'expiring', or undefined (no filter)\n * @returns Filtered list of keys\n */\nexport function filterKeysByStatus(keys: VirtualKey[], filter: KeyFilterType): VirtualKey[] {\n if (!filter) return keys;\n\n return keys.filter(key => {\n const status = expiryStatus(key.expires_at);\n if (filter === 'expired') return status === 'expired';\n if (filter === 'expiring') return status === 'soon';\n return true;\n });\n}\n", "import { FC, useMemo, useState } from 'react';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableSortLabel from '@mui/material/TableSortLabel';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Skeleton from '@mui/material/Skeleton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Tooltip from '@mui/material/Tooltip';\nimport Chip from '@mui/material/Chip';\nimport { alpha } from '@mui/material/styles';\nimport { ContentCopy, Delete, Edit, Autorenew, Search, Lock, LockOpen, Check, Close } from '@mui/icons-material';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n litellmKeyManagePermission,\n litellmKeyRevokePermission,\n litellmKeyUnblockPermission,\n} from '@acarmisc/backstage-plugin-litellm-common';\nimport { useCopyToClipboard } from '../hooks';\nimport { expiryStatus } from '../api';\nimport { keyDisplayLabel, keyLast4, pruneCopy, blockButtonState } from '../keyLabels';\nimport { fmtUsd, fmtLimits } from '../format';\nimport { filterKeysByStatus, type KeyFilterType } from '../keyFilter';\nimport { GenerateKeyButton } from './GenerateKeyButton';\nimport {\n VirtualKey,\n} from '../types';\nimport {\n EmptyState,\n Meter,\n SectionCard,\n StatusPill,\n TagChip,\n Tone,\n dataTableSx,\n quietIconButtonSx,\n} from './ui';\n\ninterface KeysTableProps {\n keys: VirtualKey[];\n /** Opens the shared key form dialog in create mode (rendered at page level). */\n onGenerateKeyClick: () => void;\n /** Opens the shared key form dialog in edit mode for the given key. */\n onEditKey: (key: VirtualKey) => void;\n loading: boolean;\n onBlockKey: (keyId: string) => Promise<void>;\n onUnblockKey: (keyId: string) => Promise<void>;\n onDeleteKey: (keyId: string) => Promise<void>;\n onPruneExpiredKeys: () => Promise<{ pruned: number }>;\n filter?: KeyFilterType;\n onClearFilter?: () => void;\n}\n\nconst shortKeyId = (token: string): string => {\n if (!token) return '-';\n if (token.length <= 16) return token;\n return `${token.slice(0, 12)}\u2026`;\n};\n\nconst formatDate = (dateStr: string): string => {\n try {\n return new Date(dateStr).toLocaleDateString();\n } catch {\n return dateStr;\n }\n};\n\nfunction expiryChipLabel(status: 'expired' | 'soon' | 'ok', expiresAt: string): string {\n if (status === 'expired') return 'Expired';\n if (status === 'soon') return `${Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 86400000)}d left`;\n return formatDate(expiresAt);\n}\n\nfunction expiryTone(status: 'expired' | 'soon' | 'ok'): Tone {\n if (status === 'expired') return 'danger';\n if (status === 'soon') return 'warning';\n return 'neutral';\n}\n\nfunction ExpiryCell({ expiresAt }: { expiresAt?: string }) {\n const status = expiryStatus(expiresAt);\n if (!status) {\n return <Typography variant=\"body2\" color=\"text.secondary\">Never</Typography>;\n }\n // A key that is simply valid needs no badge \u2014 plain text keeps the column\n // quiet so the handful of expired/expiring rows actually stand out.\n if (status === 'ok') {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {formatDate(expiresAt!)}\n </Typography>\n );\n }\n return (\n <StatusPill\n label={expiryChipLabel(status, expiresAt!)}\n tone={expiryTone(status)}\n title={`Expires ${formatDate(expiresAt!)}`}\n />\n );\n}\n\nfunction budgetTone(pct: number): Tone {\n if (pct >= 100) return 'danger';\n if (pct >= 80) return 'warning';\n return 'accent';\n}\n\nfunction keyBlockIcon(isBlocking: boolean, blocked?: boolean) {\n if (isBlocking) return <CircularProgress size={18} />;\n if (blocked) return <LockOpen fontSize=\"small\" />;\n return <Lock fontSize=\"small\" />;\n}\n\nfunction BudgetCell({ spend, maxBudget }: { spend: number; maxBudget?: number }) {\n if (!maxBudget) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtUsd(spend)}\n <Typography component=\"span\" variant=\"caption\" sx={{ ml: 0.5, opacity: 0.7 }}>\n / Unlimited\n </Typography>\n </Typography>\n );\n }\n const pct = Math.min(100, (spend / maxBudget) * 100);\n return (\n <Box minWidth={104}>\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums', mb: 0.5 }}>\n {fmtUsd(spend)}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\" sx={{ ml: 0.5 }}>\n / {fmtUsd(maxBudget)}\n </Typography>\n </Typography>\n <Meter value={pct} tone={budgetTone(pct)} height={4} />\n </Box>\n );\n}\n\ntype SortKey = 'alias' | 'created' | 'expires' | 'budget' | 'limits' | 'models';\ntype SortDirection = 'asc' | 'desc';\n\nfunction compareKeys(a: VirtualKey, b: VirtualKey, sortKey: SortKey): number {\n switch (sortKey) {\n case 'alias': return (a.key_alias ?? '').localeCompare(b.key_alias ?? '');\n case 'created': return a.created_at.localeCompare(b.created_at);\n case 'expires': return (a.expires_at ?? '').localeCompare(b.expires_at ?? '');\n case 'budget': return (a.max_budget ?? Infinity) - (b.max_budget ?? Infinity);\n case 'limits': return (a.tpm_limit ?? Infinity) - (b.tpm_limit ?? Infinity) || (a.rpm_limit ?? Infinity) - (b.rpm_limit ?? Infinity);\n case 'models': return (a.models ?? []).join(',').localeCompare((b.models ?? []).join(','));\n default: return 0;\n }\n}\n\nexport const KeysTable: FC<KeysTableProps> = ({\n keys,\n loading,\n onGenerateKeyClick,\n onEditKey,\n onBlockKey,\n onUnblockKey,\n onDeleteKey,\n onPruneExpiredKeys,\n filter,\n onClearFilter,\n}) => {\n // Permission checks\n const managePermission = usePermission({ permission: litellmKeyManagePermission });\n const revokePermission = usePermission({ permission: litellmKeyRevokePermission });\n const unblockPermission = usePermission({ permission: litellmKeyUnblockPermission });\n const canManageKeys = !managePermission.loading && managePermission.allowed;\n const canRevokeKeys = !revokePermission.loading && revokePermission.allowed;\n // Only claim \"no permission\" after a real denial, not while still checking.\n const manageDenied = !managePermission.loading && !managePermission.allowed;\n const revokeDenied = !revokePermission.loading && !revokePermission.allowed;\n const canUnblockKeys = !unblockPermission.loading && unblockPermission.allowed;\n const unblockDenied = !unblockPermission.loading && !unblockPermission.allowed;\n\n // Block confirmation\n const [blockConfirmKey, setBlockConfirmKey] = useState<VirtualKey | null>(null);\n const [blockSubmitting, setBlockSubmitting] = useState(false);\n\n // Delete confirmation\n const [deleteConfirmKey, setDeleteConfirmKey] = useState<VirtualKey | null>(null);\n const [deleteSubmitting, setDeleteSubmitting] = useState(false);\n\n // Reset spend moved into the shared KeyFormDialog (edit mode)\n\n // Clipboard\n const clipboard = useCopyToClipboard();\n\n // Filter\n const [filterText, setFilterText] = useState('');\n const [sortKey, setSortKey] = useState<SortKey>('created');\n const [sortDirection, setSortDirection] = useState<SortDirection>('desc');\n\n const handleSort = (nextSortKey: SortKey) => {\n if (sortKey === nextSortKey) {\n setSortDirection(current => current === 'asc' ? 'desc' : 'asc');\n } else {\n setSortKey(nextSortKey);\n setSortDirection('asc');\n }\n };\n\n const filteredKeys = useMemo(() => {\n let result = keys;\n // Apply status filter (expired/expiring)\n result = filterKeysByStatus(result, filter);\n // Apply text filter\n if (filterText.trim()) {\n const q = filterText.toLowerCase();\n result = result.filter(k =>\n (k.key_alias ?? '').toLowerCase().includes(q) ||\n k.models?.some(m => m.toLowerCase().includes(q)),\n );\n }\n return [...result].sort((a, b) => {\n const comparison = compareKeys(a, b, sortKey);\n return sortDirection === 'asc' ? comparison : -comparison;\n });\n }, [keys, filterText, sortKey, sortDirection, filter]);\n\n const handleOpenEdit = (k: VirtualKey) => {\n onEditKey(k);\n };\n\n const performUnblock = async (key: VirtualKey) => {\n const keyId = key.token ?? key.key;\n setBlockSubmitting(true);\n try {\n await onUnblockKey(keyId);\n } finally {\n setBlockSubmitting(false);\n }\n };\n\n const performBlock = async (key: VirtualKey) => {\n if (!blockConfirmKey) return;\n const keyId = key.token ?? key.key;\n setBlockSubmitting(true);\n try {\n await onBlockKey(keyId);\n } finally {\n setBlockSubmitting(false);\n setBlockConfirmKey(null);\n }\n };\n\n const handleToggleBlock = (key: VirtualKey) => {\n if (key.blocked) {\n // Unblock is safe (one-click) \u2014 no confirmation\n performUnblock(key);\n } else {\n // Block requires confirmation\n setBlockConfirmKey(key);\n }\n };\n\n const handleConfirmDelete = async () => {\n if (!deleteConfirmKey) return;\n setDeleteSubmitting(true);\n try {\n const keyId = deleteConfirmKey.token ?? deleteConfirmKey.key;\n await onDeleteKey(keyId);\n } finally {\n setDeleteSubmitting(false);\n setDeleteConfirmKey(null);\n }\n };\n\n\n // Prune expired keys\n const [pruneConfirmCount, setPruneConfirmCount] = useState<number | null>(null);\n const [pruneSubmitting, setPruneSubmitting] = useState(false);\n\n const expiredKeys = useMemo(() => {\n return keys.filter(k => expiryStatus(k.expires_at) === 'expired');\n }, [keys]);\n\n const handlePruneExpired = async () => {\n if (pruneConfirmCount === null || pruneConfirmCount === 0) return;\n setPruneSubmitting(true);\n try {\n await onPruneExpiredKeys();\n } catch (error) {\n // eslint-disable-next-line no-console -- TODO: surface via a snackbar/alert instead of console-only\n console.error('Failed to prune expired keys:', error);\n } finally {\n setPruneSubmitting(false);\n setPruneConfirmCount(null);\n }\n };\n\n const renderTableBody = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={8} sx={{ py: 2 }}>\n <Skeleton variant=\"rounded\" height={140} />\n </TableCell>\n </TableRow>\n );\n }\n if (filteredKeys.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={8}>\n {filterText ? (\n <EmptyState\n message=\"No keys match that filter\"\n hint=\"Try a different alias or model name.\"\n />\n ) : (\n <EmptyState\n message=\"No keys yet\"\n hint=\"Generate your first key to start calling models.\"\n action={\n <GenerateKeyButton\n size=\"small\"\n label=\"Generate Your First Key\"\n onClick={onGenerateKeyClick}\n />\n }\n />\n )}\n </TableCell>\n </TableRow>\n );\n }\n return filteredKeys.map((key) => {\n const keyId = key.token ?? key.key;\n const keyModels = key.models ?? [];\n const blockState = blockButtonState(\n key.blocked,\n { allowed: canManageKeys, denied: manageDenied },\n { allowed: canUnblockKeys, denied: unblockDenied },\n );\n return (\n <TableRow\n key={keyId}\n sx={\n key.blocked\n ? theme => ({\n // A left rule reads as \"suspended\" without greying the row into\n // illegibility the way a full background tint does.\n boxShadow: `inset 3px 0 0 0 ${theme.palette.error.main}`,\n '& td': { color: theme.palette.text.secondary },\n })\n : undefined\n }\n >\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={1} flexWrap=\"wrap\">\n <Typography variant=\"body2\">\n {key.key_alias || '\u2014'}\n </Typography>\n {key.blocked && <StatusPill label=\"Blocked\" tone=\"danger\" />}\n </Box>\n </TableCell>\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={0.5}>\n <Typography\n variant=\"body2\"\n component=\"code\"\n color=\"text.secondary\"\n title={keyId}\n sx={theme => ({\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.08 : 0.05),\n px: 0.75,\n py: 0.375,\n borderRadius: '5px',\n })}\n >\n {shortKeyId(keyId)}\n </Typography>\n <Tooltip title={clipboard.copied ? 'Copied' : 'Copy Key ID'} placement=\"top\">\n <IconButton\n size=\"small\"\n onClick={() => clipboard.copy(keyId)}\n aria-label=\"Copy key ID\"\n sx={quietIconButtonSx('accent')}\n >\n {clipboard.copied ? <Check sx={{ fontSize: 15 }} /> : <ContentCopy sx={{ fontSize: 15 }} />}\n </IconButton>\n </Tooltip>\n </Box>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\">{formatDate(key.created_at)}</Typography>\n </TableCell>\n <TableCell>\n <ExpiryCell expiresAt={key.expires_at} />\n </TableCell>\n <TableCell>\n <BudgetCell spend={key.spend ?? 0} maxBudget={key.max_budget} />\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtLimits(key.tpm_limit, key.rpm_limit)}\n </Typography>\n </TableCell>\n <TableCell>\n {keyModels.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">All models</Typography>\n ) : (\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {keyModels.slice(0, 2).map((model) => (\n <TagChip key={model} label={model} title={model} />\n ))}\n {keyModels.length > 2 && (\n <TagChip\n label={`+${keyModels.length - 2}`}\n mono={false}\n title={keyModels.slice(2).join(', ')}\n />\n )}\n </Box>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <Box display=\"flex\" justifyContent=\"flex-end\" gap={0.25}>\n <Tooltip describeChild title={manageDenied ? 'No permission to edit keys' : 'Edit key'} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => handleOpenEdit(key)}\n disabled={!canManageKeys}\n aria-label={manageDenied ? 'No permission to edit keys' : 'Edit key'}\n sx={quietIconButtonSx('accent')}\n >\n <Edit fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n <Tooltip describeChild title={blockState.label} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => handleToggleBlock(key)}\n disabled={blockSubmitting || blockState.disabled}\n aria-label={blockState.label}\n sx={quietIconButtonSx('warning')}\n >\n {keyBlockIcon(blockSubmitting, key.blocked)}\n </IconButton>\n </span>\n </Tooltip>\n <Tooltip describeChild title={revokeDenied ? 'No permission to revoke keys' : 'Revoke key'} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => setDeleteConfirmKey(key)}\n disabled={!canRevokeKeys}\n aria-label={revokeDenied ? 'No permission to revoke keys' : 'Revoke key'}\n sx={quietIconButtonSx('danger')}\n >\n <Delete fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n </Box>\n </TableCell>\n </TableRow>\n );\n });\n };\n\n return (\n <>\n <SectionCard\n title=\"Virtual Keys\"\n subtitle={\n loading\n ? 'Loading\u2026'\n : `${filteredKeys.length}${filterText ? ` of ${keys.length}` : ''} key${filteredKeys.length === 1 ? '' : 's'}`\n }\n flush\n actions={\n <>\n <TextField\n size=\"small\"\n label=\"Search alias or model\"\n placeholder=\"Search alias or model\u2026\"\n value={filterText}\n onChange={e => setFilterText(e.target.value)}\n sx={{ minWidth: 240 }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <Search fontSize=\"small\" color=\"disabled\" />\n </InputAdornment>\n ),\n }}\n />\n {expiredKeys.length > 0 && (\n <Button\n variant=\"outlined\"\n color=\"inherit\"\n startIcon={<Autorenew />}\n onClick={() => setPruneConfirmCount(expiredKeys.length)}\n sx={theme => ({\n color: theme.palette.text.secondary,\n borderColor: theme.palette.divider,\n '&:hover': {\n color: theme.palette.error.main,\n borderColor: alpha(theme.palette.error.main, 0.5),\n bgcolor: alpha(theme.palette.error.main, 0.06),\n },\n })}\n >\n Prune expired ({expiredKeys.length})\n </Button>\n )}\n </>\n }\n >\n {filter && (\n <Box sx={{ px: 2, py: 1, borderBottom: theme => `1px solid ${theme.palette.divider}` }}>\n <Chip\n size=\"small\"\n label={`Showing: ${filter === 'expired' ? 'expired' : 'expiring'} keys`}\n onDelete={onClearFilter}\n deleteIcon={<Close />}\n variant=\"outlined\"\n />\n </Box>\n )}\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sortDirection={sortKey === 'alias' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'alias'} direction={sortKey === 'alias' ? sortDirection : 'asc'} onClick={() => handleSort('alias')}>Alias</TableSortLabel>\n </TableCell>\n <TableCell>Key ID</TableCell>\n <TableCell sortDirection={sortKey === 'created' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'created'} direction={sortKey === 'created' ? sortDirection : 'asc'} onClick={() => handleSort('created')}>Created</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'expires' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'expires'} direction={sortKey === 'expires' ? sortDirection : 'asc'} onClick={() => handleSort('expires')}>Expires</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'budget' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'budget'} direction={sortKey === 'budget' ? sortDirection : 'asc'} onClick={() => handleSort('budget')}>Budget</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'limits' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'limits'} direction={sortKey === 'limits' ? sortDirection : 'asc'} onClick={() => handleSort('limits')}>TPM / RPM (per min)</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'models' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'models'} direction={sortKey === 'models' ? sortDirection : 'asc'} onClick={() => handleSort('models')}>Models</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\">Actions</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderTableBody()}\n </TableBody>\n </Table>\n </TableContainer>\n </SectionCard>\n\n {/* Block confirmation dialog */}\n <Dialog\n open={!!blockConfirmKey}\n onClose={() => !blockSubmitting && setBlockConfirmKey(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>Block key?</DialogTitle>\n <DialogContent>\n <Typography>\n Block <strong>{keyDisplayLabel(blockConfirmKey ?? ({} as VirtualKey))}</strong>? Integrations using it will fail immediately.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => setBlockConfirmKey(null)}\n disabled={blockSubmitting}\n >\n Cancel\n </Button>\n <Button\n onClick={() => blockConfirmKey && performBlock(blockConfirmKey)}\n variant=\"contained\"\n color=\"warning\"\n disabled={blockSubmitting}\n >\n {blockSubmitting ? <CircularProgress size={20} /> : 'Block'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* Delete confirmation dialog */}\n <Dialog\n open={!!deleteConfirmKey}\n onClose={() => !deleteSubmitting && setDeleteConfirmKey(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n Revoke <strong>{deleteConfirmKey ? keyDisplayLabel(deleteConfirmKey) : ''}</strong>{deleteConfirmKey && keyLast4(deleteConfirmKey) ? ` (sk-\u2026${keyLast4(deleteConfirmKey)})` : ''}?\n </DialogTitle>\n <DialogContent>\n <Typography>\n This will permanently revoke the key. Any integrations using it will stop working immediately.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDeleteConfirmKey(null)} disabled={deleteSubmitting}>\n Cancel\n </Button>\n <Button\n onClick={handleConfirmDelete}\n variant=\"contained\"\n color=\"error\"\n disabled={deleteSubmitting}\n >\n {deleteSubmitting ? <CircularProgress size={20} /> : 'Revoke'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* Prune expired keys confirmation dialog */}\n <Dialog\n open={pruneConfirmCount !== null}\n onClose={() => !pruneSubmitting && setPruneConfirmCount(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>Prune Expired Keys?</DialogTitle>\n <DialogContent>\n <Typography>\n {pruneConfirmCount !== null && pruneCopy(pruneConfirmCount)}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setPruneConfirmCount(null)} disabled={pruneSubmitting}>\n Cancel\n </Button>\n <Button\n onClick={handlePruneExpired}\n variant=\"contained\"\n color=\"error\"\n disabled={pruneSubmitting}\n >\n {pruneSubmitting ? <CircularProgress size={20} /> : 'Prune'}\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n};\n", "import { GenerateKeyRequest, UpdateKeyRequest } from './types';\n\nexport interface ValidationErrors {\n alias?: string;\n team?: string;\n budget?: string;\n duration?: string;\n models?: string;\n}\n\nexport interface ValidationOptions {\n teamRequired?: boolean;\n /** True when the user has ticked the 'Unlimited budget' checkbox. */\n unlimitedBudget?: boolean;\n isCreate?: boolean;\n}\n\n/**\n * Validates a key form (create or edit mode).\n * Returns a map of field names to error messages.\n * A field with no error is absent from the map.\n */\nexport function validateKeyForm(\n formData: GenerateKeyRequest | UpdateKeyRequest,\n options: ValidationOptions = {},\n): ValidationErrors {\n const {\n teamRequired = true,\n unlimitedBudget = false,\n isCreate = true,\n } = options;\n\n const errors: ValidationErrors = {};\n\n // Alias validation\n const alias = (isCreate ? (formData as GenerateKeyRequest).alias : (formData as UpdateKeyRequest).key_alias) ?? '';\n if (!alias.trim()) {\n errors.alias = 'Alias is required';\n }\n // A duplicate alias is only a warning in the UI (see aliasDuplicate), never a blocking error.\n\n // Team validation (create mode only)\n if (isCreate) {\n const teamId = (formData as GenerateKeyRequest).team_id;\n if (teamRequired && !teamId) {\n errors.team = 'Team is required';\n }\n }\n\n // Budget validation\n const maxBudget = formData.max_budget;\n if (!unlimitedBudget && (maxBudget === undefined || maxBudget === null || maxBudget <= 0)) {\n errors.budget = 'Enter a positive budget or tick \"Unlimited\"';\n }\n\n return errors;\n}\n\n/**\n * Returns the first field with an error, in a consistent order.\n * Used to focus the first invalid field on submit.\n */\nexport function firstInvalidField(\n errors: ValidationErrors,\n isCreate: boolean = true,\n): string | null {\n const fieldOrder = isCreate\n ? ['team', 'alias', 'budget', 'duration', 'models']\n : ['alias', 'budget', 'models'];\n\n for (const field of fieldOrder) {\n if (errors[field as keyof ValidationErrors]) {\n return field;\n }\n }\n return null;\n}\n\n/**\n * Compute the expiry date from a duration string and the current date.\n * Supported: 'd' (days), 'w' (weeks), 'm' (months), 'y' (years).\n * Example: expiryPreview('30d', new Date('2026-09-29')) => 'Expires Oct 29, 2026'\n */\nexport function expiryPreview(duration: string | undefined, now: Date = new Date()): string | null {\n if (!duration) return null;\n\n const match = duration.match(/^(\\d+)([dwmy])$/);\n if (!match) return null;\n\n const [, countStr, unit] = match;\n const count = parseInt(countStr, 10);\n if (isNaN(count)) return null;\n\n const expiry = new Date(now);\n\n switch (unit) {\n case 'd':\n expiry.setDate(expiry.getDate() + count);\n break;\n case 'w':\n expiry.setDate(expiry.getDate() + count * 7);\n break;\n case 'm':\n expiry.setMonth(expiry.getMonth() + count);\n break;\n case 'y':\n expiry.setFullYear(expiry.getFullYear() + count);\n break;\n default:\n return null;\n }\n\n // Format as \"Expires Oct 29, 2026\"\n const month = expiry.toLocaleString('en-US', { month: 'short' });\n const day = expiry.getDate();\n const year = expiry.getFullYear();\n return `Expires ${month} ${day}, ${year}`;\n}\n\n/**\n * Find the priciest input cost among selected models.\n * Returns null if no models have pricing data.\n */\nexport function priciestInputPrice(\n selectedModels: Array<{ input_cost_per_token?: number }>,\n): number | null {\n const inputCosts = selectedModels\n .map(m => m.input_cost_per_token)\n .filter((c): c is number => typeof c === 'number' && c > 0);\n if (inputCosts.length === 0) return null;\n return Math.max(...inputCosts);\n}\n", "import { VirtualKey, ModelInfo, GenerateKeyRequest, UpdateKeyRequest } from '../types';\nimport { fmtInt } from '../format';\nimport { isModelAllowed } from '@acarmisc/backstage-plugin-litellm-common';\n\nexport const generateDefaultAlias = (username?: string): string => {\n const base = (username || 'user')\n .split('@')[0]\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'user';\n const hash = Math.random().toString(36).slice(2, 8);\n return `${base}-${hash}`;\n};\n\nexport const createForm = (username?: string): GenerateKeyRequest => ({\n alias: generateDefaultAlias(username),\n models: [],\n duration: '30d',\n max_budget: 100,\n tpm_limit: undefined,\n rpm_limit: undefined,\n team_id: undefined,\n key_type: 'llm_api',\n});\n\nexport const editForm = (k: VirtualKey): UpdateKeyRequest => ({\n key_alias: k.key_alias ?? '',\n models: k.models ?? [],\n max_budget: k.max_budget,\n tpm_limit: k.tpm_limit,\n rpm_limit: k.rpm_limit,\n});\n\n// LiteLLM sentinel: a team's `models` list is `[\"all-proxy-models\"]` when the\n// team isn't restricted to specific models. A team's `models` entries can\n// also be access-group names (see litellm model_info.access_groups) rather\n// than literal model_name values. Treating either case as a literal\n// model_name allowlist matches nothing, which previously made the whole\n// \"Models\" field disappear for such teams.\nexport function isModelAllowedByTeam(model: ModelInfo, teamModels?: string[]): boolean {\n return isModelAllowed(model, teamModels);\n}\n\nexport function aliasHelperText(aliasError: boolean, aliasDuplicate: boolean): string | undefined {\n if (aliasError) return 'Alias is required';\n if (aliasDuplicate) return 'This alias is already used by one of your keys \u2014 LiteLLM requires aliases to be unique across all keys';\n return undefined;\n}\n\nexport function teamHelperText(teamError: boolean, teamRequired: boolean): string {\n if (teamError) return 'Team is required';\n if (teamRequired) return 'Bind this key to a team for scoped access';\n return 'Optional: bind this key to a specific team for scoped access';\n}\n\nexport function budgetHelperText(budgetInvalid: boolean, budgetEstimate: number | null, unlimited: boolean): string | undefined {\n if (budgetInvalid && !unlimited) return 'Enter a positive budget or tick \"Unlimited\"';\n if (budgetEstimate !== null) return `\u2248 ${fmtInt(budgetEstimate)} tokens at the priciest selected model`;\n return 'Lifetime cap for this key. It never resets';\n}\n\n\nconst sameStrings = (a: string[] = [], b: string[] = []) =>\n a.length === b.length && a.every((v, i) => v === b[i]);\n\n/**\n * The fields of an edit that actually changed. Sending only these means an\n * untouched field (say a legacy budget above the current ceiling) can't make an\n * unrelated edit fail server-side validation. Returns `{}` when nothing changed.\n */\nexport function changedEditFields(\n original: UpdateKeyRequest,\n current: UpdateKeyRequest,\n unlimitedBudget: boolean,\n): UpdateKeyRequest {\n const out: UpdateKeyRequest = {};\n if ((current.key_alias ?? '') !== (original.key_alias ?? '')) {\n out.key_alias = current.key_alias;\n }\n if (!sameStrings(current.models, original.models)) {\n out.models = current.models ?? [];\n }\n const nextBudget = unlimitedBudget ? null : current.max_budget;\n if ((nextBudget ?? null) !== (original.max_budget ?? null)) {\n out.max_budget = nextBudget;\n }\n if (current.tpm_limit !== original.tpm_limit) out.tpm_limit = current.tpm_limit;\n if (current.rpm_limit !== original.rpm_limit) out.rpm_limit = current.rpm_limit;\n return out;\n}\n", "import { FC, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport IconButton from '@mui/material/IconButton';\nimport Tabs from '@mui/material/Tabs';\nimport Tab from '@mui/material/Tab';\nimport Tooltip from '@mui/material/Tooltip';\nimport { ContentCopy, Check } from '@mui/icons-material';\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\nexport interface Snippets {\n curl: string;\n openai: string;\n opencode: string;\n pi: string;\n claudeCode: string;\n publicEndpoint: string;\n}\n\nexport function buildSnippets(baseUrl: string | null, key: string, model: string): Snippets {\n if (!baseUrl) {\n throw new Error('baseUrl not configured');\n }\n const base = trimSlash(baseUrl);\n const apiBase = `${base}/v1`;\n return {\n publicEndpoint: apiBase,\n curl: `curl ${apiBase}/chat/completions \\\\\n -H \"Authorization: Bearer ${key}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\n \"model\": \"${model}\",\n \"messages\": [{ \"role\": \"user\", \"content\": \"Hello!\" }]\n }'`,\n openai: `from openai import OpenAI\n\nclient = OpenAI(\n api_key=\"${key}\",\n base_url=\"${apiBase}\",\n)\n\nresponse = client.chat.completions.create(\n model=\"${model}\",\n messages=[{ \"role\": \"user\", \"content\": \"Hello!\" }],\n)\nprint(response.choices[0].message.content)`,\n opencode: `{\n \"$schema\": \"https://opencode.ai/config.json\",\n \"provider\": {\n \"litellm\": {\n \"npm\": \"@ai-sdk/openai-compatible\",\n \"name\": \"LiteLLM\",\n \"options\": {\n \"baseURL\": \"${apiBase}\",\n \"apiKey\": \"${key}\"\n },\n \"models\": {\n \"${model}\": {}\n }\n }\n }\n}`,\n pi: `{\n \"litellm\": {\n \"baseUrl\": \"${apiBase}\",\n \"apiKey\": \"${key}\",\n \"api\": \"openai-completions\",\n \"models\": [\n { \"id\": \"${model}\", \"name\": \"${model}\" }\n ]\n }\n}`,\n claudeCode: `# Option 1 \u2014 Static key (store in environment or .env)\nexport ANTHROPIC_AUTH_TOKEN=\"${key}\"\nexport ANTHROPIC_BASE_URL=\"${base}\"\nclaude --model ${model}\n\n# Option 2 \u2014 Read from OS keychain (macOS or Linux)\n# 1. Store this key in your system keychain:\n# macOS:\nsecurity add-generic-password -s litellm-api-key -a \"$USER\" -w '<paste key>'\n# Linux (secret-tool):\nsecret-tool store --label=\"LiteLLM\" service litellm-api-key\n\n# 2. Add to ~/.claude/settings.json (apiKeyHelper is a shell command whose\n# stdout is the key):\n# macOS:\n# { \"apiKeyHelper\": \"security find-generic-password -s litellm-api-key -w\" }\n# Linux:\n# { \"apiKeyHelper\": \"secret-tool lookup service litellm-api-key\" }\n\n# 3. Optional: refresh interval in ms (default 1h):\nexport CLAUDE_CODE_API_KEY_HELPER_TTL_MS=3600000`,\n };\n}\n\ninterface SnippetTabsProps {\n snippets: Snippets;\n model: string;\n copyState: { copy: (text: string) => Promise<boolean>; copied: boolean };\n}\n\ntype SnippetTab = 'curl' | 'openai' | 'opencode' | 'pi' | 'claude-code';\n\nconst SNIPPET_FILE_HINTS: Partial<Record<SnippetTab, string>> = {\n opencode: 'Add to ~/.config/opencode/opencode.json',\n pi: 'Add to ~/.pi/agent/models.json',\n 'claude-code': 'Store the key in your OS keychain and point apiKeyHelper at it in ~/.claude/settings.json',\n};\n\nexport const SnippetTabs: FC<SnippetTabsProps> = ({ snippets, model, copyState }) => {\n const [tab, setTab] = useState<SnippetTab>('curl');\n const snippetKey = tab === 'claude-code' ? 'claudeCode' : tab;\n const code = snippets[snippetKey as keyof Snippets];\n const fileHint = SNIPPET_FILE_HINTS[tab];\n return (\n <Box>\n <Tabs value={tab} onChange={(_, v) => setTab(v as SnippetTab)} sx={{ mb: 1 }} variant=\"scrollable\">\n <Tab label=\"curl\" value=\"curl\" />\n <Tab label=\"OpenAI SDK\" value=\"openai\" />\n <Tab label=\"opencode\" value=\"opencode\" />\n <Tab label=\"pi\" value=\"pi\" />\n <Tab label=\"Claude Code\" value=\"claude-code\" />\n </Tabs>\n {fileHint && (\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mb={0.5}>\n {fileHint}\n </Typography>\n )}\n <Box\n position=\"relative\"\n p={1.5}\n sx={{ backgroundColor: 'action.hover', border: '1px solid', borderColor: 'divider', borderRadius: 1 }}\n >\n <Tooltip title={copyState.copied ? 'Copied' : 'Copy snippet'} placement=\"top\">\n <IconButton\n size=\"small\"\n onClick={() => copyState.copy(code)}\n aria-label=\"Copy snippet\"\n sx={{ position: 'absolute', top: 4, right: 4 }}\n >\n {copyState.copied ? <Check fontSize=\"small\" /> : <ContentCopy fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n <Typography\n component=\"pre\"\n sx={{\n fontFamily: 'monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n mb: 0,\n pr: 4,\n }}\n >\n {code}\n </Typography>\n {model && (\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mt={1}>\n Using model \u201C{model}\u201D \u2014 swap it for any model you have access to.\n </Typography>\n )}\n </Box>\n </Box>\n );\n};\n\n", "import { FC, useEffect, useMemo, useRef, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Alert from '@mui/material/Alert';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport Tooltip from '@mui/material/Tooltip';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Chip from '@mui/material/Chip';\nimport { ContentCopy, Code, ExpandMore, Check } from '@mui/icons-material';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n VirtualKey,\n ModelInfo,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n UpdateKeyRequest,\n LiteLlmConfig,\n} from '../types';\nimport { DEFAULT_KEY_DURATIONS, litellmKeyResetSpendPermission, formatDurationLabel } from '@acarmisc/backstage-plugin-litellm-common';\nimport { estimateTokensFromBudget } from '../format';\nimport { useCopyToClipboard } from '../hooks';\nimport { validateKeyForm, firstInvalidField, expiryPreview, priciestInputPrice } from '../keyFormValidation';\n\n/**\n * Single form dialog for both key creation (`mode=\"create\"`) and key editing\n * (`mode=\"edit\"`).\n *\n * Create mode: alias (pre-filled), team, models, duration, budget (+unlimited\n * when gated on), TPM/RPM in the Advanced accordion, and the post-generation\n * screen with copyable key + starter snippets.\n *\n * Edit mode: the same shared fields but no duration (expiry is immutable after\n * creation) and no team switch (LiteLLM /key/update semantics); adds a masked\n * key header and the Danger Zone (reset spend). Budget validation, the\n * unlimited toggle and the team-scoped model filtering behave exactly as they\n * do at creation time.\n */\nimport {\n createForm,\n editForm,\n changedEditFields,\n isModelAllowedByTeam,\n aliasHelperText,\n teamHelperText,\n budgetHelperText,\n} from './keyFormHelpers';\nimport { buildSnippets, SnippetTabs, type Snippets } from './KeySnippets';\n\nexport type KeyFormDialogMode = 'create' | 'edit';\n\nexport interface KeyFormDialogProps {\n open: boolean;\n onClose: () => void;\n /** `create` generates a new key; `edit` updates an existing one. */\n mode: KeyFormDialogMode;\n /** Key being edited (edit mode only). */\n keyToEdit?: VirtualKey | null;\n keys: VirtualKey[];\n models: ModelInfo[];\n modelsError?: Error;\n onRetryModels?: () => void;\n teams: TeamInfo[];\n /** Current user's LiteLLM user id, used to pre-fill a default key alias. */\n username?: string;\n /** Controls for the key form; see litellm.keyGeneration in app-config.yaml. */\n keyGenerationSettings?: { allowUnlimitedBudget: boolean; teamRequired: boolean };\n onCreateKey: (request: GenerateKeyRequest) => Promise<GenerateKeyResponse>;\n onUpdateKey: (keyId: string, request: UpdateKeyRequest) => Promise<void>;\n onResetKeySpend?: (keyId: string) => Promise<void>;\n onGetConfig: () => Promise<LiteLlmConfig>;\n}\n\nexport const KeyFormDialog: FC<KeyFormDialogProps> = ({\n open,\n onClose,\n mode,\n keyToEdit = null,\n keys,\n models,\n modelsError,\n onRetryModels,\n teams,\n username,\n keyGenerationSettings,\n onCreateKey,\n onUpdateKey,\n onResetKeySpend,\n onGetConfig,\n}) => {\n const isCreate = mode === 'create';\n const [generateForm, setGenerateForm] = useState<GenerateKeyRequest>(createForm(username));\n const [editFormState, setEditFormState] = useState<UpdateKeyRequest>({});\n const [unlimitedBudget, setUnlimitedBudget] = useState(false);\n const [submitting, setSubmitting] = useState(false);\n const [newKeyValue, setNewKeyValue] = useState<string | null>(null);\n const [newKeySnippets, setNewKeySnippets] = useState<Snippets | null>(null);\n const [newKeyModel, setNewKeyModel] = useState<string>('');\n const [generateError, setGenerateError] = useState<string | null>(null);\n const [editError, setEditError] = useState<string | null>(null);\n const [resetSpendConfirm, setResetSpendConfirm] = useState(false);\n const [resetSpendSubmitting, setResetSpendSubmitting] = useState(false);\n const [config, setConfig] = useState<LiteLlmConfig | null>(null);\n const [secretCopied, setSecretCopied] = useState(false);\n const [closeWithoutCopyConfirm, setCloseWithoutCopyConfirm] = useState(false);\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const [submitAttempted, setSubmitAttempted] = useState(false);\n\n // Refs for focusing first invalid field\n const teamInputRef = useRef<HTMLInputElement>(null);\n const aliasInputRef = useRef<HTMLInputElement>(null);\n const budgetInputRef = useRef<HTMLInputElement>(null);\n\n // Clipboard hook for all copy operations\n const clipboardSecret = useCopyToClipboard();\n const clipboardSnippet = useCopyToClipboard();\n const clipboardEndpoint = useCopyToClipboard();\n\n // Permission check for reset spend\n const resetSpendPermission = usePermission({ permission: litellmKeyResetSpendPermission });\n const canResetSpend = !resetSpendPermission.loading && resetSpendPermission.allowed;\n\n // Re-arm the form each time the dialog opens so a stale result from a\n // previous run (or another user's session) is never shown.\n useEffect(() => {\n if (open) {\n if (isCreate) {\n setGenerateForm(createForm(username));\n } else if (keyToEdit) {\n setEditFormState(editForm(keyToEdit));\n setUnlimitedBudget(\n keyGenerationSettings?.allowUnlimitedBudget === true &&\n (keyToEdit.max_budget === null || keyToEdit.max_budget === undefined),\n );\n } else {\n setEditFormState({});\n setUnlimitedBudget(false);\n }\n setNewKeyValue(null);\n setNewKeySnippets(null);\n setNewKeyModel('');\n setGenerateError(null);\n setEditError(null);\n setResetSpendConfirm(false);\n setSecretCopied(false);\n setCloseWithoutCopyConfirm(false);\n setTouched({});\n setSubmitAttempted(false);\n }\n }, [open, isCreate, keyToEdit, username, keyGenerationSettings?.allowUnlimitedBudget]);\n\n // Fetch config to check key action capabilities. Kept separate from the\n // reset effect above and reading `onGetConfig` through a ref: parents often\n // pass an inline callback, and depending on its identity would re-run the\n // reset on every parent render, wiping a freshly generated key (or the\n // user's in-progress input).\n const onGetConfigRef = useRef(onGetConfig);\n onGetConfigRef.current = onGetConfig;\n useEffect(() => {\n if (!open) return undefined;\n let cancelled = false;\n onGetConfigRef.current()\n .then(c => { if (!cancelled) setConfig(c); })\n .catch(() => { if (!cancelled) setConfig(null); });\n return () => { cancelled = true; };\n }, [open]);\n\n const allowUnlimitedBudget = keyGenerationSettings?.allowUnlimitedBudget ?? false;\n const teamRequired = keyGenerationSettings?.teamRequired ?? true;\n\n const formData = isCreate ? generateForm : editFormState;\n const setFormData = (patch: Partial<GenerateKeyRequest> & Partial<UpdateKeyRequest>) => {\n if (isCreate) {\n setGenerateForm(prev => ({ ...prev, ...patch }));\n } else {\n setEditFormState(prev => ({ ...prev, ...patch }));\n }\n };\n\n // Create mode names the field `alias`; edit mode `key_alias` (matching the\n // LiteLLM payload shapes). One accessor keeps the shared JSX mode-agnostic.\n const currentAlias = (isCreate ? generateForm.alias : editFormState.key_alias) ?? '';\n const setAliasField = (value: string) => {\n if (isCreate) setFormData({ alias: value });\n else setFormData({ key_alias: value });\n };\n\n const selectedTeam = teams.find(t => t.team_id === (isCreate ? generateForm.team_id : undefined)) ?? null;\n\n // In edit mode, filter models by the key's team_id (fixed after creation).\n // In create mode, filter by the currently selected team.\n const teamIdForModels = isCreate ? generateForm.team_id : keyToEdit?.team_id;\n const teamForModels = teams.find(t => t.team_id === teamIdForModels) ?? null;\n\n // Once a team is selected, only offer models that team is actually allowed\n // to use \u2014 `models` here is already scoped to what the user can access.\n // Applies on edit too, so a key can no longer drift out of its team's\n // allowlist via /key/update.\n const availableModels = useMemo(() => {\n return models.filter(m => isModelAllowedByTeam(m, teamForModels?.models));\n }, [models, teamForModels]);\n\n const selectedModels = availableModels.filter(m => (formData.models || []).includes(m.model_name));\n\n // \u2500\u2500 Validation using the validation module \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const validationErrors = validateKeyForm(formData, {\n teamRequired,\n unlimitedBudget,\n isCreate,\n });\n\n // Show errors only if the field was touched or submit was attempted\n const showError = (field: string) => touched[field] || submitAttempted;\n const aliasError = showError('alias') && !!validationErrors.alias;\n const teamError = showError('team') && !!validationErrors.team;\n const budgetInvalid = showError('budget') && !!validationErrors.budget;\n\n // Issue #35: warn (don't block) when the alias already matches one of the\n // user's loaded keys \u2014 LiteLLM enforces globally-unique aliases.\n const aliasDuplicate = !!currentAlias && keys.some(k => k.key_alias === currentAlias && k !== keyToEdit);\n\n // \u2500\u2500 Budget estimate at the priciest selected model's input rate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const budgetEstimate = useMemo(() => {\n if (unlimitedBudget || budgetInvalid) return null;\n const pricePerToken = priciestInputPrice(selectedModels);\n if (pricePerToken === null) return null;\n return estimateTokensFromBudget(formData.max_budget ?? 0, pricePerToken);\n }, [formData.max_budget, selectedModels, unlimitedBudget, budgetInvalid]);\n\n const handleGenerate = async () => {\n // Validate before submitting\n const errors = validateKeyForm(generateForm, {\n teamRequired,\n unlimitedBudget,\n isCreate: true,\n });\n\n if (Object.keys(errors).length > 0) {\n setSubmitAttempted(true);\n // Focus first invalid field\n const firstInvalid = firstInvalidField(errors, true);\n if (firstInvalid === 'team' && teamInputRef.current) {\n teamInputRef.current.focus();\n } else if (firstInvalid === 'alias' && aliasInputRef.current) {\n aliasInputRef.current.focus();\n } else if (firstInvalid === 'budget' && budgetInputRef.current) {\n budgetInputRef.current.focus();\n }\n return;\n }\n\n setSubmitting(true);\n setGenerateError(null);\n try {\n const request: GenerateKeyRequest = {\n ...(generateForm as GenerateKeyRequest),\n max_budget: unlimitedBudget ? null : generateForm.max_budget,\n };\n const response = await onCreateKey(request);\n // When the key allows all models (none explicitly picked), fall back to\n // the first model actually allowed for the chosen team so snippets show\n // a working example rather than an empty model name.\n const model = generateForm.models?.[0] ?? availableModels[0]?.model_name ?? '';\n setNewKeyValue(response.key);\n setNewKeyModel(model);\n setNewKeySnippets(null);\n try {\n const fetchedConfig = await onGetConfig();\n if (fetchedConfig.baseUrl) {\n setNewKeySnippets(buildSnippets(fetchedConfig.baseUrl, response.key, model));\n }\n } catch {\n // Snippets are a nice-to-have; the raw key is still shown.\n }\n setGenerateForm(createForm(username));\n setUnlimitedBudget(false);\n } catch (error: any) {\n setGenerateError(error?.message ?? 'Failed to generate key');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleUpdate = async () => {\n if (!keyToEdit) return;\n\n // Validate before submitting\n const errors = validateKeyForm(editFormState, {\n teamRequired,\n unlimitedBudget,\n isCreate: false,\n });\n\n if (Object.keys(errors).length > 0) {\n setSubmitAttempted(true);\n // Focus first invalid field\n const firstInvalid = firstInvalidField(errors, false);\n if (firstInvalid === 'alias' && aliasInputRef.current) {\n aliasInputRef.current.focus();\n } else if (firstInvalid === 'budget' && budgetInputRef.current) {\n budgetInputRef.current.focus();\n }\n return;\n }\n\n setSubmitting(true);\n setEditError(null);\n try {\n const request = changedEditFields(editForm(keyToEdit), editFormState, unlimitedBudget);\n if (Object.keys(request).length > 0) {\n await onUpdateKey(keyToEdit.token ?? keyToEdit.key, request);\n }\n onClose();\n } catch (error: any) {\n setEditError(error?.message ?? 'Failed to update key');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleResetSpend = async () => {\n if (!keyToEdit || !onResetKeySpend) return;\n setResetSpendSubmitting(true);\n try {\n await onResetKeySpend(keyToEdit.token ?? keyToEdit.key);\n setResetSpendConfirm(false);\n onClose();\n } catch (e: any) {\n // Keep the dialog open and say what went wrong instead of closing as if it worked.\n setResetSpendConfirm(false);\n setEditError(e?.message ?? 'Failed to reset spend');\n } finally {\n setResetSpendSubmitting(false);\n }\n };\n\n const handleCloseWithoutConfirm = () => {\n onClose();\n setGenerateError(null);\n setEditError(null);\n setNewKeyValue(null);\n setNewKeySnippets(null);\n setGenerateForm(createForm(username));\n setEditFormState({});\n setUnlimitedBudget(false);\n setResetSpendConfirm(false);\n setSecretCopied(false);\n setCloseWithoutCopyConfirm(false);\n };\n\n // Handle close when showing the secret \u2014 check if copied first\n const handleCloseSecretDialog = () => {\n if (newKeyValue && !secretCopied) {\n // Show confirmation before closing\n setCloseWithoutCopyConfirm(true);\n } else {\n handleCloseWithoutConfirm();\n }\n };\n\n const handleConfirmCloseWithoutCopy = () => {\n setCloseWithoutCopyConfirm(false);\n handleCloseWithoutConfirm();\n };\n\n // Handle Dialog close events (Escape, backdrop click)\n const handleDialogClose = (_event: unknown, reason: string) => {\n // If showing a secret, ignore backdrop and escape\n if (newKeyValue && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n handleCloseSecretDialog();\n };\n\n const modelOption = (m: ModelInfo) => {\n const inCost = fmtCost(m.input_cost_per_token);\n const outCost = fmtCost(m.output_cost_per_token);\n const ctx = formatContextWindow(m.max_input_tokens, m.max_output_tokens);\n return (\n <Box>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mb: 0.5 }}>\n <span>{m.model_name}</span>\n {m.supports_function_calling && <Chip size=\"small\" variant=\"outlined\" label=\"Tools\" />}\n {m.supports_vision && <Chip size=\"small\" variant=\"outlined\" label=\"Vision\" />}\n </Box>\n {ctx && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ ml: 1 }}>\n {ctx}\n </Typography>\n )}\n {(inCost || outCost) && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ ml: 1 }}>\n {inCost} in \u00B7 {outCost} out\n </Typography>\n )}\n </Box>\n );\n };\n\n const renderTeamField = () => {\n if (teams.length > 0) {\n return (\n <Autocomplete\n options={teams}\n getOptionLabel={t => t.team_alias || t.team_id}\n value={selectedTeam}\n onChange={(_e, team) => {\n const restrictedModels = (formData.models || []).filter(name => {\n const model = models.find(m => m.model_name === name);\n return model ? isModelAllowedByTeam(model, team?.models) : false;\n });\n setFormData({ team_id: team?.team_id, models: restrictedModels });\n }}\n disabled={!isCreate}\n onBlur={() => setTouched(prev => ({ ...prev, team: true }))}\n renderInput={params => (\n <TextField\n {...params}\n inputRef={teamInputRef}\n label=\"Team\"\n error={teamError}\n helperText={\n isCreate\n ? teamHelperText(teamError, teamRequired)\n : 'Team binding is fixed after creation \u2014 delete and recreate the key to change it'\n }\n required={isCreate && teamRequired}\n fullWidth\n />\n )}\n />\n );\n }\n if (teamRequired && isCreate) {\n return (\n <Typography variant=\"body2\" color=\"error\">\n Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.\n </Typography>\n );\n }\n return null;\n };\n\n const editKeyId = keyToEdit?.token ?? keyToEdit?.key ?? '';\n\n const renderDangerZone = () => {\n if (isCreate || !onResetKeySpend) return null;\n // Hide the danger zone if allowOwnerResetSpend is false or permission not granted\n if (!config?.keyActions?.allowOwnerResetSpend || !canResetSpend) return null;\n return (\n <Box mt={1} pt={2} borderTop=\"1px solid\" sx={{ borderColor: 'divider' }}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mb={1}>\n Danger Zone\n </Typography>\n {!resetSpendConfirm ? (\n <Button\n size=\"small\"\n color=\"warning\"\n variant=\"outlined\"\n onClick={() => setResetSpendConfirm(true)}\n >\n Reset Spend to $0\n </Button>\n ) : (\n <Box display=\"flex\" alignItems=\"center\" gap={1} flexWrap=\"wrap\">\n <Typography variant=\"body2\" color=\"warning.main\">\n Zero out spend counter?\n </Typography>\n <Button\n size=\"small\"\n color=\"warning\"\n variant=\"contained\"\n disabled={resetSpendSubmitting}\n onClick={handleResetSpend}\n >\n {resetSpendSubmitting ? <CircularProgress size={16} /> : 'Confirm'}\n </Button>\n <Button size=\"small\" onClick={() => setResetSpendConfirm(false)}>\n Cancel\n </Button>\n </Box>\n )}\n </Box>\n );\n };\n\n const maskKey = (key: string): string => {\n if (key.length <= 8) return '***';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n };\n\n let dialogTitle = 'Edit Key';\n if (newKeyValue) dialogTitle = 'Key Generated';\n else if (isCreate) dialogTitle = 'Generate New Key';\n\n const submitLabel = isCreate ? 'Generate' : 'Save';\n return (\n <Dialog\n open={open}\n onClose={handleDialogClose}\n disableEscapeKeyDown={!!newKeyValue}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{dialogTitle}</DialogTitle>\n <DialogContent>\n {newKeyValue ? (\n <Box>\n <Alert severity=\"warning\" sx={{ mb: 2 }}>\n Copy this key now. It will never be shown again.\n </Alert>\n <Box\n display=\"flex\"\n alignItems=\"center\"\n gap={1}\n mt={2}\n p={2}\n sx={{\n backgroundColor: 'action.hover',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n }}\n >\n <Typography\n component=\"code\"\n color=\"text.primary\"\n sx={{ fontFamily: 'monospace', wordBreak: 'break-all', flex: 1 }}\n >\n {newKeyValue}\n </Typography>\n <Tooltip title={clipboardSecret.copied ? 'Copied' : 'Copy API key'} placement=\"top\">\n <IconButton\n aria-label=\"Copy API key\"\n onClick={async () => {\n const success = await clipboardSecret.copy(newKeyValue);\n if (success) {\n setSecretCopied(true);\n }\n }}\n >\n {clipboardSecret.copied ? <Check /> : <ContentCopy />}\n </IconButton>\n </Tooltip>\n </Box>\n\n {newKeyValue && !newKeySnippets && (\n <Box mt={2}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" gutterBottom>\n Public endpoint\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n Endpoint not configured\n </Typography>\n </Box>\n )}\n\n {newKeySnippets && (\n <Box mt={2}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" gutterBottom>\n Public endpoint \u2014 paste into any tool's base URL / API base field\n </Typography>\n <Box\n display=\"flex\"\n alignItems=\"center\"\n gap={1}\n p={1.5}\n sx={{\n backgroundColor: 'action.hover',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n }}\n >\n <Typography\n component=\"code\"\n color=\"text.primary\"\n sx={{ fontFamily: 'monospace', fontSize: 13, wordBreak: 'break-all', flex: 1 }}\n >\n {newKeySnippets.publicEndpoint}\n </Typography>\n <Tooltip title={clipboardEndpoint.copied ? 'Copied' : 'Copy endpoint'} placement=\"top\">\n <IconButton\n size=\"small\"\n aria-label=\"Copy endpoint\"\n onClick={() => clipboardEndpoint.copy(newKeySnippets.publicEndpoint)}\n >\n {clipboardEndpoint.copied ? <Check fontSize=\"small\" /> : <ContentCopy fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n </Box>\n )}\n\n {newKeySnippets && (\n <Box mt={3}>\n <Box display=\"flex\" alignItems=\"center\" gap={1} mb={1}>\n <Code fontSize=\"small\" color=\"action\" />\n <Typography variant=\"subtitle2\">\n Start calling the proxy \u2014 paste and run\n </Typography>\n </Box>\n <SnippetTabs snippets={newKeySnippets} model={newKeyModel} copyState={clipboardSnippet} />\n </Box>\n )}\n </Box>\n ) : (\n <Box display=\"flex\" flexDirection=\"column\" gap={2} mt={1}>\n {!isCreate && (\n <Typography variant=\"body2\" color=\"text.secondary\">\n <code style={{ fontFamily: 'monospace', color: 'inherit' }}>{maskKey(editKeyId)}</code>\n </Typography>\n )}\n {generateError && (\n <Alert severity=\"error\" onClose={() => setGenerateError(null)}>\n {generateError}\n </Alert>\n )}\n {editError && (\n <Alert severity=\"error\" onClose={() => setEditError(null)}>\n {editError}\n </Alert>\n )}\n\n {/* Field order: Team \u2192 Models \u2192 Budget \u2192 Duration \u2192 Alias \u2192 Advanced */}\n {renderTeamField()}\n\n {(availableModels.length > 0 || modelsError) && (\n <>\n {modelsError ? (\n <TextField\n label=\"Models\"\n disabled\n value=\"\"\n helperText=\"Couldn't load models. Retry\"\n fullWidth\n />\n ) : (\n <Autocomplete\n multiple\n options={availableModels}\n groupBy={m => m.mode || 'other'}\n getOptionLabel={m => m.model_name}\n value={selectedModels}\n onChange={(_e, selected) =>\n setFormData({ models: selected.map(m => m.model_name) })\n }\n renderOption={(props, m) => <li {...props}>{modelOption(m)}</li>}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Models\"\n helperText={\n teamForModels\n ? 'Leave empty to allow all models available to this team'\n : 'Leave empty to allow all models'\n }\n fullWidth\n />\n )}\n />\n )}\n {modelsError && onRetryModels && (\n <Button size=\"small\" onClick={onRetryModels}>\n Retry\n </Button>\n )}\n </>\n )}\n\n {allowUnlimitedBudget && (\n <FormControlLabel\n control={\n <Checkbox\n checked={unlimitedBudget}\n onChange={(e) => {\n setUnlimitedBudget(e.target.checked);\n if (e.target.checked) {\n setFormData({ max_budget: null });\n } else {\n setFormData({ max_budget: editFormState.max_budget ?? generateForm.max_budget ?? 100 });\n }\n }}\n />\n }\n label=\"Unlimited budget\"\n />\n )}\n <TextField\n inputRef={budgetInputRef}\n label=\"Max Budget\"\n type=\"number\"\n value={unlimitedBudget ? '' : formData.max_budget ?? ''}\n onChange={(e) => {\n setFormData({ max_budget: e.target.value ? Number(e.target.value) : undefined });\n setGenerateError(null);\n setEditError(null);\n }}\n onBlur={() => setTouched(prev => ({ ...prev, budget: true }))}\n error={budgetInvalid}\n helperText={budgetHelperText(budgetInvalid, budgetEstimate, unlimitedBudget)}\n disabled={unlimitedBudget}\n required\n fullWidth\n InputProps={{\n startAdornment: <InputAdornment position=\"start\">$</InputAdornment>,\n }}\n inputProps={{ min: 0, step: 0.01 }}\n />\n\n {!isCreate ? null : (\n <>\n <TextField\n select\n label=\"Duration\"\n value={generateForm.duration || '30d'}\n onChange={(e) => setFormData({ duration: e.target.value })}\n fullWidth\n >\n {DEFAULT_KEY_DURATIONS.map((duration) => (\n <MenuItem key={duration} value={duration}>\n {formatDurationLabel(duration)}\n </MenuItem>\n ))}\n </TextField>\n {generateForm.duration && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {expiryPreview(generateForm.duration)}\n </Typography>\n )}\n </>\n )}\n\n <TextField\n inputRef={aliasInputRef}\n label=\"Alias\"\n value={currentAlias}\n onChange={(e) => {\n setAliasField(e.target.value);\n setGenerateError(null);\n setEditError(null);\n }}\n onBlur={() => setTouched(prev => ({ ...prev, alias: true }))}\n error={aliasError}\n color={aliasDuplicate ? 'warning' : undefined}\n helperText={aliasHelperText(aliasError, aliasDuplicate)}\n required\n fullWidth\n />\n\n <Accordion disableGutters elevation={0} sx={{ border: '1px solid', borderColor: 'divider', '&:before': { display: 'none' } }}>\n <AccordionSummary expandIcon={<ExpandMore />}>\n <Typography variant=\"body2\" fontWeight={600}>Advanced</Typography>\n </AccordionSummary>\n <AccordionDetails sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"TPM Limit\"\n type=\"number\"\n value={formData.tpm_limit ?? ''}\n onChange={(e) =>\n setFormData({ tpm_limit: e.target.value ? Number(e.target.value) : undefined })\n }\n helperText=\"Max tokens per minute this key can consume across all models. Leave blank for no limit.\"\n fullWidth\n />\n <TextField\n label=\"RPM Limit\"\n type=\"number\"\n value={formData.rpm_limit ?? ''}\n onChange={(e) =>\n setFormData({ rpm_limit: e.target.value ? Number(e.target.value) : undefined })\n }\n helperText=\"Max requests per minute this key can make across all models. Leave blank for no limit.\"\n fullWidth\n />\n </AccordionDetails>\n </Accordion>\n {renderDangerZone()}\n </Box>\n )}\n </DialogContent>\n <DialogActions>\n {newKeyValue ? (\n <Button onClick={handleCloseSecretDialog} variant=\"contained\" color=\"success\">\n Done\n </Button>\n ) : (\n <>\n <Button onClick={handleCloseWithoutConfirm}>Cancel</Button>\n <Button\n onClick={isCreate ? handleGenerate : handleUpdate}\n variant=\"contained\"\n color=\"primary\"\n disabled={submitting}\n >\n {submitting ? <CircularProgress size={24} /> : submitLabel}\n </Button>\n </>\n )}\n </DialogActions>\n\n {/* Confirm close without copying the secret */}\n <Dialog open={closeWithoutCopyConfirm} onClose={() => setCloseWithoutCopyConfirm(false)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>Close Without Copying?</DialogTitle>\n <DialogContent>\n <Typography>\n You haven't copied the key. Close anyway?\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setCloseWithoutCopyConfirm(false)}>\n Go back\n </Button>\n <Button\n onClick={handleConfirmCloseWithoutCopy}\n variant=\"contained\"\n color=\"error\"\n >\n Close anyway\n </Button>\n </DialogActions>\n </Dialog>\n </Dialog>\n );\n};\n\nexport function fmtCost(perToken?: number): string | null {\n if (!perToken) return null;\n const per1k = perToken * 1000;\n return per1k < 0.01 ? `$${(perToken * 1_000_000).toFixed(2)}/M` : `$${per1k.toFixed(3)}/1K`;\n}\n\nexport function formatContextWindow(\n maxInput?: number,\n maxOutput?: number,\n): string | null {\n if (!maxInput && !maxOutput) return null;\n const fmt = (n?: number) => {\n if (!n) return null;\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${Math.round(n / 1000)}K`;\n return String(n);\n };\n const inPart = fmt(maxInput);\n const outPart = fmt(maxOutput);\n if (inPart && outPart) return `ctx ${inPart} in / ${outPart} out`;\n if (inPart) return `ctx ${inPart}`;\n if (outPart) return `ctx ${outPart} out`;\n return null;\n}", "import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport Button from '@mui/material/Button';\nimport Alert from '@mui/material/Alert';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport MenuItem from '@mui/material/MenuItem';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport Typography from '@mui/material/Typography';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Paper from '@mui/material/Paper';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport { Delete as DeleteIcon } from '@mui/icons-material';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { stringifyEntityRef, UserEntity } from '@backstage/catalog-model';\nimport { TeamInfo, ModelInfo, LiteLlmConfig, CreateTeamRequest, UpdateTeamRequest, VectorStoreInfo, McpServerInfo } from '../types';\nimport { StatusPill, dataTableSx } from './ui';\n\n/** A catalog User entity flattened into what the member picker needs. */\ninterface UserOption {\n ref: string;\n label: string;\n email?: string;\n}\n\n/** Spend-reset periods offered for a team budget (LiteLLM `budget_duration`). */\nconst BUDGET_DURATION_OPTIONS: Array<{ value: string; label: string }> = [\n { value: '1d', label: 'Daily (1d)' },\n { value: '7d', label: 'Weekly (7d)' },\n { value: '30d', label: 'Monthly (30d)' },\n { value: '90d', label: 'Quarterly (90d)' },\n { value: '365d', label: 'Yearly (365d)' },\n];\nconst DEFAULT_BUDGET_DURATION = '30d';\nconst FALLBACK_BUDGET_CEILING = 1000;\n\ninterface ManageTeamDialogProps {\n open: boolean;\n onClose: () => void;\n mode: 'create' | 'edit';\n team?: TeamInfo;\n allModels: ModelInfo[];\n config?: LiteLlmConfig;\n onSubmit: (payload: CreateTeamRequest | UpdateTeamRequest) => Promise<void>;\n /** When true, the Members section (edit mode only) exposes add/remove controls. */\n canManageMembers?: boolean;\n /** Called to add a member; the parent is expected to refresh `team` on success. */\n onAddMember?: (userEntityRef: string, maxBudgetInTeam?: number) => Promise<void>;\n /** Called to remove a member; the parent is expected to refresh `team` on success. */\n onRemoveMember?: (userEntityRef: string) => Promise<void>;\n /** When true, the Knowledge Bases section (edit mode only) is shown. */\n canManageKnowledgeBases?: boolean;\n /** Vector stores the caller may attach (already allowlist-filtered server-side). */\n vectorStores?: VectorStoreInfo[];\n /** Called to replace the team's attached knowledge bases; parent refreshes `team`. */\n onSaveKnowledgeBases?: (vectorStoreIds: string[]) => Promise<void>;\n /** When true, the MCP Servers section (edit mode only) is shown. */\n canManageMcpServers?: boolean;\n /** MCP servers the caller may attach (already allowlist-filtered server-side). */\n mcpServers?: McpServerInfo[];\n /** Called to replace the team's attached MCP servers; parent refreshes `team`. */\n onSaveMcpServers?: (mcpServerIds: string[]) => Promise<void>;\n /** When true, only members section is shown (not budget/models/KB/MCP); title changes; Save becomes Done. */\n membersOnly?: boolean;\n /** Current user's LiteLLM ID; used in membersOnly mode to prevent self-removal and role-restricted removal. */\n currentUserId?: string;\n /** Roles that can manage members in membersOnly mode; used to disable removal of role holders. */\n memberManagerRoles?: string[];\n}\n\nexport const ManageTeamDialog: FC<ManageTeamDialogProps> = ({\n open,\n onClose,\n mode,\n team,\n allModels,\n config,\n onSubmit,\n canManageMembers,\n onAddMember,\n onRemoveMember,\n canManageKnowledgeBases,\n vectorStores,\n onSaveKnowledgeBases,\n canManageMcpServers,\n mcpServers,\n onSaveMcpServers,\n membersOnly,\n currentUserId,\n memberManagerRoles,\n}) => {\n const [alias, setAlias] = useState('');\n const [models, setModels] = useState<string[]>([]);\n const [maxBudget, setMaxBudget] = useState<string>('');\n const [unlimited, setUnlimited] = useState(false);\n const [budgetDuration, setBudgetDuration] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // memberQuery is the text shown in the picker; memberRef is the entity ref\n // that will actually be submitted (either a picked catalog user's ref, or\n // whatever was typed, as a fallback for catalog lookup failures).\n const [memberQuery, setMemberQuery] = useState('');\n const [memberRef, setMemberRef] = useState('');\n const [memberBudget, setMemberBudget] = useState('');\n const [memberBusy, setMemberBusy] = useState(false);\n const [memberError, setMemberError] = useState<string | null>(null);\n\n const [kbIds, setKbIds] = useState<string[]>([]);\n const [kbBusy, setKbBusy] = useState(false);\n const [kbError, setKbError] = useState<string | null>(null);\n\n const [mcpIds, setMcpIds] = useState<string[]>([]);\n const [mcpBusy, setMcpBusy] = useState(false);\n const [mcpError, setMcpError] = useState<string | null>(null);\n\n const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;\n const maxBudgetCeiling =\n config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;\n // When budgets are hidden even from managers, the field becomes write-only:\n // the current value is never shown, and leaving it blank keeps it unchanged.\n const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;\n const budgetWriteOnly = hideBudgetForManagers && mode === 'edit';\n\n const members = useMemo(() => team?.members_with_roles ?? [], [team]);\n const showMembers = (mode === 'edit' && !!canManageMembers) || membersOnly;\n\n // Catalog users for the member picker, fetched on demand with debounced search.\n // Failures degrade to an empty option list \u2014 the field stays usable as a\n // plain entity-ref input either way.\n const catalogApi = useApi(catalogApiRef);\n const [searchUsers, setSearchUsers] = useState<UserEntity[]>([]);\n const [usersLoading, setUsersLoading] = useState(false);\n const debounceTimerRef = useRef<NodeJS.Timeout>();\n\n const handleUserSearch = useCallback(async (term: string) => {\n // Clear any pending debounce.\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n if (!term.trim()) {\n setSearchUsers([]);\n return;\n }\n\n setUsersLoading(true);\n debounceTimerRef.current = setTimeout(async () => {\n try {\n const { items } = await catalogApi.queryEntities({\n filter: { kind: 'User' },\n fullTextFilter: {\n term: term.trim(),\n fields: ['metadata.name', 'spec.profile.displayName', 'spec.profile.email'],\n },\n limit: 20,\n });\n setSearchUsers(items as UserEntity[]);\n } catch {\n setSearchUsers([]);\n } finally {\n setUsersLoading(false);\n }\n }, 300); // 300ms debounce\n }, [catalogApi]);\n\n const userOptions = useMemo<UserOption[]>(() => {\n const existingEmails = new Set(\n members\n .map(m => m.user_email?.toLowerCase())\n .filter((e): e is string => !!e),\n );\n return (searchUsers ?? [])\n .map(e => {\n const ref = stringifyEntityRef(e);\n const displayName =\n e.spec?.profile?.displayName || e.metadata.title || e.metadata.name;\n const email = e.spec?.profile?.email;\n return {\n ref,\n email,\n label: email ? `${displayName} (${email})` : displayName,\n };\n })\n .filter(o => !(o.email && existingEmails.has(o.email.toLowerCase())))\n .sort((a, b) => a.label.localeCompare(b.label));\n }, [searchUsers, members]);\n\n // Clean up debounce timer on unmount.\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n if (open) {\n if (mode === 'edit' && team) {\n setAlias(team.team_alias ?? '');\n setModels(team.models ?? []);\n if (hideBudgetForManagers) {\n // Write-only: never prefill (the backend redacts the value anyway).\n setMaxBudget('');\n } else {\n setMaxBudget(\n team.max_budget ? String(team.max_budget) : String(maxBudgetCeiling),\n );\n }\n setUnlimited(allowUnlimitedBudget && !team.max_budget);\n setBudgetDuration(team.budget_duration ?? DEFAULT_BUDGET_DURATION);\n } else {\n setAlias('');\n setModels([]);\n // Default a new team's budget to the ceiling; the admin can lower it.\n setMaxBudget(String(maxBudgetCeiling));\n setUnlimited(allowUnlimitedBudget);\n setBudgetDuration(DEFAULT_BUDGET_DURATION);\n }\n setError(null);\n setMemberQuery('');\n setMemberRef('');\n setMemberBudget('');\n setMemberError(null);\n setKbIds(team?.object_permission?.vector_stores ?? []);\n setKbError(null);\n setMcpIds(team?.object_permission?.mcp_servers ?? []);\n setMcpError(null);\n }\n }, [open, mode, team, allowUnlimitedBudget, maxBudgetCeiling, hideBudgetForManagers]);\n\n const handleSubmit = async () => {\n setError(null);\n\n if (!alias.trim()) {\n setError('Team alias is required');\n return;\n }\n\n if (models.length === 0) {\n setError('At least one model is required');\n return;\n }\n\n if (!unlimited) {\n // Write-only mode: a blank budget leaves the hidden value unchanged.\n const budgetLeftBlank = budgetWriteOnly && !maxBudget.trim();\n if (!budgetLeftBlank) {\n if (!maxBudget) {\n setError('Budget is required when unlimited budgets are disabled');\n return;\n }\n const budget = parseFloat(maxBudget);\n if (isNaN(budget) || budget <= 0) {\n setError('Budget must be a positive number');\n return;\n }\n if (budget > maxBudgetCeiling) {\n setError(`Budget cannot exceed $${maxBudgetCeiling}`);\n return;\n }\n }\n }\n\n try {\n setSubmitting(true);\n let payload: CreateTeamRequest | UpdateTeamRequest;\n\n if (mode === 'create') {\n payload = {\n team_alias: alias.trim(),\n models,\n ...(unlimited ? { max_budget: null } : { max_budget: parseFloat(maxBudget) }),\n ...(budgetDuration && { budget_duration: budgetDuration }),\n } as CreateTeamRequest;\n } else {\n // Write-only mode: a blank budget omits the field (leave unchanged).\n // Otherwise validation above guarantees a non-empty value here.\n let budgetField: { max_budget?: number | null } = {};\n if (unlimited) {\n budgetField = { max_budget: null };\n } else if (maxBudget.trim()) {\n budgetField = { max_budget: parseFloat(maxBudget) };\n }\n payload = {\n team_alias: alias.trim(),\n models,\n ...budgetField,\n ...(budgetDuration && { budget_duration: budgetDuration }),\n } as UpdateTeamRequest;\n }\n\n await onSubmit(payload);\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'An error occurred');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleAddMember = async () => {\n if (!onAddMember || !memberRef.trim()) return;\n setMemberError(null);\n // Members-only managers cannot set member budgets (server refuses it).\n const budget =\n !membersOnly && memberBudget ? parseFloat(memberBudget) : undefined;\n if (budget !== undefined && (isNaN(budget) || budget <= 0)) {\n setMemberError('Max budget in team must be a positive number');\n return;\n }\n try {\n setMemberBusy(true);\n await onAddMember(memberRef.trim(), budget);\n setMemberQuery('');\n setMemberRef('');\n setMemberBudget('');\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to add member');\n } finally {\n setMemberBusy(false);\n }\n };\n\n const handleRemoveMember = async (userId: string) => {\n if (!onRemoveMember) return;\n setMemberError(null);\n try {\n setMemberBusy(true);\n await onRemoveMember(userId);\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to remove member');\n } finally {\n setMemberBusy(false);\n }\n };\n\n const handleSaveKnowledgeBases = async () => {\n if (!onSaveKnowledgeBases) return;\n setKbError(null);\n try {\n setKbBusy(true);\n await onSaveKnowledgeBases(kbIds);\n } catch (err) {\n setKbError(err instanceof Error ? err.message : 'Failed to save knowledge bases');\n } finally {\n setKbBusy(false);\n }\n };\n\n const handleSaveMcpServers = async () => {\n if (!onSaveMcpServers) return;\n setMcpError(null);\n try {\n setMcpBusy(true);\n await onSaveMcpServers(mcpIds);\n } catch (err) {\n setMcpError(err instanceof Error ? err.message : 'Failed to save MCP servers');\n } finally {\n setMcpBusy(false);\n }\n };\n\n const modelNames = allModels.map(m => m.model_name);\n // Keep an unusual existing value (e.g. \"14d\", \"1mo\") selectable so editing a\n // team doesn't silently rewrite its duration.\n const durationOptions = BUDGET_DURATION_OPTIONS.some(o => o.value === budgetDuration)\n ? BUDGET_DURATION_OPTIONS\n : [...BUDGET_DURATION_OPTIONS, { value: budgetDuration, label: budgetDuration }];\n const showKnowledgeBases = mode === 'edit' && !!canManageKnowledgeBases;\n const kbOptions = (vectorStores ?? []).map(v => v.id);\n const kbLabel = (id: string) =>\n (vectorStores ?? []).find(v => v.id === id)?.name ?? id;\n const showMcpServers = mode === 'edit' && !!canManageMcpServers;\n const mcpOptions = (mcpServers ?? []).map(s => s.id);\n const mcpLabel = (id: string) =>\n (mcpServers ?? []).find(s => s.id === id)?.name ?? id;\n\n // In membersOnly mode, determine if a member removal is disabled\n const isRemovalDisabled = (memberUserId: string, memberRole: string): { disabled: boolean; reason?: string } => {\n if (!membersOnly) return { disabled: false };\n if (memberUserId === currentUserId) {\n return { disabled: true, reason: \"You can't remove yourself\" };\n }\n if (memberManagerRoles?.includes(memberRole)) {\n return { disabled: true, reason: `Only platform admins can remove a team ${memberRole}` };\n }\n return { disabled: false };\n };\n\n const getDialogTitle = () => {\n if (membersOnly) {\n return `Manage members \u2014 ${team?.team_alias || 'Untitled team'}`;\n }\n return mode === 'create' ? 'Create Team' : 'Edit Team';\n };\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>{getDialogTitle()}</DialogTitle>\n <DialogContent sx={{ pt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {membersOnly && (\n <Alert severity=\"info\">\n As a team {team?.members_with_roles?.find(m => m.user_id === currentUserId)?.role || 'member'} you can add or remove members. Budgets and models are managed by your platform admins.\n </Alert>\n )}\n\n {!membersOnly && (\n <>\n <TextField\n label=\"Team Alias\"\n value={alias}\n onChange={e => setAlias(e.target.value)}\n disabled={submitting}\n fullWidth\n />\n\n <Autocomplete\n multiple\n options={modelNames}\n value={models}\n onChange={(_, newValue) => setModels(newValue)}\n disabled={submitting}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Models\"\n required\n helperText=\"At least one model is required here \u2014 this delegated flow only grants access to models your admin has allow-listed for team creation, not every proxy model. (Teams with no model restriction shown elsewhere were configured directly in LiteLLM.)\"\n />\n )}\n />\n\n <TextField\n label={budgetWriteOnly ? 'New Max Budget ($)' : 'Max Budget ($)'}\n type=\"number\"\n value={maxBudget}\n onChange={e => setMaxBudget(e.target.value)}\n disabled={submitting || unlimited}\n inputProps={{ min: 0, max: maxBudgetCeiling }}\n helperText={\n budgetWriteOnly\n ? 'Current budget is hidden \u2014 leave blank to keep it, or enter a new value'\n : `Maximum: $${maxBudgetCeiling}`\n }\n fullWidth\n />\n\n {allowUnlimitedBudget && (\n <FormControlLabel\n control={<Checkbox checked={unlimited} onChange={e => setUnlimited(e.target.checked)} disabled={submitting} />}\n label=\"Unlimited Budget\"\n />\n )}\n\n <TextField\n select\n label=\"Budget Duration\"\n value={budgetDuration}\n onChange={e => setBudgetDuration(e.target.value)}\n disabled={submitting || unlimited}\n helperText=\"Spend-reset period for the team budget\"\n fullWidth\n >\n {durationOptions.map(o => (\n <MenuItem key={o.value} value={o.value}>\n {o.label}\n </MenuItem>\n ))}\n </TextField>\n </>\n )}\n\n {showMembers && (\n <Box>\n <Divider sx={{ my: 1 }} />\n <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>\n Members\n </Typography>\n {memberError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setMemberError(null)}>\n {memberError}\n </Alert>\n )}\n {members.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n No members yet.\n </Typography>\n ) : (\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 1.5, mb: 1.5 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>User</TableCell>\n <TableCell align=\"right\">Role</TableCell>\n <TableCell align=\"right\" sx={{ width: 40 }} />\n </TableRow>\n </TableHead>\n <TableBody>\n {members.map(m => (\n <TableRow key={m.user_id}>\n <TableCell>\n {m.user_email ? (\n <>\n <Typography variant=\"body2\">{m.user_email}</Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {m.user_id}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"body2\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {m.user_id}\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <StatusPill label={m.role} tone={m.role === 'admin' ? 'accent' : 'neutral'} dot={false} />\n </TableCell>\n <TableCell align=\"right\">\n {(() => {\n const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);\n // span wrapper: a disabled button emits no hover events\n return (\n <Tooltip title={reason ?? ''}>\n <span>\n <IconButton\n edge=\"end\"\n size=\"small\"\n aria-label={`remove ${m.user_id}`}\n disabled={memberBusy || disabled}\n onClick={() => handleRemoveMember(m.user_id)}\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n );\n })()}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'flex-start', flexWrap: 'wrap' }}>\n <Autocomplete\n freeSolo\n autoHighlight\n options={userOptions}\n loading={usersLoading}\n inputValue={memberQuery}\n onInputChange={(_, newInputValue, reason) => {\n setMemberQuery(newInputValue);\n // 'reset' fires when a selection sets the input programmatically \u2014\n // memberRef is already set by onChange in that case, so only sync\n // free typing (and clearing) back into the submitted ref here.\n if (reason === 'input' || reason === 'clear') {\n setMemberRef(newInputValue);\n // Trigger a debounced search for new results.\n handleUserSearch(newInputValue);\n }\n }}\n onChange={(_, newValue) => {\n if (newValue && typeof newValue !== 'string') {\n setMemberQuery(newValue.label);\n setMemberRef(newValue.ref);\n }\n }}\n getOptionLabel={o => (typeof o === 'string' ? o : o.label)}\n isOptionEqualToValue={(o, v) => o.ref === (typeof v === 'string' ? v : v.ref)}\n disabled={memberBusy}\n sx={{ flex: 1, minWidth: 260 }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Add member\"\n placeholder=\"Search by name or email\u2026\"\n size=\"small\"\n helperText=\"Pick a catalog user, or paste a user entity ref\"\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {usersLoading ? <CircularProgress color=\"inherit\" size={14} /> : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n />\n )}\n />\n {!membersOnly && (\n <TextField\n label=\"Max budget in team ($)\"\n type=\"number\"\n value={memberBudget}\n onChange={e => setMemberBudget(e.target.value)}\n disabled={memberBusy}\n size=\"small\"\n sx={{ width: 160 }}\n />\n )}\n <Button\n onClick={handleAddMember}\n disabled={memberBusy || !memberRef.trim()}\n variant=\"outlined\"\n sx={{ mt: 0.5 }}\n >\n Add\n </Button>\n </Box>\n </Box>\n )}\n\n {!membersOnly && showKnowledgeBases && (\n <Box>\n <Divider sx={{ my: 1 }} />\n <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>\n Knowledge Bases\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n Attaching a knowledge base exposes its documents to every key in\n this team.\n </Typography>\n {kbError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setKbError(null)}>\n {kbError}\n </Alert>\n )}\n <Autocomplete\n multiple\n options={kbOptions}\n value={kbIds}\n getOptionLabel={kbLabel}\n onChange={(_, v) => setKbIds(v)}\n disabled={kbBusy}\n renderInput={params => (\n <TextField {...params} label=\"Attached knowledge bases\" />\n )}\n />\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>\n <Button\n onClick={handleSaveKnowledgeBases}\n disabled={kbBusy}\n variant=\"outlined\"\n >\n {kbBusy ? 'Saving\u2026' : 'Save knowledge bases'}\n </Button>\n </Box>\n </Box>\n )}\n\n {!membersOnly && showMcpServers && (\n <Box>\n <Divider sx={{ my: 1 }} />\n <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>\n MCP Servers\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n Attaching an MCP server lets every key in this team invoke that\n server's tools through the model \u2014 including any side effects\n those tools have.\n </Typography>\n {mcpError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setMcpError(null)}>\n {mcpError}\n </Alert>\n )}\n <Autocomplete\n multiple\n options={mcpOptions}\n value={mcpIds}\n getOptionLabel={mcpLabel}\n onChange={(_, v) => setMcpIds(v)}\n disabled={mcpBusy}\n renderInput={params => (\n <TextField {...params} label=\"Attached MCP servers\" />\n )}\n />\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>\n <Button\n onClick={handleSaveMcpServers}\n disabled={mcpBusy}\n variant=\"outlined\"\n >\n {mcpBusy ? 'Saving\u2026' : 'Save MCP servers'}\n </Button>\n </Box>\n </Box>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={submitting}>\n {membersOnly ? 'Done' : 'Cancel'}\n </Button>\n {!membersOnly && (\n <Button onClick={handleSubmit} disabled={submitting} variant=\"contained\">\n {submitting ? 'Saving...' : 'Save'}\n </Button>\n )}\n </DialogActions>\n </Dialog>\n );\n};\n", "import { UserInfo, TeamInfo, VirtualKey } from './types';\nimport { Tone } from './components/ui';\nimport { budgetStatusForPct } from '@acarmisc/backstage-plugin-litellm-common';\n\n/** One concrete budget limit the signed-in user is subject to. */\nexport interface BudgetLimit {\n kind: 'key' | 'user' | 'team';\n /** Display name: key_alias / \"Personal budget\" / team_alias. */\n label: string;\n /** Secondary identifier: masked key, team_id, etc. */\n sublabel?: string;\n /** Spend cap in USD (> 0 when a cap exists). */\n budget: number;\n /** Spend so far in the current window. */\n spend: number;\n /** Reset window, e.g. \"30d\". Missing means the budget never resets. */\n budgetDuration?: string;\n /** User-facing warning threshold (soft limit). */\n softLimit?: number;\n /** Share of the cap spent, 0..100+ (unclamped). */\n pct: number;\n /**\n * True when the backend redacted the dollar amounts (team budget hiding).\n * `budget`/`spend` are then 0 and only `pct` carries the signal \u2014 render\n * the meter without `$` figures.\n */\n hidden?: boolean;\n}\n\n/** The budgets that apply to the current user, grouped by enforcement level. */\nexport interface BudgetSummary {\n /** Budgeted keys, capped at `maxKeys`, closest to the cap first. */\n keys: BudgetLimit[];\n /** Budgeted keys hidden by the cap. */\n hiddenBudgetedKeys: number;\n /** Every key owned by the user (budgeted or not). */\n totalKeyCount: number;\n /** Personal budget, when one is set (undefined otherwise). */\n user?: BudgetLimit;\n /** Team budgets shared by the user's teams. */\n teams: BudgetLimit[];\n}\n\n/** Share of the cap spent, unclamped so 120% stays visible as such. */\nfunction limitPct(spend: number, budget: number): number {\n if (budget <= 0) return 0;\n return (spend / budget) * 100;\n}\n\n/**\n * Collapses the current user's data into the budget limits that LiteLLM\n * actually enforces for them: key budgets (top `maxKeys`, closest to the cap\n * first), then the personal budget (when set), then each team budget. Team\n * budgets are enforced for every key bound to that team; a key *without* a\n * team falls back to the owner's personal budget.\n */\nexport function buildBudgetSummary(\n user: UserInfo | null,\n teams: TeamInfo[],\n keys: VirtualKey[],\n maxKeys = 3,\n): BudgetSummary {\n const budgeted = keys\n .filter(k => (k.max_budget ?? 0) > 0)\n .map(k => {\n const spend = k.spend ?? 0;\n return {\n kind: 'key' as const,\n label: k.key_alias || k.key || 'Untitled key',\n sublabel: k.key,\n budget: k.max_budget!,\n spend,\n budgetDuration: k.budget_duration,\n pct: limitPct(spend, k.max_budget!),\n };\n })\n .sort((a, b) => b.pct - a.pct);\n\n const userBudget =\n user && (user.max_budget ?? user.hard_limit ?? 0) > 0\n ? (() => {\n const budget = user.max_budget ?? user.hard_limit ?? 0;\n const spend = user.current_spend ?? user.spend ?? 0;\n return {\n kind: 'user' as const,\n label: 'Personal budget',\n sublabel: user.user_email || user.user_id,\n budget,\n spend,\n budgetDuration: user.budget_duration,\n softLimit: user.soft_limit,\n pct: limitPct(spend, budget),\n };\n })()\n : undefined;\n\n const teamLimits: BudgetLimit[] = teams\n .filter(t => (t.max_budget ?? 0) > 0 || t.budget_hidden === true)\n .map(t => {\n if (t.budget_hidden === true) {\n return {\n kind: 'team' as const,\n label: t.team_alias || 'Untitled team',\n sublabel: t.team_id,\n budget: 0,\n spend: 0,\n budgetDuration: t.budget_duration,\n pct: Math.min(100, Math.max(0, t.budget_pct ?? 0)),\n hidden: true as const,\n };\n }\n const spend = t.spend ?? 0;\n return {\n kind: 'team' as const,\n label: t.team_alias || 'Untitled team',\n sublabel: t.team_id,\n budget: t.max_budget!,\n spend,\n budgetDuration: t.budget_duration,\n pct: limitPct(spend, t.max_budget!),\n };\n })\n .sort((a, b) => b.pct - a.pct);\n\n return {\n keys: budgeted.slice(0, maxKeys),\n hiddenBudgetedKeys: Math.max(0, budgeted.length - maxKeys),\n totalKeyCount: keys.length,\n user: userBudget,\n teams: teamLimits,\n };\n}\n\n/**\n * Every concrete limit across all levels, keys first then personal then\n * teams. The per-level slices are already sorted by proximity to the cap, so\n * each level's limits stay ordered; this is the flat list for a \"show all\n * limits\" view. Keys beyond a display `maxKeys` are not included \u2014 build the\n * summary with a large `maxKeys` when the full list is needed.\n */\nexport function allBudgetLimits(summary: BudgetSummary): BudgetLimit[] {\n return [\n ...summary.keys,\n ...(summary.user ? [summary.user] : []),\n ...summary.teams,\n ];\n}\n\n/** One gauge in the condensed homepage card \u2014 a single enforcement level. */\nexport interface BudgetGauge {\n kind: 'key' | 'user' | 'team';\n /**\n * The limit of this level nearest its cap, or undefined when the user has\n * no cap at this level (render an empty gauge).\n */\n limit?: BudgetLimit;\n /** How many limits apply at this level (1 for a personal budget). */\n count: number;\n}\n\nconst GAUGE_KINDS: Array<BudgetGauge['kind']> = ['key', 'user', 'team'];\n\n/**\n * Collapses a `BudgetSummary` to exactly one gauge per enforcement level \u2014\n * key, user, team \u2014 carrying the limit nearest its cap and how many limits\n * that level holds. Every level is always returned, with `limit` undefined\n * when the user has no cap there, so the caller can render a stable row.\n *\n * Pass a summary built with a large `maxKeys` (e.g. `keys.length`) so the\n * nearest key is present even when it falls outside the display cap; a key\n * count hidden by that cap is still reflected in `count`.\n */\nexport function buildBudgetGauges(summary: BudgetSummary): BudgetGauge[] {\n const byLevel: Record<BudgetGauge['kind'], BudgetLimit[]> = {\n key: summary.keys,\n user: summary.user ? [summary.user] : [],\n team: summary.teams,\n };\n return GAUGE_KINDS.map(kind => {\n const limits = byLevel[kind];\n const count =\n kind === 'key' ? limits.length + summary.hiddenBudgetedKeys : limits.length;\n return {\n kind,\n count,\n limit: limits.length\n ? limits.reduce((a, b) => (b.pct > a.pct ? b : a))\n : undefined,\n };\n });\n}\n\n/**\n * One-line summary of a `BudgetSummary`, for a collapsed/compact header:\n * how many concrete limits the user is subject to, and the one closest to\n * its cap \u2014 kept as the whole `BudgetLimit` so the caller can name its\n * level (key / personal / team). `closest` is null when there are no limits.\n */\nexport function budgetHeadline(summary: BudgetSummary): {\n count: number;\n closest: BudgetLimit | null;\n} {\n const all: BudgetLimit[] = [\n ...summary.keys,\n ...(summary.user ? [summary.user] : []),\n ...summary.teams,\n ];\n const count =\n summary.keys.length +\n summary.hiddenBudgetedKeys +\n (summary.user ? 1 : 0) +\n summary.teams.length;\n const closest = all.length\n ? all.reduce((a, b) => (b.pct > a.pct ? b : a))\n : null;\n return { count, closest };\n}\n\n/** \"30d\" \u2192 \"every 30 days\"; \"1d\" \u2192 \"daily\". Returns null when duration is unset. */\nexport function fmtBudgetDuration(duration?: string): string | null {\n if (!duration) return null;\n const m = /^(\\d+)(s|m|h|d)$/.exec(duration);\n if (!m) return duration;\n const n = Number(m[1]);\n const unit = m[2];\n if (unit === 'd') return n === 1 ? 'daily' : `every ${n} days`;\n if (unit === 'h') return n === 1 ? 'hourly' : `every ${n} hours`;\n if (unit === 'm') return n === 1 ? 'every minute' : `every ${n} minutes`;\n return n === 1 ? 'every second' : `every ${n} seconds`;\n}\n\n/** status pill tone + meter tone for a budget at `pct`. */\nexport function budgetTone(pct: number): Tone {\n const status = budgetStatusForPct(pct);\n if (status === 'over') return 'danger';\n if (status === 'near') return 'warning';\n return 'accent';\n}\n\n/** Budget status for the signed-in user's overall spend vs their cap. */\nexport interface UserBudgetKpi {\n /** Total spend in the active budget window (lifetime or reset period). */\n spend: number;\n /** The budget cap, or null if unlimited. */\n max: number | null;\n /** max - spend, clamped at >= 0 for display. Null if unlimited. */\n remaining: number | null;\n /** spend / max * 100, or null if unlimited. Unclamped (can be > 100). */\n pct: number | null;\n /** 'capped' when a budget exists, 'unlimited' otherwise. */\n kind: 'capped' | 'unlimited';\n /**\n * Caption for the KPI. When capped: \"resets {formatted reset_at}\" if reset_at\n * exists and budget_duration is set, else \"lifetime cap\". Null if unlimited.\n */\n resetLabel: string | null;\n}\n\n/**\n * Compute the user's budget status: spend vs their personal cap.\n * Returns { spend, max, remaining, pct, kind, resetLabel } where remaining\n * is clamped at >= 0 for display purposes but pct and kind reflect the real status.\n */\nexport function userBudgetKpi(userInfo: UserInfo | null): UserBudgetKpi {\n if (!userInfo) {\n return {\n spend: 0,\n max: null,\n remaining: null,\n pct: null,\n kind: 'unlimited',\n resetLabel: null,\n };\n }\n\n const spend = userInfo.spend ?? 0;\n const max = userInfo.max_budget ?? null;\n\n if (max === null || max <= 0) {\n return {\n spend,\n max: null,\n remaining: null,\n pct: null,\n kind: 'unlimited',\n resetLabel: null,\n };\n }\n\n const remaining = Math.max(0, max - spend);\n const pct = (spend / max) * 100;\n\n // Format reset label\n let resetLabel: string;\n if (userInfo.budget_duration && userInfo.budget_reset_at) {\n try {\n const resetDate = new Date(userInfo.budget_reset_at);\n // Format as \"MMM D, YYYY HH:MM\" (e.g., \"Jan 1, 2026 00:00\")\n const fmt = new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n timeZone: 'UTC',\n });\n const formatted = fmt.format(resetDate);\n resetLabel = `resets ${formatted}`;\n } catch {\n resetLabel = 'lifetime cap';\n }\n } else {\n resetLabel = 'lifetime cap';\n }\n\n return {\n spend,\n max,\n remaining,\n pct,\n kind: 'capped',\n resetLabel,\n };\n}", "import { FC, ReactNode, useEffect, useMemo, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Grid from '@mui/material/Grid';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport Skeleton from '@mui/material/Skeleton';\nimport {\n AreaChart,\n Area,\n BarChart,\n Bar,\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n ReferenceLine,\n Cell,\n} from 'recharts';\nimport {\n DateRange,\n UsageMetrics,\n ModelInfo,\n UserInfo,\n UsageModelBreakdown,\n UsageKeyBreakdown,\n} from '../types';\nimport { fmtUsd, fmtInt, modelsWithUsage } from '../format';\nimport { userBudgetKpi } from '../budget';\nimport {\n ChartCard,\n ChartTooltip,\n EmptyState,\n Meter,\n MetricStrip,\n SectionCard,\n SegmentedControl,\n Tone,\n SeriesLegend,\n TagChip,\n chartColor,\n dataTableSx,\n fmtCompact,\n fmtDateShort,\n fmtUsdCompact,\n useChartTheme,\n SERIES,\n} from './ui';\n\ninterface UsageStatsProps {\n usage: UsageMetrics | null;\n usageError?: Error;\n onRetryUsage?: () => void;\n models: ModelInfo[];\n dateRange: DateRange;\n currentPreset: DatePreset;\n onDateRangeChange: (range: DateRange, preset?: DatePreset) => void;\n loading: boolean;\n userInfo?: UserInfo;\n}\n\ntype DatePreset = 'today' | '24h' | '7d' | '30d';\ntype TabKey = 'costs' | 'models' | 'keys';\n\nconst TOP_N_MODELS = 6;\nconst PERIOD_LS_KEY = 'litellm_usage_period';\n\nconst PRESET_LABELS: Record<DatePreset, string> = {\n today: 'Today',\n '24h': 'Last 24 hours',\n '7d': 'Last 7 days',\n '30d': 'Last 30 days',\n};\n\nconst fmtPct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Green above 99%, amber down to 90%, red below. */\nfunction rateTone(rate: number): Tone {\n if (rate >= 0.99) return 'success';\n if (rate >= 0.9) return 'warning';\n return 'danger';\n}\n\nconst ChartSkeleton: FC<{ height?: number }> = ({ height = 240 }) => (\n <Skeleton variant=\"rounded\" height={height} />\n);\n\n/** Shows a loading skeleton, an empty-state message, or the chart itself. */\nconst ChartOrFallback: FC<{\n loading: boolean;\n empty: boolean;\n height?: number;\n children: ReactNode;\n}> = ({ loading, empty, height = 240, children }) => {\n if (loading) return <ChartSkeleton height={height} />;\n if (empty) return <EmptyState message=\"No data for this period\" height={height} />;\n return <>{children}</>;\n};\n\n/** Inline success-rate bar used in both breakdown tables. */\nconst SuccessRateCell: FC<{ rate: number; requests: number }> = ({ rate, requests }) => {\n if (requests === 0) return <Typography variant=\"body2\" color=\"text.secondary\">\u2014</Typography>;\n const tone = rateTone(rate);\n return (\n <Box display=\"flex\" alignItems=\"center\" gap={1}>\n {/* Fixed, not flexible: the success-rate column is the last one, so a\n flexible meter stretches across all the table's slack space. */}\n <Box width={72} flexShrink={0}>\n <Meter value={rate * 100} tone={tone} height={4} />\n </Box>\n <Typography\n variant=\"caption\"\n sx={{ fontVariantNumeric: 'tabular-nums', minWidth: 44 }}\n >\n {fmtPct(rate)}\n </Typography>\n </Box>\n );\n};\n\nexport const UsageStats: FC<UsageStatsProps> = ({\n usage,\n usageError,\n onRetryUsage,\n models,\n dateRange,\n currentPreset,\n onDateRangeChange,\n loading,\n userInfo,\n}) => {\n const chart = useChartTheme();\n const [selectedModel, setSelectedModel] = useState<string>('all');\n const [tab, setTab] = useState<TabKey>('costs');\n\n // Filter to only models that have usage in the current period\n const modelsInPeriod = useMemo(\n () => modelsWithUsage(usage, models),\n [usage, models],\n );\n\n // If the currently selected model is no longer in the list, reset to 'all'\n useEffect(() => {\n if (selectedModel !== 'all' && !modelsInPeriod.includes(selectedModel)) {\n setSelectedModel('all');\n }\n }, [modelsInPeriod, selectedModel]);\n\n const handlePresetChange = (preset: DatePreset) => {\n const end = new Date();\n const start = new Date();\n if (preset === 'today') start.setHours(0, 0, 0, 0);\n else if (preset === '24h') start.setHours(start.getHours() - 24);\n else if (preset === '7d') start.setDate(start.getDate() - 7);\n else if (preset === '30d') start.setDate(start.getDate() - 30);\n try { localStorage.setItem(PERIOD_LS_KEY, preset); } catch { /* ignore */ }\n onDateRangeChange({ start, end }, preset);\n };\n\n // \u2500\u2500 daily_usage \u2192 base series \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const dailyData = useMemo(\n () =>\n (usage?.daily_usage ?? []).map(d => ({\n date: d.date,\n spend: d.spend,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n totalTokens: d.total_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n })),\n [usage],\n );\n\n // \u2500\u2500 Cumulative spend per day \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const cumulativeData = useMemo(() => {\n let cum = 0;\n return dailyData.map(d => { cum += d.spend; return { date: d.date, cumulative: cum }; });\n }, [dailyData]);\n\n // \u2500\u2500 Success rate trend (days with requests only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const successRateData = useMemo(\n () =>\n dailyData\n .filter(d => d.apiRequests > 0)\n .map(d => ({\n date: d.date,\n successRate: parseFloat(((d.successfulRequests / d.apiRequests) * 100).toFixed(1)),\n })),\n [dailyData],\n );\n\n // \u2500\u2500 Stacked spend by model per day \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const { modelSpendByDate, topModels: topSpendModels } = useMemo(() => {\n const rows = usage?.daily_by_model ?? [];\n const modelTotals: Record<string, number> = {};\n for (const r of rows) modelTotals[r.model] = (modelTotals[r.model] ?? 0) + r.spend;\n\n const top = Object.entries(modelTotals)\n .sort(([, a], [, b]) => b - a)\n .slice(0, TOP_N_MODELS)\n .map(([m]) => m);\n\n const dateMap: Record<string, Record<string, number>> = {};\n for (const r of rows) {\n if (!dateMap[r.date]) dateMap[r.date] = {};\n const bucket = top.includes(r.model) ? r.model : 'Other';\n dateMap[r.date][bucket] = (dateMap[r.date][bucket] ?? 0) + r.spend;\n }\n\n const sorted = Object.entries(dateMap)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, m]) => ({ date, ...m }));\n\n const hasOther = sorted.some(r => (r as any).Other > 0);\n return { modelSpendByDate: sorted, topModels: hasOther ? [...top, 'Other'] : top };\n }, [usage]);\n\n // \u2500\u2500 Model breakdown rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const modelRows = useMemo(() => {\n const entries = Object.entries<UsageModelBreakdown>(usage?.usage_by_model ?? {}).map(([model, d]) => ({\n model,\n spend: d.total_spend,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n totalTokens: d.total_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n successRate: d.api_requests > 0 ? d.successful_requests / d.api_requests : 0,\n }));\n return selectedModel === 'all' ? entries : entries.filter(e => e.model === selectedModel);\n }, [usage, selectedModel]);\n\n // top-models horizontal bar (sorted by spend)\n const topModelSpendBars = useMemo(\n () => [...modelRows].sort((a, b) => b.spend - a.spend).slice(0, 10),\n [modelRows],\n );\n\n // \u2500\u2500 Key breakdown rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const keyRows = useMemo(\n () =>\n Object.entries<UsageKeyBreakdown>(usage?.usage_by_key ?? {}).map(([keyHash, d]) => ({\n keyHash,\n keyAlias: d.key_alias ?? keyHash.slice(0, 8),\n teamId: d.team_id ?? null,\n models: d.models,\n spend: d.total_spend,\n totalTokens: d.total_tokens,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n successRate: d.api_requests > 0 ? d.successful_requests / d.api_requests : 0,\n })),\n [usage],\n );\n\n const topKeySpendBars = useMemo(\n () => [...keyRows].sort((a, b) => b.spend - a.spend).slice(0, 10),\n [keyRows],\n );\n\n const totalRequests = usage?.api_requests ?? 0;\n const overallSuccessRate = totalRequests > 0 ? (usage?.successful_requests ?? 0) / totalRequests : 0;\n const budgetKpi = userBudgetKpi(userInfo ?? null);\n\n // Keep the budget reference line inside the plot even when spend is far below it.\n const cumulativeDomain: any = budgetKpi.max && budgetKpi.max > 0\n ? [0, (dataMax: number) => Math.max(dataMax, budgetKpi.max!) * 1.05]\n : [0, 'auto'];\n\n const successTone: Tone = totalRequests === 0 ? 'neutral' : rateTone(overallSuccessRate);\n\n const metrics = [\n {\n label: 'Total spend',\n value: fmtUsd(usage?.total_spend ?? 0),\n hint: undefined,\n tone: 'accent' as const,\n },\n ...(budgetKpi.kind === 'capped' && budgetKpi.max !== null && budgetKpi.remaining !== null\n ? [\n {\n label: 'Budget left',\n value: budgetKpi.remaining > 0 ? fmtUsd(budgetKpi.remaining) : 'Over cap',\n hint: `${fmtUsd(budgetKpi.spend)} of ${fmtUsd(budgetKpi.max)} \u00B7 ${budgetKpi.resetLabel ?? ''}`,\n tone: (budgetKpi.pct !== null && budgetKpi.pct >= 100 ? 'danger' : 'accent') as Tone,\n },\n ]\n : []),\n {\n label: 'Requests',\n value: fmtInt(totalRequests),\n hint: `${fmtInt(usage?.failed_requests ?? 0)} failed`,\n tone: 'info' as const,\n },\n {\n label: 'Success rate',\n value: totalRequests > 0 ? fmtPct(overallSuccessRate) : '\u2014',\n hint: totalRequests > 0 ? `${fmtInt(usage?.successful_requests ?? 0)} succeeded` : undefined,\n tone: successTone,\n },\n {\n label: 'Tokens',\n value: fmtCompact(usage?.total_tokens ?? 0),\n hint: `${fmtCompact(usage?.prompt_tokens ?? 0)} in \u00B7 ${fmtCompact(usage?.completion_tokens ?? 0)} out`,\n tone: 'success' as const,\n },\n ];\n\n const renderKeyRows = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={7} sx={{ py: 3 }}>\n <Skeleton variant=\"rounded\" height={80} />\n </TableCell>\n </TableRow>\n );\n }\n if (keyRows.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={7}><EmptyState message=\"No key activity in this period\" /></TableCell>\n </TableRow>\n );\n }\n return [...keyRows]\n .sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests)\n .map(r => (\n <TableRow key={r.keyHash}>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>{r.keyAlias}</Typography>\n {r.teamId ? (\n <Typography variant=\"caption\" color=\"text.secondary\">team: {r.teamId}</Typography>\n ) : null}\n </TableCell>\n <TableCell>\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {r.models.slice(0, 3).map(m => (\n <TagChip key={m} label={m} title={m} />\n ))}\n {r.models.length > 3 && <TagChip label={`+${r.models.length - 3}`} mono={false} />}\n </Box>\n </TableCell>\n <TableCell align=\"right\">{fmtUsd(r.spend)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.apiRequests)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.totalTokens)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.failedRequests)}</TableCell>\n <TableCell>\n <SuccessRateCell rate={r.successRate} requests={r.apiRequests} />\n </TableCell>\n </TableRow>\n ));\n };\n\n const renderModelRows = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={8} sx={{ py: 3 }}>\n <Skeleton variant=\"rounded\" height={80} />\n </TableCell>\n </TableRow>\n );\n }\n if (modelRows.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={8}><EmptyState message=\"No model activity in this period\" /></TableCell>\n </TableRow>\n );\n }\n return [...modelRows]\n .sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens)\n .map(r => (\n <TableRow key={r.model}>\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={1}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: chartColor(r.model), flexShrink: 0 }} />\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>{r.model}</Typography>\n </Box>\n </TableCell>\n <TableCell align=\"right\">{fmtUsd(r.spend)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.apiRequests)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.successfulRequests)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.failedRequests)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.promptTokens)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.completionTokens)}</TableCell>\n <TableCell>\n <SuccessRateCell rate={r.successRate} requests={r.apiRequests} />\n </TableCell>\n </TableRow>\n ));\n };\n\n const periodSelect = (\n <TextField\n select\n size=\"small\"\n label=\"Period\"\n value={currentPreset}\n onChange={e => handlePresetChange(e.target.value as DatePreset)}\n sx={{ minWidth: 160 }}\n >\n {(Object.keys(PRESET_LABELS) as DatePreset[]).map(p => (\n <MenuItem key={p} value={p}>{PRESET_LABELS[p]}</MenuItem>\n ))}\n </TextField>\n );\n\n if (usageError) {\n return (\n <SectionCard\n title=\"Usage Analytics\"\n subtitle={`${PRESET_LABELS[currentPreset]} \u00B7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`}\n actions={periodSelect}\n >\n <Alert severity=\"error\">\n Failed to load usage data: {(usageError as any).message || 'Unknown error'}\n {onRetryUsage && (\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={onRetryUsage}>Retry</Button>\n </Box>\n )}\n </Alert>\n </SectionCard>\n );\n }\n\n return (\n <SectionCard\n title=\"Usage Analytics\"\n subtitle={`${PRESET_LABELS[currentPreset]} \u00B7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`}\n actions={periodSelect}\n >\n <MetricStrip metrics={metrics} />\n\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n flexWrap: 'wrap',\n mt: 2.5,\n mb: 2,\n }}\n >\n <SegmentedControl<TabKey>\n value={tab}\n onChange={setTab}\n options={[\n { value: 'costs', label: 'Costs' },\n { value: 'models', label: 'Model Activity' },\n { value: 'keys', label: 'Key Activity' },\n ]}\n />\n {tab === 'models' && (\n <TextField\n select\n size=\"small\"\n label=\"Model\"\n value={selectedModel}\n onChange={e => setSelectedModel(e.target.value)}\n sx={{ minWidth: 220 }}\n >\n <MenuItem value=\"all\">All models</MenuItem>\n {models\n .filter(m => modelsInPeriod.includes(m.model_name))\n .map(m => (\n <MenuItem key={m.model_name} value={m.model_name}>{m.model_name}</MenuItem>\n ))}\n </TextField>\n )}\n </Box>\n\n {/* \u2550\u2550 COSTS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'costs' && (\n <Grid container spacing={2}>\n {/* Daily spend by model \u2014 the headline chart, given full width so the\n stack and its colour key stay legible with up to seven series. */}\n <Grid item xs={12}>\n <ChartCard title=\"Daily spend by model\" height={260}>\n <ChartOrFallback loading={loading} empty={modelSpendByDate.length === 0} height={260}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={modelSpendByDate} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtUsdCompact} width={56} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={fmtUsd} hideZero />}\n />\n {topSpendModels.map(m => (\n <Area\n key={m}\n type=\"monotone\"\n dataKey={m}\n stackId=\"spend\"\n stroke={chartColor(m)}\n strokeWidth={1.5}\n fill={chartColor(m)}\n fillOpacity={0.28}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n {!loading && topSpendModels.length > 0 && (\n <SeriesLegend series={topSpendModels.map(m => ({ name: m, color: chartColor(m) }))} />\n )}\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily token usage\">\n <ChartOrFallback loading={loading} empty={dailyData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtCompact} width={48} {...chart.axis} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} />} />\n <Legend {...chart.legend} />\n <Area type=\"monotone\" dataKey=\"promptTokens\" name=\"Input\" stackId=\"tok\" stroke={SERIES.input} strokeWidth={1.5} fill={SERIES.input} fillOpacity={0.25} />\n <Area type=\"monotone\" dataKey=\"completionTokens\" name=\"Output\" stackId=\"tok\" stroke={SERIES.output} strokeWidth={1.5} fill={SERIES.output} fillOpacity={0.25} />\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily requests\">\n <ChartOrFallback loading={loading} empty={dailyData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }} barCategoryGap=\"30%\">\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtCompact} width={48} {...chart.axis} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} />} />\n <Legend {...chart.legend} />\n <Bar dataKey=\"successfulRequests\" name=\"Successful\" fill={SERIES.success} stackId=\"r\" />\n <Bar dataKey=\"failedRequests\" name=\"Failed\" fill={SERIES.failure} stackId=\"r\" radius={[3, 3, 0, 0]} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily success rate\">\n <ChartOrFallback loading={loading} empty={successRateData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={successRateData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis domain={[0, 100]} tickFormatter={v => `${v}%`} width={44} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={(v: number) => `${v}%`} />}\n />\n <ReferenceLine y={100} stroke={SERIES.success} strokeDasharray=\"4 4\" strokeOpacity={0.5} />\n <Line\n type=\"monotone\"\n dataKey=\"successRate\"\n name=\"Success rate\"\n stroke={SERIES.input}\n strokeWidth={2}\n dot={{ r: 2.5, strokeWidth: 0, fill: SERIES.input }}\n activeDot={{ r: 4 }}\n />\n </LineChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard\n title=\"Spend in period\"\n >\n <ChartOrFallback loading={loading} empty={cumulativeData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={cumulativeData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis\n tickFormatter={fmtUsdCompact}\n width={56}\n domain={cumulativeDomain}\n {...chart.axis}\n />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={fmtUsd} />}\n />\n {budgetKpi.max && budgetKpi.max > 0 && (\n <ReferenceLine\n y={budgetKpi.max}\n stroke={SERIES.budget}\n strokeDasharray=\"5 4\"\n label={{ value: `Budget ${fmtUsd(budgetKpi.max)}`, position: 'insideTopRight', fontSize: 10, fill: SERIES.budget }}\n />\n )}\n <Area\n type=\"monotone\"\n dataKey=\"cumulative\"\n name=\"Cumulative spend\"\n stroke={SERIES.spend}\n strokeWidth={2}\n fill={SERIES.spend}\n fillOpacity={0.18}\n />\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n </Grid>\n )}\n\n {/* \u2550\u2550 MODELS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'models' && (\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Spend by model\" height={Math.max(200, topModelSpendBars.length * 34)}>\n <ChartOrFallback\n loading={loading}\n empty={topModelSpendBars.length === 0}\n height={Math.max(200, topModelSpendBars.length * 34)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topModelSpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtUsdCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"model\" width={170} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtUsd} labelFormatter={l => l} />} />\n <Bar dataKey=\"spend\" name=\"Spend\" radius={[0, 3, 3, 0]} barSize={14}>\n {topModelSpendBars.map(r => (\n <Cell key={r.model} fill={chartColor(r.model)} />\n ))}\n </Bar>\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Tokens by model\" height={Math.max(200, topModelSpendBars.length * 34)}>\n <ChartOrFallback\n loading={loading}\n empty={modelRows.length === 0}\n height={Math.max(200, topModelSpendBars.length * 34)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topModelSpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"model\" width={170} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} labelFormatter={l => l} />} />\n <Legend {...chart.legend} />\n <Bar dataKey=\"promptTokens\" name=\"Input\" fill={SERIES.input} stackId=\"t\" barSize={14} />\n <Bar dataKey=\"completionTokens\" name=\"Output\" fill={SERIES.output} stackId=\"t\" barSize={14} radius={[0, 3, 3, 0]} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12}>\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 2 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>Model</TableCell>\n <TableCell align=\"right\">Spend</TableCell>\n <TableCell align=\"right\">Requests</TableCell>\n <TableCell align=\"right\">Success</TableCell>\n <TableCell align=\"right\">Failed</TableCell>\n <TableCell align=\"right\">Input</TableCell>\n <TableCell align=\"right\">Output</TableCell>\n <TableCell sx={{ width: 160 }}>Success rate</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderModelRows()}\n </TableBody>\n </Table>\n </TableContainer>\n </Grid>\n </Grid>\n )}\n\n {/* \u2550\u2550 KEYS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'keys' && (\n <Grid container spacing={2}>\n {(loading || topKeySpendBars.length > 0) && (\n <Grid item xs={12}>\n <ChartCard title=\"Spend by key\" height={Math.max(160, topKeySpendBars.length * 32)}>\n <ChartOrFallback\n loading={loading}\n empty={topKeySpendBars.length === 0}\n height={Math.max(160, topKeySpendBars.length * 32)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topKeySpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtUsdCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"keyAlias\" width={160} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtUsd} labelFormatter={l => l} />} />\n <Bar dataKey=\"spend\" name=\"Spend\" fill={SERIES.input} radius={[0, 3, 3, 0]} barSize={14} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n )}\n\n <Grid item xs={12}>\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 2 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>Key</TableCell>\n <TableCell>Models</TableCell>\n <TableCell align=\"right\">Spend</TableCell>\n <TableCell align=\"right\">Requests</TableCell>\n <TableCell align=\"right\">Tokens</TableCell>\n <TableCell align=\"right\">Failed</TableCell>\n <TableCell sx={{ width: 160 }}>Success rate</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderKeyRows()}\n </TableBody>\n </Table>\n </TableContainer>\n </Grid>\n </Grid>\n )}\n </SectionCard>\n );\n};\n", "/**\n * Widget state machine for loading, error, and ready states.\n *\n * Discriminated union that represents the overall state of a widget:\n * - 'loading': profile or usage data is being fetched\n * - 'unprovisioned': user has no LiteLLM account (provisioning error)\n * - 'error': a data fetch failed (non-provisioning error)\n * - 'ready': data is available; usageUnavailable indicates failed usage fetch\n */\n\nimport { ApiError } from './api';\n\nexport const USAGE_UNAVAILABLE_MSG = 'Usage unavailable';\nexport const UNPROVISIONED_MSG = 'LiteLLM account not set up. Ask your admin.';\n\nconst UNPROVISIONED_BACKEND_MESSAGE = 'User not found in LiteLLM';\n\n/**\n * Detects whether an error represents a provisioning error.\n *\n * The backend answers 404 with body `{ error: 'User not found in LiteLLM' }`\n * when the user hasn't been provisioned. `ApiError` uses that `error` text as\n * its message, and `useLiteLLMProfile` surfaces failures as a plain message\n * string, so all three shapes are recognised: an ApiError (status + body), an\n * Error, or the bare message string.\n */\nexport function isUnprovisionedError(error: unknown): boolean {\n if (typeof error === 'string') {\n return error === UNPROVISIONED_BACKEND_MESSAGE;\n }\n if (error instanceof ApiError) {\n const body = error.body as { error?: unknown } | null | undefined;\n return (\n error.status === 404 &&\n !!body &&\n typeof body === 'object' &&\n body.error === UNPROVISIONED_BACKEND_MESSAGE\n );\n }\n if (error instanceof Error) {\n return error.message === UNPROVISIONED_BACKEND_MESSAGE;\n }\n return false;\n}\n\nexport type WidgetViewState =\n | { kind: 'loading' }\n | { kind: 'unprovisioned' }\n | { kind: 'error'; message: string }\n | { kind: 'ready'; usageUnavailable: boolean };\n\nexport interface WidgetStateParams {\n /** True if profile data is currently loading */\n loading: boolean;\n /** Error from profile fetch (getUserInfo). null if no error. */\n error: unknown;\n /** User info object; null if not loaded or unprovisioned */\n userInfo: unknown;\n /** Error from usage fetch. null if no error. */\n usageError: unknown;\n /** Number of keys; optional. Used to determine if the user has any keys. */\n hasKeys?: boolean;\n}\n\n/**\n * Determines the overall widget view state based on loading and error conditions.\n *\n * Priority:\n * 1. If loading, return 'loading'\n * 2. If profile error is unprovisioned, return 'unprovisioned'\n * 3. If profile error (any other), return 'error'\n * 4. Otherwise, return 'ready' with usageUnavailable flag based on usageError\n */\nexport function widgetViewState({\n loading,\n error,\n userInfo: _userInfo,\n usageError,\n hasKeys: _hasKeys,\n}: WidgetStateParams): WidgetViewState {\n if (loading) {\n return { kind: 'loading' };\n }\n\n if (error) {\n if (isUnprovisionedError(error)) {\n return { kind: 'unprovisioned' };\n }\n return { kind: 'error', message: USAGE_UNAVAILABLE_MSG };\n }\n\n return {\n kind: 'ready',\n usageUnavailable: usageError !== null && usageError !== undefined,\n };\n}\n", "/**\n * Shared budget-limit presentation used by both budget cards: the\n * `LiteLLMBudgetWidget` (full/compact meter list) and the condensed\n * `LiteLLMBudgetGauges` (expanded \"all limits\" view). Keeping the card in one\n * place means a limit reads identically wherever it is shown.\n */\nimport { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport type { Theme } from '@mui/material/styles';\nimport { Link } from '@backstage/core-components';\nimport { BudgetLimit, fmtBudgetDuration, budgetTone } from '../budget';\nimport { fmtUsd } from '../format';\nimport { Meter, Tone } from './ui';\n\n/** Semantic colour for a tone, from the host theme. */\nexport function levelToneColor(tone: Tone | undefined, theme: Theme): string {\n switch (tone) {\n case 'success': return theme.palette.success.main;\n case 'warning': return theme.palette.warning.main;\n case 'danger': return theme.palette.error.main;\n case 'info': return theme.palette.info.main;\n default: return theme.palette.primary.main;\n }\n}\n\n/** Spend-vs-cap meter card for a single limit. */\nexport const LimitCard: FC<{ limit: BudgetLimit }> = ({ limit }) => {\n const tone = budgetTone(limit.pct);\n const pct = Math.round(limit.pct);\n const closeTo = limit.softLimit !== undefined && limit.spend >= limit.softLimit;\n return (\n <Paper variant=\"outlined\" sx={{ px: 1.5, py: 1.25, borderRadius: 1.5 }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 1.5 }}>\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n title={limit.sublabel ? `${limit.label} \u00B7 ${limit.sublabel}` : limit.label}\n >\n {limit.label}\n </Typography>\n {limit.sublabel && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n fontSize: 10.5,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n display: 'block',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {limit.sublabel}\n </Typography>\n )}\n </Box>\n {limit.hidden ? (\n <Typography variant=\"body2\" sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>\n {pct}% used\n </Typography>\n ) : (\n <Typography variant=\"body2\" sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>\n {fmtUsd(limit.spend)}\n <Box component=\"span\" color=\"text.secondary\" sx={{ fontWeight: 400 }}>\n {' / '}\n {fmtUsd(limit.budget)}\n </Box>\n </Typography>\n )}\n </Box>\n <Box sx={{ mt: 1 }}>\n <Meter value={limit.pct} tone={tone} height={6} />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: 1,\n mt: 0.75,\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {limit.hidden ? (\n <>Hidden by admin</>\n ) : (\n <>{pct}% of budget{closeTo && ` \u00B7 soft-limit warning`}</>\n )}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {fmtBudgetDuration(limit.budgetDuration)\n ? `resets ${fmtBudgetDuration(limit.budgetDuration)}`\n : 'never resets'}\n </Typography>\n </Box>\n </Paper>\n );\n};\n\n/** A LimitCard prefixed with a small KEY / USER / TEAM tag. */\nexport const TaggedLimit: FC<{ limit: BudgetLimit }> = ({ limit }) => {\n const theme = useTheme();\n const tone = budgetTone(limit.pct);\n return (\n <Box>\n <Typography\n sx={{\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: tone === 'accent' ? theme.palette.text.secondary : levelToneColor(tone, theme),\n mb: 0.5,\n }}\n >\n {limit.kind}\n </Typography>\n <LimitCard limit={limit} />\n </Box>\n );\n};\n\n/** A key-budget note under a limit list \u2014 plain text when no href is given. */\nexport const MoreKeysNote: FC<{ count: number; href?: string; label?: string }> = ({\n count,\n href,\n label,\n}) => {\n const text = label ?? `+${count} more budgeted key${count > 1 ? 's' : ''} further from the cap`;\n if (!href) {\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {text}\n </Typography>\n );\n }\n return (\n <Link to={href} variant=\"caption\">\n {text} \u2192\n </Link>\n );\n};\n\n/**\n * Flat list of concrete limits across every level, as tagged meter cards.\n * Used by the condensed gauges card's expanded view; the full widget renders\n * its own grouped-by-level rail instead.\n */\nexport const BudgetLimitList: FC<{\n limits: BudgetLimit[];\n /** Keys beyond the supplied limits \u2014 rendered as a trailing note. */\n hiddenKeyCount?: number;\n keysHref?: string;\n}> = ({ limits, hiddenKeyCount = 0, keysHref }) => (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25 }}>\n {limits.map(limit => (\n <TaggedLimit key={`${limit.kind}:${limit.sublabel ?? limit.label}`} limit={limit} />\n ))}\n {hiddenKeyCount > 0 && <MoreKeysNote count={hiddenKeyCount} href={keysHref} />}\n </Box>\n);\n\n/** Inset panel used to hold a nested list of limits inside a card. */\nexport const LimitListPanel: FC<{ children: ReactNode }> = ({ children }) => (\n <Box\n sx={theme => ({\n px: 1.5,\n py: 1.5,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.03 : 0.02),\n })}\n >\n {children}\n </Box>\n);\n", "/**\n * Build a link to the keys tab on the LiteLLM page.\n * @param baseUrl - The base URL of the LiteLLM module (result from useRouteRef)\n * @returns The full URL to the keys tab, or undefined if baseUrl is not available\n */\nexport function buildKeysLink(baseUrl: string | undefined): string | undefined {\n if (baseUrl === undefined) {\n return undefined;\n }\n return `${baseUrl}?tab=keys`;\n}\n", "/**\n * LiteLLM budget-policy widget. Renders the enforcement hierarchy as a\n * numbered flow \u2014 key \u2192 personal \u2192 team \u2192 global \u2014 and, against each level\n * the signed-in user actually has a limit on, a live meter showing how close\n * they are to the cap. Intended for at-a-glance use on a homepage card next\n * to `LiteLLMHomeWidget`, but works anywhere.\n *\n * The policy text mirrors the LiteLLM proxy behaviour:\n * - every request is checked against stacked limits, in order;\n * - a key bound to a team is capped by the team budgets, not the owner's\n * personal budget;\n * - a limit with a `budget_duration` resets its spend when the window\n * closes; without one it never resets.\n *\n * Two knobs shrink it for use as a secondary column:\n * - `compact` drops the numbered rail and the policy footnote, showing\n * only the limits the user actually has as a tight tagged meter list;\n * - `collapsible` folds the body under a one-line summary header.\n * `action` renders a host-supplied node (e.g. a button) pinned to the card\n * bottom, always visible.\n *\n * When user data is passed via props (userInfo, teams, keys), they are used\n * directly without refetching. Otherwise, the hook fetches them.\n */\nimport { FC, ReactNode, useId, useMemo, useState } from 'react';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport { ExpandMore } from '@mui/icons-material';\nimport { alpha } from '@mui/material/styles';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { StatusPill, Tone } from './ui';\nimport { widgetViewState, UNPROVISIONED_MSG } from '../widgetState';\nimport {\n levelToneColor,\n LimitCard,\n MoreKeysNote,\n TaggedLimit,\n} from './BudgetLimitList';\nimport {\n buildBudgetSummary,\n budgetHeadline,\n BudgetLimit,\n BudgetSummary,\n budgetTone,\n} from '../budget';\nimport { rootRouteRef } from '../routes';\nimport { buildKeysLink } from '../routeHelpers';\n\nexport interface LiteLLMBudgetWidgetProps {\n /** Optional title override. Defaults to 'Budget Policy'. */\n title?: string;\n /** Max key budgets to show, closest to the cap first. Defaults to 3. */\n maxKeys?: number;\n /**\n * Drop the numbered key\u2192personal\u2192team\u2192global rail and the policy\n * footnote; show only the limits the user actually has. Defaults to false.\n */\n compact?: boolean;\n /** Fold the body under a clickable one-line summary header. Defaults to false. */\n collapsible?: boolean;\n /** Initial expanded state when `collapsible`. Defaults to true. */\n defaultExpanded?: boolean;\n /**\n * Node rendered at the card bottom, below a divider and outside the\n * collapsible region so it stays visible when collapsed \u2014 e.g. a\n * \"create key\" button.\n */\n action?: ReactNode;\n /**\n * Optional preloaded data to use instead of fetching via the hook.\n * When provided, the component uses these values directly without refetching.\n */\n userInfo?: UserInfo | null;\n teams?: TeamInfo[];\n keys?: VirtualKey[];\n}\n\ninterface LevelFrameProps {\n rank: number;\n name: string;\n tagline: string;\n note?: string;\n tone?: Tone;\n isLast?: boolean;\n children: ReactNode;\n}\n\nconst LevelFrame: FC<LevelFrameProps> = ({\n rank,\n name,\n tagline,\n note,\n tone,\n isLast,\n children,\n}) => (\n <Box sx={{ display: 'flex', gap: 1.5 }}>\n {/* Left rail: rank badge + connector to the next level. */}\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 26, flexShrink: 0 }}>\n <Box\n sx={theme => ({\n width: 26,\n height: 26,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(levelToneColor(tone, theme), 0.14),\n color: levelToneColor(tone, theme),\n fontSize: 12,\n fontWeight: 700,\n flexShrink: 0,\n })}\n >\n {rank}\n </Box>\n <Box\n sx={theme => ({\n flex: 1,\n width: 2,\n minHeight: 14,\n bgcolor: isLast ? 'transparent' : alpha(theme.palette.text.primary, 0.12),\n })}\n />\n </Box>\n\n <Box sx={{ flex: 1, minWidth: 0, pb: isLast ? 0 : 2 }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 1, flexWrap: 'wrap', mb: 0.75 }}>\n <Typography\n sx={theme => ({\n fontSize: 12.5,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: levelToneColor(tone, theme),\n })}\n >\n {name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontSize: 11.5 }}>\n {tagline}\n </Typography>\n {note && <StatusPill label={note} tone=\"neutral\" dot={false} sx={{ ml: 'auto' }} />}\n </Box>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>{children}</Box>\n </Box>\n </Box>\n);\n\nconst EmptyLimitCard: FC<{ children: ReactNode }> = ({ children }) => (\n <Paper\n variant=\"outlined\"\n sx={theme => ({\n px: 1.5,\n py: 1.25,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.03 : 0.015),\n })}\n >\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontSize: 13 }}>\n {children}\n </Typography>\n </Paper>\n);\n\n/** How each enforcement level reads in the collapsed summary line. */\nconst CLOSEST_LEVEL_LABEL: Record<BudgetLimit['kind'], string> = {\n key: 'key',\n user: 'personal',\n team: 'team',\n};\n\n\n/**\n * The one thing that's easy to get wrong about LiteLLM budgets: the order\n * caps are checked in. Short by design.\n */\nconst HierarchyNote: FC<{ withReset?: boolean }> = ({ withReset }) => (\n <Box\n sx={theme => ({\n px: 1.5,\n py: 1.25,\n borderRadius: 1.5,\n border: '1px dashed',\n borderColor: alpha(theme.palette.text.primary, 0.18),\n })}\n >\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\">\n <b>Order:</b> key \u2192 personal \u2192 team \u2192 global. The first cap you reach\n blocks the request; a key that belongs to a team uses the team's cap,\n not your personal one.\n {withReset &&\n ' A cap with a reset window drops to $0 when the window closes; without one it never resets.'}\n </Typography>\n </Box>\n);\n\n/** Full body: the numbered key\u2192personal\u2192team\u2192global rail plus the policy footnote. */\nconst FullBody: FC<{ summary: BudgetSummary; keysLink?: string }> = ({ summary, keysLink }) => {\n const hasBudgetedKeys = summary.keys.length + summary.hiddenBudgetedKeys > 0;\n return (\n <>\n <LevelFrame\n rank={1}\n name=\"Key\"\n tagline=\"per-key cap \u00B7 highest priority\"\n note={hasBudgetedKeys ? undefined : 'no key budgets set'}\n >\n {!hasBudgetedKeys && (\n <EmptyLimitCard>No key has a budget, so no key-level cap applies.</EmptyLimitCard>\n )}\n {summary.keys.map(k => (\n <LimitCard key={k.sublabel ?? k.label} limit={k} />\n ))}\n {summary.hiddenBudgetedKeys > 0 && keysLink && (\n <MoreKeysNote count={summary.hiddenBudgetedKeys} href={keysLink} />\n )}\n </LevelFrame>\n\n <LevelFrame\n rank={2}\n name=\"User\"\n tagline=\"cap on everything you spend with your own keys\"\n note=\"skipped for team-bound keys\"\n >\n {summary.user ? (\n <LimitCard limit={summary.user} />\n ) : (\n <EmptyLimitCard>No personal budget is set on your account.</EmptyLimitCard>\n )}\n </LevelFrame>\n\n <LevelFrame rank={3} name=\"Team\" tagline=\"shared cap for all keys in a team (if any)\">\n {summary.teams.length > 0\n ? summary.teams.map(t => (\n <LimitCard key={t.sublabel ?? t.label} limit={t} />\n ))\n : (\n <EmptyLimitCard>No team you belong to has a budget.</EmptyLimitCard>\n )}\n </LevelFrame>\n\n <LevelFrame rank={4} name=\"Global\" tagline=\"proxy-wide cap set by your admin\" isLast>\n <EmptyLimitCard>\n Configured by your admin in the proxy config \u2014 it isn't visible from this page. When\n set, it limits spend across every request on the proxy.\n </EmptyLimitCard>\n </LevelFrame>\n\n <Box sx={{ mt: 2 }}>\n <HierarchyNote withReset />\n </Box>\n </>\n );\n};\n\n/** Compact body: only the limits the user actually has, as a tagged meter list. */\nconst CompactBody: FC<{ summary: BudgetSummary; keysLink?: string }> = ({ summary, keysLink }) => {\n const { count } = budgetHeadline(summary);\n if (count === 0) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontSize: 13 }}>\n No budget limits apply to you right now.\n </Typography>\n );\n }\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25 }}>\n <HierarchyNote />\n {summary.keys.map(k => (\n <TaggedLimit key={k.sublabel ?? k.label} limit={k} />\n ))}\n {summary.hiddenBudgetedKeys > 0 && keysLink && (\n <MoreKeysNote count={summary.hiddenBudgetedKeys} href={keysLink} />\n )}\n {summary.user && <TaggedLimit limit={summary.user} />}\n {summary.teams.map(t => (\n <TaggedLimit key={t.sublabel ?? t.label} limit={t} />\n ))}\n </Box>\n );\n};\n\nexport const LiteLLMBudgetWidget: FC<LiteLLMBudgetWidgetProps> = ({\n title = 'Budget Policy',\n maxKeys = 3,\n compact = false,\n collapsible = false,\n defaultExpanded = true,\n action,\n userInfo: propUserInfo,\n teams: propTeams,\n keys: propKeys,\n}) => {\n const { userInfo: hookUserInfo, teams: hookTeams, keys: hookKeys, loading, error } = useLiteLLMProfile();\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const keysLink = buildKeysLink(moduleRouteRef?.());\n const [expanded, setExpanded] = useState(defaultExpanded);\n const collapsibleContentId = useId();\n\n // Use provided props if available, otherwise use hook data\n const user = propUserInfo !== undefined ? propUserInfo : hookUserInfo;\n const teams = propTeams !== undefined ? propTeams : hookTeams;\n const keys = propKeys !== undefined ? propKeys : hookKeys;\n\n const viewState = useMemo(\n () => widgetViewState({\n loading,\n error,\n userInfo: user,\n usageError: null, // budget widget doesn't fetch usage\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [loading, error, user, keys],\n );\n\n const summary = useMemo(\n () => buildBudgetSummary(user, teams, keys, maxKeys),\n [user, teams, keys, maxKeys],\n );\n const headline = useMemo(() => budgetHeadline(summary), [summary]);\n\n const limitsWord = `${headline.count} limit${headline.count === 1 ? '' : 's'}`;\n const closestWord =\n headline.closest === null\n ? ''\n : ` \u00B7 closest: ${CLOSEST_LEVEL_LABEL[headline.closest.kind]} ${Math.round(\n headline.closest.pct,\n )}%`;\n const summaryText =\n headline.count === 0 ? 'no limits apply' : `${limitsWord}${closestWord}`;\n\n const body = (\n <>\n {viewState.kind === 'loading' && (\n <Box sx={{ minHeight: 140 }}>\n {[0, 1, 2, 3].map(i => (\n <Box key={i} sx={{ display: 'flex', gap: 1, mb: 1 }}>\n <Skeleton variant=\"rectangular\" width={24} height={24} sx={{ flexShrink: 0, mt: 0.5 }} />\n <Box sx={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={18} sx={{ mb: 0.5 }} />\n <Skeleton variant=\"rectangular\" width=\"100%\" height={8} sx={{ mb: 0.5 }} />\n <Skeleton variant=\"text\" width=\"40%\" height={12} />\n </Box>\n </Box>\n ))}\n </Box>\n )}\n\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {viewState.message}\n </Typography>\n )}\n\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {viewState.kind === 'ready' &&\n (compact ? <CompactBody summary={summary} keysLink={keysLink} /> : <FullBody summary={summary} keysLink={keysLink} />)}\n </>\n );\n\n return (\n <Paper sx={{ p: 2 }}>\n {collapsible ? (\n <Box\n onClick={() => setExpanded(e => !e)}\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n cursor: 'pointer',\n userSelect: 'none',\n mb: expanded ? 1.5 : 0,\n }}\n >\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"h6\" lineHeight={1.2}>{title}</Typography>\n {viewState.kind === 'ready' && (\n <Box sx={{ mt: 0.5 }}>\n <StatusPill\n label={summaryText}\n tone={budgetTone(headline.closest?.pct ?? 0)}\n />\n </Box>\n )}\n </Box>\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Collapse budget policy' : 'Expand budget policy'}\n aria-expanded={expanded}\n aria-controls={collapsibleContentId}\n onClick={e => {\n e.stopPropagation();\n setExpanded(x => !x);\n }}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: expanded ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <ExpandMore />\n </IconButton>\n </Box>\n ) : (\n <Box sx={{ mb: 1.5 }}>\n <Typography variant=\"h6\" lineHeight={1.2}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n How LiteLLM caps spend \u2014 and where you stand right now\n </Typography>\n </Box>\n )}\n\n {collapsible ? (\n <Collapse in={expanded} unmountOnExit>\n <Box id={collapsibleContentId}>\n {body}\n </Box>\n </Collapse>\n ) : (\n body\n )}\n\n {action && (\n <Box\n sx={theme => ({\n mt: 2,\n pt: 2,\n borderTop: `1px solid ${theme.palette.divider}`,\n })}\n >\n {action}\n </Box>\n )}\n </Paper>\n );\n};\n", "import { FC, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Divider from '@mui/material/Divider';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableContainer from '@mui/material/TableContainer';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport { alpha } from '@mui/material/styles';\nimport MuiTooltip from '@mui/material/Tooltip';\nimport { ExpandMore, Group, Add, LockOutlined, GroupAddOutlined } from '@mui/icons-material';\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n} from 'recharts';\nimport { TeamInfo, UsageMetrics } from '../types';\nimport {\n ChartTooltip,\n EmptyState,\n Meter,\n SectionCard,\n Stat,\n StatusPill,\n TagChip,\n Tone,\n dataTableSx,\n fmtDateShort,\n fmtUsdCompact,\n useChartTheme,\n SERIES,\n} from './ui';\n\nfunction budgetTone(isOver: boolean, isNear: boolean): Tone {\n if (isOver) return 'danger';\n if (isNear) return 'warning';\n return 'accent';\n}\n\nconst fmtUsd2 = (n: number) => `$${(n ?? 0).toFixed(2)}`;\n\nfunction visibleBudgetPct(spend: number, budget: number): number {\n if (budget <= 0) return 0;\n return Math.min((spend / budget) * 100, 100);\n}\n\nfunction budgetStatValue(hidden: boolean, budget: number): string {\n if (hidden) return 'Hidden';\n if (budget > 0) return fmtUsd2(budget);\n return 'Unlimited';\n}\n\ninterface TeamCardProps {\n team: TeamInfo;\n usage: UsageMetrics | null;\n usageLoading: boolean;\n canManage?: boolean;\n onEditTeam?: (team: TeamInfo) => void;\n /** Members-only management (team-role path); hidden when `canManage`. */\n canManageMembers?: boolean;\n onManageMembers?: (team: TeamInfo) => void;\n onExpand?: (team: TeamInfo) => void;\n}\n\nconst TeamCard: FC<TeamCardProps> = ({ team, usage, usageLoading, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand }) => {\n const [expanded, setExpanded] = useState(false);\n const chart = useChartTheme();\n\n const handleExpandChange = (newExpanded: boolean) => {\n setExpanded(newExpanded);\n if (newExpanded && onExpand) {\n onExpand(team);\n }\n };\n\n // When the backend redacts dollar amounts (budget hiding), only the\n // consumption level survives: pct + status + reset window. Spend charts\n // and `$` figures must stay hidden \u2014 usage spend is zeroed server-side\n // for the same reason.\n const hidden = team.budget_hidden === true;\n const budget = hidden ? 0 : team.max_budget ?? 0;\n const spend = hidden ? 0 : team.spend ?? 0;\n const budgetPct = hidden\n ? Math.min(100, Math.max(0, team.budget_pct ?? 0))\n : visibleBudgetPct(spend, budget);\n const isOver = hidden\n ? team.budget_status === 'over'\n : budget > 0 && spend >= budget;\n const isNear = hidden\n ? team.budget_status === 'near'\n : budget > 0 && spend >= budget * 0.8 && !isOver;\n\n const dailyData = usage?.daily_usage?.map(d => ({ date: d.date, spend: d.spend })) ?? [];\n\n const renderDailySpendSection = () => {\n // Spend is redacted server-side when the budget is hidden \u2014 a flat $0\n // chart would mislead, so the section is omitted entirely.\n if (hidden) return null;\n if (usageLoading) {\n return (\n <Box display=\"flex\" justifyContent=\"center\" py={3}>\n <CircularProgress size={22} />\n </Box>\n );\n }\n if (dailyData.length === 0) return null;\n return (\n <Box mb={2.5}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 11, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', mb: 1 }}\n >\n Daily spend\n </Typography>\n <Box height={150}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtUsdCompact} width={52} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={v => `$${v.toFixed(4)}`} />}\n />\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n strokeWidth={2}\n fill={SERIES.spend}\n fillOpacity={0.18}\n />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n );\n };\n\n const sectionLabel = (label: string) => (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 11, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', mb: 1 }}\n >\n {label}\n </Typography>\n );\n\n return (\n <Paper variant=\"outlined\" sx={{ borderRadius: 2, p: 2.5 }}>\n <Box display=\"flex\" alignItems=\"center\" gap={1.5}>\n <Box\n sx={theme => ({\n width: 36,\n height: 36,\n borderRadius: 1.5,\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette.primary.main, 0.1),\n color: theme.palette.primary.main,\n })}\n >\n <Group fontSize=\"small\" />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Typography variant=\"subtitle1\" sx={{ fontWeight: 600, lineHeight: 1.3 }}>\n {team.team_alias || 'Untitled team'}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {team.team_id}\n </Typography>\n </Box>\n {isOver && <StatusPill label=\"Over budget\" tone=\"danger\" />}\n {isNear && <StatusPill label=\"Near limit\" tone=\"warning\" />}\n {canManage && onEditTeam && (\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => onEditTeam(team)}\n sx={{ textTransform: 'none' }}\n >\n Edit\n </Button>\n )}\n {canManageMembers && onManageMembers && !canManage && (\n <MuiTooltip title=\"Add or remove members of this team\">\n <Button\n size=\"small\"\n variant=\"text\"\n startIcon={<GroupAddOutlined />}\n onClick={() => onManageMembers(team)}\n sx={{ textTransform: 'none' }}\n >\n Manage members\n </Button>\n </MuiTooltip>\n )}\n <IconButton\n size=\"small\"\n onClick={() => handleExpandChange(!expanded)}\n aria-label={expanded ? 'Hide team details' : 'Show team details'}\n aria-expanded={expanded}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: expanded ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <ExpandMore />\n </IconButton>\n </Box>\n\n {/* Fixed-track grid, capped in width, so the six stats line up across\n every team card instead of stretching to fill the row. */}\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: 'repeat(3, minmax(0, 1fr))', sm: 'repeat(6, minmax(0, 1fr))' },\n gap: 2,\n mt: 2.5,\n maxWidth: 640,\n }}\n >\n <Stat label=\"Members\" value={team.members_with_roles?.length ?? '\u2014'} />\n <Stat label=\"Models\" value={team.models?.length ? team.models.length : 'All'} />\n <Stat label=\"Budget\" value={budgetStatValue(hidden, budget)} />\n <Stat label=\"Spend\" value={hidden ? '\u2014' : fmtUsd2(spend)} />\n <Stat label=\"TPM\" value={team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : '\u2014'} />\n <Stat label=\"RPM\" value={team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : '\u2014'} />\n </Box>\n\n {hidden && (\n <Box mt={2} maxWidth={640}>\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"baseline\" mb={0.75}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {budgetPct.toFixed(0)}% used\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Hidden by admin\n </Typography>\n </Box>\n <Meter value={budgetPct} tone={budgetTone(isOver, isNear)} height={5} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.75 }}>\n Team budget is hidden \u2014 showing usage level only\n {team.budget_duration ? ` \u00B7 resets every ${team.budget_duration}` : ''}.\n </Typography>\n </Box>\n )}\n\n {!hidden && budget > 0 && (\n <Box mt={2} maxWidth={640}>\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"baseline\" mb={0.75}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtUsd2(spend)} of {fmtUsd2(budget)}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {budgetPct.toFixed(0)}%\n </Typography>\n </Box>\n <Meter value={budgetPct} tone={budgetTone(isOver, isNear)} height={5} />\n </Box>\n )}\n\n <Collapse in={expanded} unmountOnExit>\n <Divider sx={{ my: 2.5 }} />\n\n <Box mb={2.5}>\n {sectionLabel('Models')}\n {team.models?.length ? (\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {team.models.map(m => (\n <TagChip key={m} label={m} title={m} />\n ))}\n </Box>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">All models allowed</Typography>\n )}\n </Box>\n\n {renderDailySpendSection()}\n\n <Box>\n {sectionLabel('Members')}\n {team.members_with_roles?.length ? (\n <TableContainer\n component={Paper}\n variant=\"outlined\"\n sx={{ borderRadius: 1.5 }}\n >\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>User</TableCell>\n <TableCell align=\"right\">Role</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {team.members_with_roles.map(m => (\n <TableRow key={m.user_id}>\n <TableCell>\n {m.user_email ? (\n <>\n <Typography variant=\"body2\">{m.user_email}</Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {m.user_id}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"body2\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {m.user_id}\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <StatusPill\n label={m.role}\n tone={m.role === 'admin' ? 'accent' : 'neutral'}\n dot={false}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">No members assigned.</Typography>\n )}\n </Box>\n </Collapse>\n </Paper>\n );\n};\n\ninterface TeamUsageProps {\n teams: TeamInfo[];\n loading: boolean;\n getTeamUsage: (teamId: string) => UsageMetrics | null;\n getTeamUsageLoading: (teamId: string) => boolean;\n canManage?: boolean;\n onEditTeam?: (team: TeamInfo) => void;\n /** When true (with `onCreateTeam`), a \"Create Team\" action renders in the section header. */\n canCreate?: boolean;\n onCreateTeam?: () => void;\n /** Called when a team card is expanded to trigger data loading. */\n onTeamExpand?: (team: TeamInfo) => void;\n /** Per-team: whether the caller may manage this team's members only. */\n canManageMembers?: (team: TeamInfo) => boolean;\n onManageMembers?: (team: TeamInfo) => void;\n /** Teams are synced from an identity provider: show a badge, no write controls. */\n readOnly?: boolean;\n}\n\nexport const TeamUsage: FC<TeamUsageProps> = ({\n teams,\n loading,\n getTeamUsage,\n getTeamUsageLoading,\n canManage,\n onEditTeam,\n canCreate,\n onCreateTeam,\n onTeamExpand,\n canManageMembers,\n onManageMembers,\n readOnly,\n}) => {\n const readOnlyBadge = (\n <MuiTooltip title=\"Teams and memberships are managed in your identity provider. Changes made here would be overwritten, so editing is disabled.\">\n <Box\n component=\"span\"\n sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.5, color: 'text.secondary', fontSize: 12.5 }}\n >\n <LockOutlined sx={{ fontSize: 15 }} />\n Synced from identity provider\n </Box>\n </MuiTooltip>\n );\n const createButton =\n canCreate && onCreateTeam ? (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n startIcon={<Add />}\n onClick={onCreateTeam}\n >\n Create Team\n </Button>\n ) : undefined;\n const createAction = readOnly ? readOnlyBadge : createButton;\n\n if (loading) {\n return (\n <SectionCard title=\"Teams\" actions={createAction}>\n <Skeleton variant=\"rounded\" height={120} sx={{ mb: 2 }} />\n <Skeleton variant=\"rounded\" height={120} />\n </SectionCard>\n );\n }\n\n if (!teams.length) {\n return (\n <SectionCard title=\"Teams\" actions={createAction}>\n <EmptyState\n message=\"You're not a member of any LiteLLM team yet.\"\n hint=\"Your account is provisioned, so you can still generate personal keys and use models. Ask an admin to add you to a team if you need a shared budget.\"\n />\n </SectionCard>\n );\n }\n\n return (\n <SectionCard\n title=\"Teams\"\n subtitle={`${teams.length} team${teams.length === 1 ? '' : 's'}`}\n actions={createAction}\n >\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n {teams.map(team => (\n <TeamCard\n key={team.team_id}\n team={team}\n usage={getTeamUsage(team.team_id)}\n usageLoading={getTeamUsageLoading(team.team_id)}\n canManage={canManage}\n onEditTeam={onEditTeam}\n canManageMembers={canManageMembers?.(team)}\n onManageMembers={onManageMembers}\n onExpand={onTeamExpand}\n />\n ))}\n </Box>\n </SectionCard>\n );\n};\n", "import { FC, useCallback, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableSortLabel from '@mui/material/TableSortLabel';\nimport Typography from '@mui/material/Typography';\nimport MenuItem from '@mui/material/MenuItem';\nimport Select from '@mui/material/Select';\nimport FormControl from '@mui/material/FormControl';\nimport InputLabel from '@mui/material/InputLabel';\nimport TextField from '@mui/material/TextField';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport { Search } from '@mui/icons-material';\nimport ContentCopyIcon from '@mui/icons-material/ContentCopy';\nimport Tooltip from '@mui/material/Tooltip';\nimport Snackbar from '@mui/material/Snackbar';\nimport Alert from '@mui/material/Alert';\nimport { ModelInfo, TeamInfo } from '../types';\nimport { SectionCard, EmptyState, TagChip, dataTableSx, quietIconButtonSx } from './ui';\nimport { alpha, useTheme } from '@mui/material/styles';\n\ninterface ModelsTableProps {\n allModels: ModelInfo[];\n teams: TeamInfo[];\n loading: boolean;\n}\n\nconst ALL_PROXY_MODELS = 'all-proxy-models';\n\nfunction isModelAllowedByTeam(model: ModelInfo, teamModels?: string[]): boolean {\n if (!teamModels || teamModels.length === 0 || teamModels.includes(ALL_PROXY_MODELS)) return true;\n return teamModels.includes(model.model_name) ||\n !!model.access_groups?.some(group => teamModels.includes(group));\n}\n\nfunction fmtCostPerToken(cost?: number): string {\n if (cost === undefined || cost === null) return '\u2014';\n if (cost === 0) return '$0';\n if (cost < 0.000001) return `$${(cost * 1_000_000).toFixed(2)}/M`;\n if (cost < 0.001) return `$${(cost * 1000).toFixed(3)}/K`;\n return `$${cost.toFixed(4)}`;\n}\n\nfunction fmtTokens(n?: number): string {\n if (n === undefined || n === null) return '\u2014';\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;\n return String(n);\n}\n\nexport const ModelsTable: FC<ModelsTableProps> = ({ allModels, teams, loading }) => {\n const theme = useTheme();\n const [selectedTeamId, setSelectedTeamId] = useState<string>('');\n const [filterText, setFilterText] = useState<string>('');\n const [copiedSnackbar, setCopiedSnackbar] = useState(false);\n const [sortKey, setSortKey] = useState<'model_name' | 'mode' | 'input_cost_per_token' | 'output_cost_per_token' | 'max_input_tokens' | 'max_output_tokens'>('model_name');\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');\n\n const selectedTeam = useMemo(\n () => teams.find(t => t.team_id === selectedTeamId) ?? null,\n [teams, selectedTeamId],\n );\n\n const teamModels = useMemo(() => {\n if (!selectedTeam) return [];\n return allModels.filter(model => isModelAllowedByTeam(model, selectedTeam.models));\n }, [allModels, selectedTeam]);\n\n const filteredModels = useMemo(() => {\n const q = filterText.trim().toLowerCase();\n let models = teamModels;\n if (q) {\n models = teamModels.filter(model =>\n model.model_name.toLowerCase().includes(q) ||\n (model.access_groups || []).some(group => group.toLowerCase().includes(q)),\n );\n }\n return [...models].sort((a, b) => {\n let aVal: string | number | undefined;\n let bVal: string | number | undefined;\n switch (sortKey) {\n case 'model_name':\n aVal = a.model_name;\n bVal = b.model_name;\n break;\n case 'mode':\n aVal = a.mode;\n bVal = b.mode;\n break;\n case 'input_cost_per_token':\n aVal = a.input_cost_per_token ?? 0;\n bVal = b.input_cost_per_token ?? 0;\n break;\n case 'output_cost_per_token':\n aVal = a.output_cost_per_token ?? 0;\n bVal = b.output_cost_per_token ?? 0;\n break;\n case 'max_input_tokens':\n aVal = a.max_input_tokens ?? 0;\n bVal = b.max_input_tokens ?? 0;\n break;\n case 'max_output_tokens':\n aVal = a.max_output_tokens ?? 0;\n bVal = b.max_output_tokens ?? 0;\n break;\n default:\n return 0;\n }\n if (aVal === undefined || aVal === null) aVal = '';\n if (bVal === undefined || bVal === null) bVal = '';\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n return sortDirection === 'asc' ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);\n }\n return sortDirection === 'asc' ? (aVal as number) - (bVal as number) : (bVal as number) - (aVal as number);\n });\n }, [teamModels, filterText, sortKey, sortDirection]);\n\n const handleCopyModelId = useCallback((modelId: string) => {\n navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));\n }, []);\n\n const handleSort = useCallback((key: typeof sortKey) => {\n if (sortKey === key) {\n setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');\n } else {\n setSortKey(key);\n setSortDirection('asc');\n }\n }, [sortKey]);\n\n const modeColor = (mode: string): string => {\n switch (mode) {\n case 'chat': return theme.palette.info.main;\n case 'embedding': return theme.palette.success.main;\n case 'completion': return theme.palette.primary.main;\n case 'image': return theme.palette.warning.main;\n default: return theme.palette.info.main;\n }\n };\n\n return (\n <SectionCard\n title=\"Available Models\"\n subtitle={\n selectedTeam\n ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ''} model${filteredModels.length === 1 ? '' : 's'}`\n : 'Select a team to view its models'\n }\n >\n <Box sx={{ px: 2.5, pb: 2.5, pt: 1, display: 'flex', gap: 2, flexWrap: 'wrap' }}>\n <FormControl size=\"small\" sx={{ minWidth: 240, mb: 2 }}>\n <InputLabel id=\"team-select-label\">Team</InputLabel>\n <Select\n labelId=\"team-select-label\"\n value={selectedTeamId}\n label=\"Team\"\n onChange={e => setSelectedTeamId(e.target.value)}\n >\n {teams.map(t => (\n <MenuItem key={t.team_id} value={t.team_id}>\n {t.team_alias ?? t.team_id}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n <TextField\n label=\"Filter Models\"\n size=\"small\"\n value={filterText}\n onChange={e => setFilterText(e.target.value)}\n disabled={!selectedTeamId}\n sx={{ minWidth: 240, mb: 2 }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <Search fontSize=\"small\" />\n </InputAdornment>\n ),\n }}\n />\n </Box>\n\n {loading && (\n <EmptyState message=\"Loading models\u2026\" />\n )}\n\n {!loading && !selectedTeamId && (\n <EmptyState\n message=\"Select a team to see available models\"\n hint=\"Each team may have a different set of models assigned\"\n />\n )}\n\n {!loading && selectedTeamId && teamModels.length === 0 && (\n <EmptyState\n message=\"No models available for this team\"\n hint={allModels.length === 0 ? 'No models are configured in the system' : 'None of the team\\'s assigned models were found in the catalog'}\n />\n )}\n\n {!loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && (\n <EmptyState\n message=\"No models match your search\"\n hint=\"Try a different search term\"\n />\n )}\n\n {!loading && filteredModels.length > 0 && (\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sortDirection={sortKey === 'model_name' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'model_name'} direction={sortKey === 'model_name' ? sortDirection : 'asc'} onClick={() => handleSort('model_name')}>Model ID</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'mode' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'mode'} direction={sortKey === 'mode' ? sortDirection : 'asc'} onClick={() => handleSort('mode')}>Mode</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'input_cost_per_token' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'input_cost_per_token'} direction={sortKey === 'input_cost_per_token' ? sortDirection : 'asc'} onClick={() => handleSort('input_cost_per_token')}>Input Cost</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'output_cost_per_token' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'output_cost_per_token'} direction={sortKey === 'output_cost_per_token' ? sortDirection : 'asc'} onClick={() => handleSort('output_cost_per_token')}>Output Cost</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'max_input_tokens' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'max_input_tokens'} direction={sortKey === 'max_input_tokens' ? sortDirection : 'asc'} onClick={() => handleSort('max_input_tokens')}>Max Input</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'max_output_tokens' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'max_output_tokens'} direction={sortKey === 'max_output_tokens' ? sortDirection : 'asc'} onClick={() => handleSort('max_output_tokens')}>Max Output</TableSortLabel>\n </TableCell>\n <TableCell>Capabilities</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {filteredModels.map(m => (\n <TableRow key={m.model_name} hover>\n <TableCell>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Tooltip title={m.model_name} placement=\"top\">\n <span\n role=\"button\"\n tabIndex={0}\n aria-label=\"Copy model ID\"\n onClick={() => handleCopyModelId(m.model_name)}\n onKeyDown={e => e.key === 'Enter' && handleCopyModelId(m.model_name)}\n style={{ cursor: 'pointer', display: 'inline-flex' }}\n >\n <TagChip label={m.model_name} title=\"Copy model ID\" />\n </span>\n </Tooltip>\n <Tooltip title=\"Copy model ID\">\n <Box\n component=\"span\"\n role=\"button\"\n tabIndex={0}\n onClick={() => handleCopyModelId(m.model_name)}\n onKeyDown={e => e.key === 'Enter' && handleCopyModelId(m.model_name)}\n sx={quietIconButtonSx('accent')}\n style={{ cursor: 'pointer', display: 'inline-flex' }}\n >\n <ContentCopyIcon sx={{ fontSize: 14 }} />\n </Box>\n </Tooltip>\n </Box>\n </TableCell>\n <TableCell>\n <Box\n component=\"span\"\n sx={{\n display: 'inline-block',\n px: 0.75,\n py: 0.25,\n borderRadius: 1,\n fontSize: 11,\n fontWeight: 600,\n textTransform: 'capitalize',\n bgcolor: alpha(modeColor(m.mode), 0.1),\n color: modeColor(m.mode),\n }}\n >\n {m.mode}\n </Box>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtCostPerToken(m.input_cost_per_token)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtCostPerToken(m.output_cost_per_token)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtTokens(m.max_input_tokens)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtTokens(m.max_output_tokens)}\n </Typography>\n </TableCell>\n <TableCell>\n <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>\n {m.supports_function_calling && (\n <TagChip label=\"Fn\" title=\"Function calling\" />\n )}\n {m.supports_vision && (\n <TagChip label=\"\uD83D\uDC41\" title=\"Vision\" />\n )}\n </Box>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n\n <Snackbar\n open={copiedSnackbar}\n autoHideDuration={2000}\n onClose={() => setCopiedSnackbar(false)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <Alert severity=\"success\" variant=\"filled\" sx={{ fontSize: 13 }}>\n Model ID copied to clipboard\n </Alert>\n </Snackbar>\n </SectionCard>\n );\n};\n", "import { FC, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TablePagination from '@mui/material/TablePagination';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport Alert from '@mui/material/Alert';\nimport { alpha } from '@mui/material/styles';\nimport { KeyboardArrowDown } from '@mui/icons-material';\nimport { useAsync } from 'react-use';\nimport { LiteLlmApiInterface } from '../api';\nimport { AuditLogEntry, AuditLogsParams } from '../types';\nimport { EmptyState, SectionCard, StatusPill, Tone, dataTableSx } from './ui';\n\ninterface AuditLogProps {\n api: LiteLlmApiInterface;\n}\n\nconst ACTION_TONES: Record<string, Tone> = {\n created: 'success',\n deleted: 'danger',\n updated: 'warning',\n blocked: 'danger',\n unblocked: 'success',\n};\n\nfunction actionTone(action?: string): Tone {\n if (!action) return 'neutral';\n for (const [key, tone] of Object.entries(ACTION_TONES)) {\n if (action.toLowerCase().includes(key)) return tone;\n }\n return 'info';\n}\n\n/** `LiteLLM_VerificationToken` \u2192 `Key`; falls back to the raw table name. */\nconst TABLE_LABELS: Record<string, string> = {\n LiteLLM_VerificationToken: 'Key',\n LiteLLM_TeamTable: 'Team',\n LiteLLM_TeamMembership: 'Team member',\n LiteLLM_ObjectPermissionTable: 'Team access (KB / MCP)',\n LiteLLM_UserTable: 'User',\n};\n\nfunction prettyTableName(name?: string | null): string {\n if (!name) return '\u2014';\n return TABLE_LABELS[name] ?? name;\n}\n\nfunction formatDateTime(iso: string): string {\n try {\n return new Date(iso).toLocaleString();\n } catch {\n return iso;\n }\n}\n\nconst DetailRow: FC<{ entry: AuditLogEntry }> = ({ entry }) => {\n const [open, setOpen] = useState(false);\n const hasDetail = entry.before_value || entry.updated_values;\n\n return (\n <>\n <TableRow>\n <TableCell sx={{ width: 40, pr: 0 }}>\n {hasDetail && (\n <IconButton\n size=\"small\"\n onClick={() => setOpen(o => !o)}\n aria-label={open ? 'Hide changes' : 'Show changes'}\n aria-expanded={open}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: open ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <KeyboardArrowDown fontSize=\"small\" />\n </IconButton>\n )}\n </TableCell>\n <TableCell sx={{ whiteSpace: 'nowrap' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">{formatDateTime(entry.updated_at)}</Typography>\n </TableCell>\n <TableCell>\n {entry.action && <StatusPill label={entry.action} tone={actionTone(entry.action)} />}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{prettyTableName(entry.table_name)}</Typography>\n </TableCell>\n <TableCell>\n <Typography\n variant=\"body2\"\n component=\"code\"\n color=\"text.secondary\"\n title={entry.object_id ?? undefined}\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12 }}\n >\n {entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? '\u2026' : '') : '\u2014'}\n </Typography>\n </TableCell>\n <TableCell>{entry.changed_by ?? '\u2014'}</TableCell>\n </TableRow>\n {/* The `&&` selectors below double specificity so they beat the\n table-level `tbody td` rules in dataTableSx \u2014 otherwise the collapsed\n row keeps its cell padding and border, leaving an empty stripe\n between entries. */}\n {hasDetail && (\n <TableRow sx={{ '&&:hover': { bgcolor: 'transparent' } }}>\n <TableCell colSpan={6} sx={{ '&&': { py: 0, border: 0 } }}>\n <Collapse in={open} unmountOnExit>\n <Box\n display=\"flex\"\n gap={2}\n flexWrap=\"wrap\"\n sx={theme => ({\n p: 2,\n mb: 1.5,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.05 : 0.03),\n })}\n >\n {entry.before_value && (\n <Box flex={1} minWidth={200}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n display=\"block\"\n mb={0.75}\n sx={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n Before\n </Typography>\n <Typography component=\"pre\" variant=\"caption\" sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all', m: 0 }}>\n {JSON.stringify(entry.before_value, null, 2)}\n </Typography>\n </Box>\n )}\n {entry.updated_values && (\n <Box flex={1} minWidth={200}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n display=\"block\"\n mb={0.75}\n sx={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n After\n </Typography>\n <Typography component=\"pre\" variant=\"caption\" sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all', m: 0 }}>\n {JSON.stringify(entry.updated_values, null, 2)}\n </Typography>\n </Box>\n )}\n </Box>\n </Collapse>\n </TableCell>\n </TableRow>\n )}\n </>\n );\n};\n\nfunction renderAuditLogBody(loading: boolean, entries: AuditLogEntry[]) {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={6} sx={{ py: 2 }}>\n <Skeleton variant=\"rounded\" height={160} />\n </TableCell>\n </TableRow>\n );\n }\n if (entries.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={6}>\n <EmptyState\n message=\"No audit events found\"\n hint=\"Try widening the filters or a different time window.\"\n />\n </TableCell>\n </TableRow>\n );\n }\n return entries.map(entry => <DetailRow key={entry.id} entry={entry} />);\n}\n\nexport const AuditLog: FC<AuditLogProps> = ({ api }) => {\n const [page, setPage] = useState(0);\n const [pageSize, setPageSize] = useState(25);\n const [filters, setFilters] = useState<Pick<AuditLogsParams, 'action' | 'table_name' | 'changed_by'>>({});\n\n const fetchParams: AuditLogsParams = useMemo(\n () => ({ page: page + 1, page_size: pageSize, ...filters }),\n [page, pageSize, filters],\n );\n\n const { value, loading, error } = useAsync(\n () => api.getAuditLogs(fetchParams),\n [api, fetchParams],\n );\n\n const entries: AuditLogEntry[] = value?.audit_logs ?? [];\n const total = value?.total ?? 0;\n\n return (\n <SectionCard\n title=\"Audit Log\"\n subtitle={loading ? 'Loading\u2026' : `${total.toLocaleString()} event${total === 1 ? '' : 's'}`}\n flush\n actions={\n <>\n <TextField\n size=\"small\"\n label=\"Action\"\n select\n value={filters.action ?? ''}\n onChange={e => { setFilters(f => ({ ...f, action: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 150 }}\n >\n <MenuItem value=\"\">All actions</MenuItem>\n <MenuItem value=\"created\">Created</MenuItem>\n <MenuItem value=\"updated\">Updated</MenuItem>\n <MenuItem value=\"deleted\">Deleted</MenuItem>\n <MenuItem value=\"blocked\">Blocked</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n label=\"Table\"\n select\n value={filters.table_name ?? ''}\n onChange={e => { setFilters(f => ({ ...f, table_name: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 150 }}\n >\n <MenuItem value=\"\">All tables</MenuItem>\n <MenuItem value=\"LiteLLM_VerificationToken\">Key</MenuItem>\n <MenuItem value=\"LiteLLM_TeamTable\">Team</MenuItem>\n <MenuItem value=\"LiteLLM_TeamMembership\">Team member</MenuItem>\n <MenuItem value=\"LiteLLM_ObjectPermissionTable\">Team access (KB / MCP)</MenuItem>\n <MenuItem value=\"LiteLLM_UserTable\">User</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n label=\"Changed by\"\n value={filters.changed_by ?? ''}\n onChange={e => { setFilters(f => ({ ...f, changed_by: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 180 }}\n />\n </>\n }\n >\n {error && (\n <Box px={2.5} pb={2}>\n <Alert severity=\"error\">{error.message}</Alert>\n </Box>\n )}\n\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sx={{ width: 40 }} />\n <TableCell>Time</TableCell>\n <TableCell>Action</TableCell>\n <TableCell>Table</TableCell>\n <TableCell>Object ID</TableCell>\n <TableCell>Changed By</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderAuditLogBody(loading, entries)}\n </TableBody>\n </Table>\n </TableContainer>\n\n <TablePagination\n component=\"div\"\n count={total}\n page={page}\n onPageChange={(_, p) => setPage(p)}\n rowsPerPage={pageSize}\n onRowsPerPageChange={e => { setPageSize(Number(e.target.value)); setPage(0); }}\n rowsPerPageOptions={[10, 25, 50]}\n sx={theme => ({ borderTop: `1px solid ${theme.palette.divider}` })}\n />\n </SectionCard>\n );\n};\n", "/**\n * Convert a Date to a local calendar day string in YYYY-MM-DD format.\n * Uses local calendar components (getFullYear, getMonth, getDate),\n * not UTC, to avoid timezone shifts at month/year boundaries.\n */\nexport function toLocalDay(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Month-to-date range as YYYY-MM-DD strings: the 1st of the current month through today.\n * Uses local calendar, not UTC, to respect the user's timezone.\n */\nexport function monthToDateRange(now: Date = new Date()): { startDate: string; endDate: string } {\n const start = new Date(now.getFullYear(), now.getMonth(), 1);\n return {\n startDate: toLocalDay(start),\n endDate: toLocalDay(now),\n };\n}\n\nexport type DatePreset = 'today' | '24h' | '7d' | '30d';\n\n/**\n * Build a date range from a preset name. Returns an object with\n * Date objects and pre-formatted YYYY-MM-DD strings for API calls.\n */\nexport function localDateRange(\n preset: DatePreset,\n now: Date = new Date(),\n): { start: Date; end: Date; startDate: string; endDate: string } {\n const end = new Date(now);\n const start = new Date(now);\n\n if (preset === 'today') {\n start.setHours(0, 0, 0, 0);\n } else if (preset === '24h') {\n start.setHours(start.getHours() - 24);\n } else if (preset === '7d') {\n start.setDate(start.getDate() - 7);\n } else if (preset === '30d') {\n start.setDate(start.getDate() - 30);\n }\n\n return {\n start,\n end,\n startDate: toLocalDay(start),\n endDate: toLocalDay(end),\n };\n}\n", "// Re-export all permissions from common for backward compatibility\nexport {\n litellmKeyCreatePermission,\n litellmKeyRevokePermission,\n litellmKeyManagePermission,\n litellmKeyResetSpendPermission,\n litellmKeyUnblockPermission,\n litellmAuditReadPermission,\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n litellmTeamDeletePermission,\n litellmPermissions,\n} from '@acarmisc/backstage-plugin-litellm-common';\n", "/**\n * Feedback message generation for toast notifications.\n * Maps action outcomes to appropriate toast messages and severity levels.\n */\n\nexport type AlertSeverity = 'success' | 'warning' | 'error' | 'info';\n\nexport interface AlertMessage {\n message: string;\n severity: AlertSeverity;\n}\n\ntype ActionKind =\n | 'generateSuccess'\n | 'generateError'\n | 'updateSuccess'\n | 'updateError'\n | 'blockSuccess'\n | 'blockError'\n | 'unblockSuccess'\n | 'unblockError'\n | 'resetSpendSuccess'\n | 'resetSpendError'\n | 'deleteSuccess'\n | 'deleteError'\n | 'deleteAlreadyDeleted'\n | 'pruneSuccess'\n | 'prunePartial'\n | 'pruneError'\n | 'teamSaveSuccess'\n | 'teamSaveError'\n | 'knowledgeBaseSuccess'\n | 'mcpServerSuccess';\n\n/**\n * Generate a toast alert message for an action outcome.\n * For inline dialog errors (e.g., key form validation), return null\n * to let the dialog handle it internally.\n */\nexport function toastFor(kind: ActionKind, errorMsg?: string): AlertMessage | null {\n switch (kind) {\n case 'generateSuccess':\n return { message: 'Key generated successfully', severity: 'success' };\n case 'generateError':\n return { message: `Failed to generate key: ${errorMsg}`, severity: 'error' };\n\n case 'updateSuccess':\n return { message: 'Key updated successfully', severity: 'success' };\n case 'updateError':\n return { message: `Failed to update key: ${errorMsg}`, severity: 'error' };\n\n case 'blockSuccess':\n return { message: 'Key blocked \u2014 requests will be rejected until unblocked', severity: 'warning' };\n case 'blockError':\n return { message: `Failed to block key: ${errorMsg}`, severity: 'error' };\n\n case 'unblockSuccess':\n return { message: 'Key unblocked', severity: 'success' };\n case 'unblockError':\n return { message: `Failed to unblock key: ${errorMsg}`, severity: 'error' };\n\n case 'resetSpendSuccess':\n return { message: 'Spend counter reset to $0', severity: 'success' };\n case 'resetSpendError':\n return { message: `Failed to reset spend: ${errorMsg}`, severity: 'error' };\n\n case 'deleteSuccess':\n return { message: 'Key revoked successfully', severity: 'success' };\n case 'deleteError':\n return { message: `Failed to revoke key: ${errorMsg}`, severity: 'error' };\n case 'deleteAlreadyDeleted':\n return { message: 'Key was already deleted', severity: 'warning' };\n\n case 'pruneSuccess':\n return { message: 'Pruned expired keys', severity: 'success' };\n case 'prunePartial':\n return { message: 'Pruned expired keys (some failed to delete)', severity: 'warning' };\n case 'pruneError':\n return { message: `Failed to prune expired keys: ${errorMsg}`, severity: 'error' };\n\n case 'teamSaveSuccess':\n return { message: 'Team saved', severity: 'success' };\n case 'teamSaveError':\n return { message: `Failed to save team: ${errorMsg}`, severity: 'error' };\n\n case 'knowledgeBaseSuccess':\n return { message: 'Knowledge bases updated', severity: 'success' };\n\n case 'mcpServerSuccess':\n return { message: 'MCP servers updated', severity: 'success' };\n\n default:\n return null;\n }\n}\n", "import { TeamInfo } from './types';\n\n/**\n * Checks whether a user can manage members of a team (add/remove members).\n * A user is a member manager if:\n * - The feature is not in readOnly mode (teams synced from identity provider)\n * - There are configured memberManagerRoles\n * - The user is a member of the team with a role in memberManagerRoles\n */\nexport function isTeamMemberManager(\n team: TeamInfo | undefined,\n userId: string | undefined,\n memberManagerRoles: string[] | undefined,\n readOnly: boolean | undefined,\n): boolean {\n if (!team || !userId || !memberManagerRoles || memberManagerRoles.length === 0 || readOnly) {\n return false;\n }\n return team.members_with_roles?.some(m => m.user_id === userId && memberManagerRoles.includes(m.role)) ?? false;\n}\n", "/**\n * Copy for unprovisioned users.\n */\n\nexport function getUnprovisionedTitle(): string {\n return 'Your LiteLLM account isn\\'t set up yet';\n}\n\nexport function getUnprovisionedMessage(supportContact?: string): string {\n const contact = supportContact?.trim();\n if (contact) {\n return `Contact ${contact}`;\n }\n return 'Contact your administrator';\n}\n\nexport function getAdminDetailsTitle(): string {\n return 'Details for administrators';\n}\n\nexport function getAdminDetailsMessage(): string {\n return 'Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.';\n}\n", "import { FC, useCallback, useEffect, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport Tabs from '@mui/material/Tabs';\nimport Tab from '@mui/material/Tab';\nimport Grid from '@mui/material/Grid';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport { useSearchParams } from 'react-router-dom';\nimport { useAsync, useAsyncRetry } from 'react-use';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport { Content, Progress } from '@backstage/core-components';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { DashboardHeader } from './DashboardHeader';\nimport { KeysTable } from './KeysTable';\nimport { KeyFormDialog } from './KeyFormDialog';\nimport { ManageTeamDialog } from './ManageTeamDialog';\nimport { UsageStats } from './UsageStats';\nimport { LiteLLMBudgetWidget } from './LiteLLMBudgetWidget';\nimport { TeamUsage } from './TeamUsage';\nimport { ModelsTable } from './ModelsTable';\nimport { AuditLog } from './AuditLog';\nimport { liteLlmApiRef } from '../api';\nimport { toLocalDay } from '../dates';\nimport {\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n} from '../permissions';\nimport { DateRange, GenerateKeyRequest, GenerateKeyResponse, UpdateKeyRequest, UsageMetrics, CreateTeamRequest, UpdateTeamRequest, TeamInfo, VirtualKey } from '../types';\nimport { toastFor } from '../feedback';\nimport { isTeamMemberManager } from '../teamMemberManager';\nimport {\n getUnprovisionedTitle,\n getUnprovisionedMessage,\n getAdminDetailsTitle,\n getAdminDetailsMessage,\n} from '../unprovisionedCopy';\n\nconst PERIOD_LS_KEY = 'litellm_usage_period';\ntype DatePreset = 'today' | '24h' | '7d' | '30d';\n\ntype PageTab = 'overview' | 'keys' | 'teams' | 'models' | 'audit';\nconst PAGE_TABS: readonly PageTab[] = ['overview', 'keys', 'teams', 'models', 'audit'];\nconst isPageTab = (v: string | null): v is PageTab =>\n !!v && (PAGE_TABS as readonly string[]).includes(v);\n\nfunction initDateRange(): DateRange {\n let preset = '7d';\n try { preset = localStorage.getItem(PERIOD_LS_KEY) ?? '7d'; } catch { /* ignore */ }\n const end = new Date();\n const start = new Date();\n if (preset === 'today') start.setHours(0, 0, 0, 0);\n else if (preset === '24h') start.setHours(start.getHours() - 24);\n else if (preset === '30d') start.setDate(start.getDate() - 30);\n else start.setDate(start.getDate() - 7);\n return { start, end };\n}\n\nexport const LiteLLMPage: FC = () => {\n const api = useApi(liteLlmApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [dateRange, setDateRange] = useState<DateRange>(initDateRange);\n const [currentPreset, setCurrentPreset] = useState<DatePreset>(() => {\n try { return (localStorage.getItem(PERIOD_LS_KEY) as DatePreset) ?? '7d'; } catch { return '7d'; }\n });\n const [searchParams, setSearchParams] = useSearchParams();\n const [activeTab, setActiveTab] = useState<PageTab>(() => {\n const t = searchParams.get('tab');\n return isPageTab(t) ? t : 'overview';\n });\n const [filter, setFilter] = useState<'expired' | 'expiring' | undefined>(() => {\n const f = searchParams.get('filter');\n return f === 'expired' || f === 'expiring' ? f : undefined;\n });\n\n // `?generate=1` (e.g. from a homepage budget card's \"Generate New Key\"\n // CTA) opens the generate-key dialog on arrival. The param is cleared once honoured so a\n // manual close doesn't immediately reopen it on the next render.\n const [generateDialogOpen, setGenerateDialogOpen] = useState(\n () => searchParams.get('generate') === '1',\n );\n useEffect(() => {\n if (searchParams.get('generate') !== '1') return;\n setGenerateDialogOpen(true);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.delete('generate');\n return next;\n },\n { replace: true },\n );\n }, [searchParams, setSearchParams]);\n\n // Keep `?tab=` in sync so links (e.g. the budget widget's \"more keys\"\n // note pointing at `/litellm?tab=keys`) land on the right tab and the URL\n // stays shareable.\n const selectTab = useCallback(\n (tab: PageTab) => {\n setActiveTab(tab);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.set('tab', tab);\n return next;\n },\n { replace: true },\n );\n },\n [setSearchParams],\n );\n\n // Navigate to keys tab with a filter applied\n const navigateToFilter = useCallback(\n (f: 'expired' | 'expiring') => {\n setActiveTab('keys');\n setFilter(f);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.set('tab', 'keys');\n next.set('filter', f);\n return next;\n },\n { replace: true },\n );\n },\n [setSearchParams],\n );\n\n // Clear filter when explicitly requested\n const clearFilter = useCallback(() => {\n setFilter(undefined);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.delete('filter');\n return next;\n },\n { replace: true },\n );\n }, [setSearchParams]);\n\n const [manageTeam, setManageTeam] = useState<{ mode: 'create' | 'edit' | 'members'; team?: TeamInfo } | null>(null);\n /** Which key is open in the shared key form dialog; null = create mode. */\n const [keyToEdit, setKeyToEdit] = useState<VirtualKey | null>(null);\n const keyFormOpen = generateDialogOpen || !!keyToEdit;\n\n // Team usage cache: teamId -> UsageMetrics\n const [teamUsageCache, setTeamUsageCache] = useState<Record<string, UsageMetrics | null>>({});\n const [teamUsageLoading, setTeamUsageLoading] = useState<Record<string, boolean>>({});\n\n const { value: userInfo, loading: userLoading, error: userError } = useAsync(\n () => api.getUserInfo(),\n [api],\n );\n\n const { value: keys, loading: keysLoading, error: keysError, retry: refreshKeys } = useAsyncRetry(\n () => api.listKeys(),\n [api],\n );\n\n const { value: allModels, loading: modelsLoading, error: modelsError, retry: refreshModels } = useAsyncRetry(\n () => api.listModels(),\n [api],\n );\n\n const { value: allTeams, loading: teamsLoading, error: teamsError, retry: refreshTeams } = useAsyncRetry(\n () => api.getTeams(),\n [api],\n );\n\n const { value: liteLlmConfig } = useAsync(() => api.getConfig(), [api]);\n\n // Teams the caller administers by group ownership (not membership). Only\n // fetched when team management is enabled; failures degrade to an empty list.\n const { value: managedTeams } = useAsync(\n async () =>\n liteLlmConfig?.teamManagement?.enabled\n ? api.getManagedTeams().catch(() => [])\n : [],\n [api, liteLlmConfig],\n );\n\n const { allowed: canCreateTeam } = usePermission({ permission: litellmTeamCreatePermission });\n const { allowed: canManageTeam } = usePermission({ permission: litellmTeamManagePermission });\n const { allowed: canManageMembers } = usePermission({ permission: litellmTeamMembersManagePermission });\n const { allowed: canManageKnowledgeBases } = usePermission({ permission: litellmTeamKnowledgebaseManagePermission });\n const { allowed: canManageMcpServers } = usePermission({ permission: litellmTeamMcpManagePermission });\n const teamMgmtEnabled = liteLlmConfig?.teamManagement?.enabled ?? false;\n const objectPermsEnabled = liteLlmConfig?.teamManagement?.objectPermissionsEnabled ?? false;\n\n const { value: vectorStores } = useAsync(\n async () =>\n objectPermsEnabled ? api.getVectorStores().catch(() => []) : [],\n [api, objectPermsEnabled],\n );\n const { value: mcpServers } = useAsync(\n async () =>\n objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],\n [api, objectPermsEnabled],\n );\n\n // Filter to teams the current user belongs to\n const teams = useMemo(() => {\n if (!allTeams?.length) return [];\n if (!userInfo) return allTeams;\n const userId = userInfo.user_id;\n const memberOf = userInfo.teams;\n if (memberOf?.length) {\n return allTeams.filter(t => memberOf.includes(t.team_id));\n }\n // No team list on the profile: fall back to membership on the team records.\n // Never fall back to *all* teams \u2014 that would list teams the user isn't in.\n return allTeams.filter(t =>\n t.members_with_roles?.some(m => m.user_id === userId),\n );\n }, [allTeams, userInfo]);\n\n const { value: usage, loading: usageLoading, error: usageError, retry: refreshUsage } = useAsyncRetry(async () => {\n const startDate = toLocalDay(dateRange.start);\n const endDate = toLocalDay(dateRange.end);\n return api.getUsage(startDate, endDate);\n }, [api, dateRange]);\n\n // Invalidate team usage cache when date range changes so stale data isn't shown\n const handleDateRangeChange = useCallback((range: DateRange, preset?: DatePreset) => {\n setDateRange(range);\n if (preset) {\n setCurrentPreset(preset);\n }\n setTeamUsageCache({});\n setTeamUsageLoading({});\n }, [setDateRange, setCurrentPreset]);\n\n // Fetch team usage on demand when a team card is expanded\n const loadTeamUsage = useCallback(async (teamId: string) => {\n if (teamUsageCache[teamId] !== undefined || teamUsageLoading[teamId]) return;\n setTeamUsageLoading(prev => ({ ...prev, [teamId]: true }));\n try {\n const startDate = toLocalDay(dateRange.start);\n const endDate = toLocalDay(dateRange.end);\n const data = await api.getTeamUsage(teamId, startDate, endDate);\n setTeamUsageCache(prev => ({ ...prev, [teamId]: data }));\n } catch {\n setTeamUsageCache(prev => ({ ...prev, [teamId]: null }));\n } finally {\n setTeamUsageLoading(prev => ({ ...prev, [teamId]: false }));\n }\n }, [api, dateRange, teamUsageCache, teamUsageLoading]);\n\n // Models offered for key generation: when the user has a model restriction, the\n // UNION of their own allowed models and their teams' models (a team-bound key is\n // limited to its team's models, which the server enforces and the key form then\n // narrows to the selected team); with no restriction, every model. The server\n // (POST /keys/generate) is the source of truth for what is actually accepted.\n const allowedModels = useMemo(() => {\n if (!allModels?.length) return [];\n const userModels = userInfo?.models;\n const teamModels = teams?.flatMap(t => t.models ?? []);\n const hasUserRestriction = userModels && userModels.length > 0;\n const hasTeamRestriction = teamModels && teamModels.length > 0;\n if (!hasUserRestriction && !hasTeamRestriction) return allModels;\n const allowed = new Set([\n ...(hasUserRestriction ? userModels! : allModels.map(m => m.model_name)),\n ...(hasTeamRestriction ? teamModels! : []),\n ]);\n return allModels.filter(m => allowed.has(m.model_name));\n }, [allModels, userInfo, teams]);\n\n const getConfig = useCallback(() => api.getConfig(), [api]);\n\n const handleGenerateKey = useCallback(\n async (request: GenerateKeyRequest): Promise<GenerateKeyResponse> => {\n try {\n const response = await api.generateKey(request);\n const alert = toastFor('generateSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n return response;\n } catch (e: any) {\n // The dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleUpdateKey = useCallback(\n async (keyId: string, request: UpdateKeyRequest) => {\n try {\n await api.updateKey(keyId, request);\n const alert = toastFor('updateSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n // The dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleBlockKey = useCallback(\n async (keyId: string) => {\n try {\n await api.blockKey(keyId);\n const alert = toastFor('blockSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('blockError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleUnblockKey = useCallback(\n async (keyId: string) => {\n try {\n await api.unblockKey(keyId);\n const alert = toastFor('unblockSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('unblockError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleResetKeySpend = useCallback(\n async (keyId: string) => {\n try {\n await api.resetKeySpend(keyId);\n const alert = toastFor('resetSpendSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n // The key dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleDeleteKey = useCallback(\n async (keyId: string) => {\n try {\n await api.deleteKey(keyId);\n const alert = toastFor('deleteSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n if (e.body?.success && (e.body?.message?.includes('already deleted') || e.body?.message?.includes('never existed'))) {\n const alert = toastFor('deleteAlreadyDeleted');\n if (alert) alertApi.post(alert);\n refreshKeys();\n return;\n }\n const alert = toastFor('deleteError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handlePruneExpiredKeys = useCallback(\n async () => {\n try {\n const result = await api.pruneExpiredKeys();\n const kind = result.failed > 0 ? 'prunePartial' : 'pruneSuccess';\n const alert = toastFor(kind);\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('pruneError', e.message);\n if (alert) alertApi.post(alert);\n }\n return { pruned: 0, failed: 0 };\n },\n [api, refreshKeys, alertApi],\n ) as () => Promise<{ pruned: number; failed: number }>;\n\n const isInitialLoading = userLoading && !userInfo;\n\n if (isInitialLoading) {\n return <Progress />;\n }\n\n // User exists in Backstage but has no LiteLLM account\n if (userError || !userInfo) {\n const hint = (userError as any)?.body?.hint;\n return (\n <Box sx={{ p: 3, display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box\n sx={{\n maxWidth: 600,\n mx: 'auto',\n py: 6,\n textAlign: 'center',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 2,\n }}\n >\n <Typography variant=\"h5\" sx={{ fontWeight: 600 }}>\n {getUnprovisionedTitle()}\n </Typography>\n <Typography color=\"text.secondary\">\n {hint || getUnprovisionedMessage(liteLlmConfig?.supportContact)}\n </Typography>\n <Accordion sx={{ width: '100%', maxWidth: 500, mt: 2 }}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {getAdminDetailsTitle()}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {getAdminDetailsMessage()}\n </Typography>\n </AccordionDetails>\n </Accordion>\n </Box>\n </Box>\n );\n }\n\n const pageTabs = (\n <Tabs\n value={activeTab}\n onChange={(_, v) => selectTab(v as PageTab)}\n variant=\"scrollable\"\n scrollButtons=\"auto\"\n // Substring class matching so these survive a host MUI classname prefix\n // (Backstage renders `v5-MuiTabs-indicator`, not `MuiTabs-indicator`).\n sx={{\n minHeight: 44,\n '& [class*=\"MuiTabs-indicator\"]': { height: 2, borderRadius: '2px 2px 0 0' },\n '& [class*=\"MuiTab-root\"]': { minHeight: 44, textTransform: 'none', fontSize: 14 },\n }}\n >\n <Tab label=\"Overview\" value=\"overview\" />\n <Tab label=\"Keys\" value=\"keys\" />\n <Tab label=\"Teams\" value=\"teams\" />\n <Tab label=\"Models\" value=\"models\" />\n {userInfo.can_view_audit && <Tab label=\"Audit Log\" value=\"audit\" />}\n </Tabs>\n );\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box sx={{ px: 3, pt: 3 }}>\n <DashboardHeader\n userInfo={userInfo}\n teams={teams ?? []}\n keys={keys ?? []}\n loading={userLoading || teamsLoading}\n keysError={keysError}\n onGenerateKeyClick={() => setGenerateDialogOpen(true)}\n onNavigateToFilter={navigateToFilter}\n tabs={pageTabs}\n />\n </Box>\n\n <Content>\n {activeTab === 'overview' && (() => {\n // Show onboarding when keys have loaded without error and list is empty\n if (!keysLoading && !keysError && keys?.length === 0) {\n return (\n <Box sx={{ maxWidth: 600, mx: 'auto', py: 4 }}>\n <Box\n sx={{\n textAlign: 'center',\n py: 6,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 3,\n }}\n >\n <Typography variant=\"h5\" sx={{ fontWeight: 600 }}>\n Create your first API key\n </Typography>\n <Box\n component=\"ol\"\n sx={{\n textAlign: 'left',\n pl: 3,\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n '& li': { color: 'text.secondary' },\n }}\n >\n <li>Generate a key</li>\n <li>Copy the endpoint</li>\n <li>Make a call</li>\n </Box>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setGenerateDialogOpen(true)}\n >\n Generate API Key\n </Button>\n </Box>\n </Box>\n );\n }\n\n return (\n <Grid container spacing={2} alignItems=\"flex-start\">\n <Grid item xs={12} lg={8}>\n <UsageStats\n usage={usage ?? null}\n usageError={usageError}\n onRetryUsage={refreshUsage}\n models={allModels ?? []}\n dateRange={dateRange}\n currentPreset={currentPreset}\n onDateRangeChange={handleDateRangeChange}\n loading={usageLoading}\n userInfo={userInfo}\n />\n </Grid>\n <Grid item xs={12} lg={4}>\n <LiteLLMBudgetWidget compact collapsible userInfo={userInfo ?? null} teams={teams} keys={keys ?? []} />\n </Grid>\n </Grid>\n );\n })()}\n\n {activeTab === 'keys' && (() => {\n if (keysError) {\n return (\n <Alert severity=\"error\">\n Failed to load keys: {(keysError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshKeys}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n return (\n <KeysTable\n keys={keys ?? []}\n loading={keysLoading || modelsLoading}\n onGenerateKeyClick={() => setGenerateDialogOpen(true)}\n onEditKey={setKeyToEdit}\n onBlockKey={handleBlockKey}\n onUnblockKey={handleUnblockKey}\n onDeleteKey={handleDeleteKey}\n onPruneExpiredKeys={handlePruneExpiredKeys}\n filter={filter}\n onClearFilter={clearFilter}\n />\n );\n })()}\n\n {activeTab === 'teams' && (() => {\n if (teamsError) {\n return (\n <Alert severity=\"error\">\n Failed to load teams: {(teamsError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshTeams}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n // Union of teams the user is a member of and teams their group owns,\n // de-duplicated by team_id (membership entries win on conflict).\n const teamsById = new Map<string, TeamInfo>();\n for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);\n for (const t of teams ?? []) teamsById.set(t.team_id, t);\n const visibleTeams = Array.from(teamsById.values());\n const readOnly = liteLlmConfig?.teamManagement?.readOnly ?? false;\n const memberManagerRoles = liteLlmConfig?.teamManagement?.memberManagerRoles ?? [];\n\n return (\n <TeamUsage\n teams={visibleTeams}\n loading={teamsLoading}\n getTeamUsage={teamId => teamUsageCache[teamId] ?? null}\n getTeamUsageLoading={teamId => teamUsageLoading[teamId] ?? false}\n canManage={teamMgmtEnabled && canManageTeam && !readOnly}\n onEditTeam={t => setManageTeam({ mode: 'edit', team: t })}\n canCreate={teamMgmtEnabled && canCreateTeam && !readOnly}\n onCreateTeam={() => setManageTeam({ mode: 'create' })}\n canManageMembers={t =>\n teamMgmtEnabled &&\n canManageMembers &&\n isTeamMemberManager(t, userInfo?.user_id, memberManagerRoles, readOnly)\n }\n onManageMembers={t => setManageTeam({ mode: 'members', team: t })}\n readOnly={readOnly}\n onTeamExpand={team => loadTeamUsage(team.team_id)}\n />\n );\n })()}\n\n {activeTab === 'models' && (() => {\n if (modelsError) {\n return (\n <Alert severity=\"error\">\n Failed to load models: {(modelsError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshModels}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n return (\n <ModelsTable\n allModels={allModels ?? []}\n teams={teams ?? []}\n loading={modelsLoading}\n />\n );\n })()}\n\n {activeTab === 'audit' && userInfo.can_view_audit && <AuditLog api={api} />}\n </Content>\n\n <KeyFormDialog\n open={keyFormOpen}\n onClose={() => {\n setGenerateDialogOpen(false);\n setKeyToEdit(null);\n }}\n mode={keyToEdit ? 'edit' : 'create'}\n keyToEdit={keyToEdit}\n keys={keys ?? []}\n models={allowedModels}\n modelsError={modelsError}\n onRetryModels={refreshModels}\n teams={teams ?? []}\n username={userInfo.user_id}\n keyGenerationSettings={liteLlmConfig?.keyGeneration}\n onCreateKey={handleGenerateKey}\n onUpdateKey={handleUpdateKey}\n onResetKeySpend={handleResetKeySpend}\n onGetConfig={getConfig}\n />\n\n <ManageTeamDialog\n open={!!manageTeam}\n onClose={() => setManageTeam(null)}\n mode={manageTeam?.mode === 'members' ? 'edit' : (manageTeam?.mode ?? 'create')}\n team={manageTeam?.team}\n allModels={allModels ?? []}\n config={liteLlmConfig}\n membersOnly={manageTeam?.mode === 'members'}\n currentUserId={userInfo?.user_id}\n memberManagerRoles={liteLlmConfig?.teamManagement?.memberManagerRoles}\n onSubmit={async payload => {\n try {\n if (manageTeam?.mode === 'edit' && manageTeam.team) {\n const loadedAt = manageTeam.team.metadata?.updated_at_iso;\n await api.updateTeam(manageTeam.team.team_id, {\n ...(payload as UpdateTeamRequest),\n // Reject the edit if someone else changed the team since it was loaded.\n ...(typeof loadedAt === 'string' ? { expectedUpdatedAtIso: loadedAt } : {}),\n });\n } else {\n await api.createTeam(payload as CreateTeamRequest);\n }\n const alert = toastFor('teamSaveSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n canManageMembers={teamMgmtEnabled && canManageMembers && !liteLlmConfig?.teamManagement?.readOnly}\n onAddMember={async (userEntityRef, maxBudgetInTeam) => {\n if (!manageTeam?.team) return;\n const updated = await api.addTeamMember(manageTeam.team.team_id, {\n userEntityRef,\n ...(maxBudgetInTeam ? { maxBudgetInTeam } : {}),\n });\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n refreshTeams();\n }}\n onRemoveMember={async userEntityRef => {\n if (!manageTeam?.team) return;\n const updated = await api.removeTeamMember(\n manageTeam.team.team_id,\n userEntityRef,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n refreshTeams();\n }}\n canManageKnowledgeBases={\n teamMgmtEnabled && objectPermsEnabled && canManageKnowledgeBases\n }\n vectorStores={vectorStores ?? []}\n onSaveKnowledgeBases={async vectorStoreIds => {\n if (!manageTeam?.team) return;\n try {\n const updated = await api.setTeamKnowledgeBases(\n manageTeam.team.team_id,\n vectorStoreIds,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n const alert = toastFor('knowledgeBaseSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n canManageMcpServers={\n teamMgmtEnabled && objectPermsEnabled && canManageMcpServers\n }\n mcpServers={mcpServers ?? []}\n onSaveMcpServers={async mcpServerIds => {\n if (!manageTeam?.team) return;\n try {\n const updated = await api.setTeamMcpServers(\n manageTeam.team.team_id,\n mcpServerIds,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n const alert = toastFor('mcpServerSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n />\n\n </Box>\n );\n};\n", "export { litellmPlugin } from './plugin';\nexport { LiteLLMPage } from './components/LiteLLMPage';\nexport { DashboardHeader } from './components/DashboardHeader';\nexport { KeysTable } from './components/KeysTable';\nexport { UsageStats } from './components/UsageStats';\nexport { TeamUsage } from './components/TeamUsage';\nexport { LiteLLMHomeWidget } from './components/LiteLLMHomeWidget';\nexport type { LiteLLMHomeWidgetProps } from './components/LiteLLMHomeWidget';\nexport { LiteLLMBudgetWidget } from './components/LiteLLMBudgetWidget';\nexport type { LiteLLMBudgetWidgetProps } from './components/LiteLLMBudgetWidget';\nexport { LiteLLMBudgetGauges } from './components/LiteLLMBudgetGauges';\nexport type {\n LiteLLMBudgetGaugesProps,\n BudgetCta,\n BudgetCtaKind,\n BudgetCtaSpec,\n} from './components/LiteLLMBudgetGauges';\nexport { KeyFormDialog } from './components/KeyFormDialog';\nexport type { KeyFormDialogMode, KeyFormDialogProps } from './components/KeyFormDialog';\nexport { GenerateKeyButton } from './components/GenerateKeyButton';\nexport type { GenerateKeyButtonProps } from './components/GenerateKeyButton';\nexport { GenerateKeyDialog } from './components/GenerateKeyDialog';\nexport { ManageTeamDialog } from './components/ManageTeamDialog';\nexport { LiteLlmApi, liteLlmApiRef } from './api';\nexport {\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n} from './permissions';\nexport type { LiteLlmApiInterface } from './api';\nexport * from './types';\n", "import { TrendingUp as TrendingUpIcon } from '@mui/icons-material';\nimport {\n createFrontendPlugin,\n ApiBlueprint,\n PageBlueprint,\n fetchApiRef,\n discoveryApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { liteLlmApiRef, LiteLlmApi } from './api';\nimport { rootRouteRef } from './routes';\n\nconst liteLlmApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: liteLlmApiRef,\n deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef },\n factory: ({ fetchApi, discoveryApi }) => new LiteLlmApi(fetchApi, discoveryApi),\n }),\n});\n\nconst liteLlmPage = PageBlueprint.make({\n params: {\n path: '/litellm',\n title: 'LiteLLM',\n icon: <TrendingUpIcon />,\n routeRef: rootRouteRef,\n loader: async () => {\n const { LiteLLMPage } = await import('./components/LiteLLMPage');\n return <LiteLLMPage />;\n },\n },\n});\n\nexport const litellmPlugin = createFrontendPlugin({\n pluginId: 'litellm',\n routes: {\n root: rootRouteRef,\n },\n extensions: [liteLlmApi, liteLlmPage],\n});\n", "import { ElementType, FC, useEffect, useMemo, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport FormControl from '@mui/material/FormControl';\nimport Select from '@mui/material/Select';\nimport MenuItem from '@mui/material/MenuItem';\nimport Skeleton from '@mui/material/Skeleton';\nimport { AreaChart, Area, XAxis, Tooltip, ResponsiveContainer } from 'recharts';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { liteLlmApiRef } from '../api';\nimport { rootRouteRef } from '../routes';\nimport { UsageMetrics } from '../types';\nimport { fmtUsd } from '../format';\nimport { toLocalDay } from '../dates';\nimport { SERIES, ChartTooltip } from './ui';\nimport { widgetViewState, USAGE_UNAVAILABLE_MSG, UNPROVISIONED_MSG } from '../widgetState';\nimport { rangeCaption, sparklineAriaLabel, usageSummary } from '../homeWidgetHelpers';\n\nexport interface LiteLLMHomeWidgetProps {\n /** Default period when the widget mounts. Defaults to '7d'. */\n defaultPeriod?: 'today' | '7d' | '30d';\n /** Optional title override. Defaults to 'LiteLLM Usage'. */\n title?: string;\n /**\n * Render without the widget's own card chrome and title, for hosts (such as\n * the home page grid) that already provide a titled card. Defaults to false.\n */\n bare?: boolean;\n}\n\ntype DatePreset = 'today' | '7d' | '30d';\n\n\nfunction presetToDateRange(preset: DatePreset): { start: Date; end: Date } {\n const end = new Date();\n const start = new Date();\n if (preset === 'today') {\n start.setHours(0, 0, 0, 0);\n } else if (preset === '7d') {\n start.setDate(start.getDate() - 7);\n } else {\n start.setDate(start.getDate() - 30);\n }\n return { start, end };\n}\n\n\nexport const LiteLLMHomeWidget: FC<LiteLLMHomeWidgetProps> = ({\n defaultPeriod = '7d',\n title = 'LiteLLM Usage',\n bare = false,\n}) => {\n const api = useApi(liteLlmApiRef);\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const { userInfo, keys, loading: profileLoading, error: profileError } = useLiteLLMProfile();\n const [period, setPeriod] = useState<DatePreset>(defaultPeriod);\n const [usageLoading, setUsageLoading] = useState(true);\n const [usageError, setUsageError] = useState<unknown>(null);\n const [usage, setUsage] = useState<UsageMetrics | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n setUsageLoading(true);\n setUsageError(null);\n\n const { start, end } = presetToDateRange(period);\n const startDate = toLocalDay(start);\n const endDate = toLocalDay(end);\n\n api.getUsage(startDate, endDate)\n .then((usageResult) => {\n if (cancelled) return;\n setUsage(usageResult);\n setUsageLoading(false);\n })\n .catch((err) => {\n if (!cancelled) {\n setUsageError(err);\n setUsage(null);\n setUsageLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [api, period]);\n\n const viewState = useMemo(\n () => widgetViewState({\n loading: profileLoading || usageLoading,\n error: profileError,\n userInfo,\n usageError,\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [profileLoading, usageLoading, profileError, userInfo, usageError, keys],\n );\n\n const Wrapper: ElementType = bare ? Box : Paper;\n const partialFailure = !usageLoading && usageError && usage;\n\n const dailyData = (usage?.daily_usage ?? []).map(d => ({\n date: d.date,\n spend: d.spend,\n }));\n\n const hasSparkline = dailyData.length > 0;\n\n const { start, end } = presetToDateRange(period);\n const startDate = toLocalDay(start);\n const endDate = toLocalDay(end);\n const dateRangeCaption = rangeCaption(startDate, endDate);\n const sparklineAriaLabelText = sparklineAriaLabel(dailyData);\n\n return (\n <Wrapper sx={bare ? { height: '100%' } : { p: 2, height: '100%' }}>\n {/* Card header */}\n <Box display=\"flex\" justifyContent={bare ? 'flex-end' : 'space-between'} alignItems=\"center\" mb={1.5}>\n {!bare && <Typography variant=\"h6\">{title}</Typography>}\n <FormControl size=\"small\" sx={{ minWidth: 90 }}>\n <Select\n value={period}\n onChange={e => setPeriod(e.target.value as DatePreset)}\n displayEmpty\n inputProps={{ 'aria-label': 'Usage period' }}\n >\n <MenuItem value=\"today\">Today</MenuItem>\n <MenuItem value=\"7d\">7d</MenuItem>\n <MenuItem value=\"30d\">30d</MenuItem>\n </Select>\n </FormControl>\n </Box>\n\n {/* Loading state */}\n {viewState.kind === 'loading' && (\n <Box sx={{ minHeight: 120 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={20} sx={{ mb: 1 }} />\n <Skeleton variant=\"rectangular\" width=\"100%\" height={100} />\n </Box>\n )}\n\n {/* Error state */}\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {viewState.message}\n </Typography>\n )}\n\n {/* Unprovisioned state */}\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {/* Content */}\n {viewState.kind === 'ready' && partialFailure && (\n <Box sx={{ mt: 1, mb: 1, p: 1, backgroundColor: 'action.hover', borderRadius: 1 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {USAGE_UNAVAILABLE_MSG}\n </Typography>\n </Box>\n )}\n\n {viewState.kind === 'ready' && (\n <>\n {/* Summary line */}\n <Typography\n variant=\"body2\"\n sx={{\n fontWeight: 500,\n mb: hasSparkline ? 1.5 : 1,\n color: viewState.usageUnavailable ? 'text.secondary' : 'text.primary',\n }}\n >\n {viewState.usageUnavailable ? USAGE_UNAVAILABLE_MSG : usageSummary(usage)}\n </Typography>\n\n {/* Sparkline with caption */}\n {hasSparkline && !viewState.usageUnavailable && (\n <>\n <Box\n height={80}\n role=\"img\"\n aria-label={sparklineAriaLabelText}\n sx={{ mb: 0.5 }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <XAxis dataKey=\"date\" hide />\n <Tooltip content={<ChartTooltip valueFormatter={fmtUsd} />} />\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n fill={SERIES.spend}\n fillOpacity={0.3}\n dot={false}\n isAnimationActive={false}\n />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 1 }}>\n daily spend ({dateRangeCaption})\n </Typography>\n </>\n )}\n\n {/* Footer link */}\n {moduleRouteRef?.() && (\n <Typography variant=\"caption\" sx={{ mt: 1, display: 'block' }}>\n <Link to={moduleRouteRef()} color=\"primary\">\n Open LiteLLM \u2192\n </Link>\n </Typography>\n )}\n </>\n )}\n </Wrapper>\n );\n};\n", "import { fmtUsd } from './format';\nimport { fmtCompact, fmtDateShort } from './components/ui/tokens';\nimport { toLocalDay } from './dates';\nimport type { UsageMetrics } from './types';\n\n/**\n * Build a human-readable date range caption from two YYYY-MM-DD strings.\n * Example: '2026-09-01', '2026-09-29' \u2192 'Sep 1 \u2013 Sep 29'\n */\nexport function rangeCaption(startDay: string, endDay: string): string {\n return `${fmtDateShort(startDay)} \u2013 ${fmtDateShort(endDay)}`;\n}\n\n/**\n * Build a month-to-date range caption from a Date.\n * Example: new Date('2026-09-29') \u2192 'Sep 1 \u2013 29'\n * Handles same-day (returns date twice) and month/year edge cases.\n */\nexport function mtdCaption(now: Date = new Date()): string {\n const year = now.getFullYear();\n const month = now.getMonth();\n const day = now.getDate();\n const startDay = `${year}-${String(month + 1).padStart(2, '0')}-01`;\n const endDay = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n return rangeCaption(startDay, endDay);\n}\n\n/**\n * Build an aria-label summary for a sparkline chart showing daily spend data.\n * Includes total spend, peak value, and the date it occurred.\n * Example: 'Daily spend over 7 days, total $129.90, peak $41.20 on Sep 27'\n */\nexport function sparklineAriaLabel(points: Array<{ date: string; spend: number }>): string {\n if (!points || points.length === 0) {\n return 'No daily spend data';\n }\n\n const total = points.reduce((sum, p) => sum + p.spend, 0);\n const maxPoint = points.reduce(\n (max, p) => (p.spend > max.spend ? p : max),\n points[0],\n );\n\n const dayCount = points.length;\n const peakDate = fmtDateShort(maxPoint.date);\n\n return `Daily spend over ${dayCount} day${dayCount === 1 ? '' : 's'}, total ${fmtUsd(total)}, peak ${fmtUsd(maxPoint.spend)} on ${peakDate}`;\n}\n\n/**\n * Spend recorded on the local calendar day `now` (defaults to today) in a\n * daily-spend series. Days the API omits count as zero \u2014 no spend recorded\n * yet \u2014 so a chart that simply hasn't seen a request today still answers\n * `$0.00` instead of `undefined`.\n *\n * `now` is overridable so the same helper yields yesterday's figure\n * (`spendOnDay(points, yesterday)`) for a day-over-day hint.\n */\nexport function spendOnDay(\n points: Array<{ date: string; spend: number }>,\n now: Date = new Date(),\n): number {\n const day = toLocalDay(now);\n return points.find(p => p.date === day)?.spend ?? 0;\n}\n\n/**\n * Format usage metrics as a single summary line: '$X spent \u00B7 YM in \u00B7 ZM out'\n * Handles zero usage and undefined values gracefully.\n */\nexport function usageSummary(usage: UsageMetrics | null | undefined): string {\n if (!usage) {\n return '$0.00 spent \u00B7 0 in \u00B7 0 out';\n }\n\n const spent = fmtUsd(usage.total_spend ?? 0);\n const tokenIn = fmtCompact(usage.prompt_tokens ?? 0);\n const tokenOut = fmtCompact(usage.completion_tokens ?? 0);\n\n return `${spent} spent \u00B7 ${tokenIn} in \u00B7 ${tokenOut} out`;\n}\n\n/**\n * Build ARIA attributes for a meter component showing a percentage value.\n * When value > 100%, sets aria-valuetext to include \"over cap\" warning.\n * Returns an object with role, aria-valuenow, aria-valuemin, aria-valuemax,\n * aria-label, and optionally aria-valuetext.\n */\nexport function meterAria(\n pct: number,\n label?: string,\n): {\n role: string;\n 'aria-valuenow': number;\n 'aria-valuemin': number;\n 'aria-valuemax': number;\n 'aria-label'?: string;\n 'aria-valuetext'?: string;\n} {\n const attrs: ReturnType<typeof meterAria> = {\n role: 'meter',\n 'aria-valuenow': Math.max(0, Math.min(100, pct)),\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n };\n\n if (label) {\n attrs['aria-label'] = label;\n }\n\n if (pct > 100) {\n attrs['aria-valuetext'] = `${Math.round(pct)}% \u2014 over cap`;\n }\n\n return attrs;\n}\n", "/**\n * Condensed budget card for a homepage column: spend KPIs on one line,\n * one inline row per enforcement level (key \u2192 personal \u2192 team), and a\n * month-to-date daily spend strip, in a fixed card that never reflows.\n *\n * The card is deliberately *row*-shaped rather than four side-by-side\n * columns: a four-column grid lets one long key alias widen its track (a\n * `1fr` track is only as narrow as its widest unbreakable content) and lets\n * each column wrap its own number of caption lines, so the text under the\n * rings drifts out of alignment. Rows share three fixed tracks \u2014 ring,\n * flexible name, right-aligned amount \u2014 so every figure is in the same\n * place and tabular numerals line up, and a long name ellipsizes inside\n * `minmax(0, 1fr)` instead of stretching anything.\n *\n * Each row shows the limit nearest its cap at that level: the ring carries\n * the percentage, the middle track the level tag, limit name and a short\n * note (over cap, a `+N more` link, or the key id / email), and the right\n * track the spend-vs-cap dollars over the reset window \u2014 one caption per\n * fact, so the reset window is never printed twice in a row. Where the full `LiteLLMBudgetWidget` lists every limit as a\n * meter card, this trades detail for density. Gauges are always rendered in\n * the same order, with an empty ring when the user has no cap at that\n * level, so the card keeps a stable shape as data loads and across users.\n *\n * Above the rows sit two inline KPIs \u2014 **today spent** (with a\n * day-over-day hint) and month-to-date spend \u2014 both derived from the same\n * month-to-date usage call, so the indicator costs no extra request. The\n * usage period is frozen to month-to-date (no period selector): the chart\n * always covers the 1st of the current month through today.\n *\n * The bottom action bar is composable: pass any subset of `ctas` \u2014 generate\n * a new key, open the LiteLLM module, or expand the full per-limit list in\n * place \u2014 in the order you want. `action` remains an escape hatch for a\n * fully custom node; when either is present it renders below a divider. The\n * `new-key` CTA renders the shared `GenerateKeyButton`, identical to the\n * one on the plugin page.\n */\nimport { ElementType, FC, ReactNode, useCallback, useEffect, useId, useMemo, useState } from 'react';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport { useTheme } from '@mui/material/styles';\nimport useMediaQuery from '@mui/material/useMediaQuery';\nimport { ExpandMore } from '@mui/icons-material';\nimport { AreaChart, Area, ResponsiveContainer, Tooltip, ReferenceLine, XAxis } from 'recharts';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { liteLlmApiRef } from '../api';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { fmtUsd } from '../format';\nimport { monthToDateRange, toLocalDay } from '../dates';\nimport { resolveCtas, type BudgetCtaKind, type BudgetCtaSpec, type BudgetCta } from '../ctas';\nimport { widgetViewState, USAGE_UNAVAILABLE_MSG, UNPROVISIONED_MSG } from '../widgetState';\nimport { Gauge, StatusPill, ChartTooltip, SERIES, toneColor, type Tone } from './ui';\nimport { GenerateKeyButton } from './GenerateKeyButton';\nimport { BudgetLimitList, LimitListPanel } from './BudgetLimitList';\nimport {\n allBudgetLimits,\n buildBudgetGauges,\n buildBudgetSummary,\n budgetHeadline,\n BudgetGauge,\n BudgetLimit,\n budgetTone,\n fmtBudgetDuration,\n} from '../budget';\nimport { rootRouteRef } from '../routes';\nimport { mtdCaption, sparklineAriaLabel, spendOnDay } from '../homeWidgetHelpers';\n\nexport type { BudgetCtaKind, BudgetCtaSpec, BudgetCta } from '../ctas';\n\nexport interface LiteLLMBudgetGaugesProps {\n /** Optional title override. Defaults to 'Budget'. */\n title?: string;\n /**\n * Render without the card's own chrome and title, for hosts (such as the\n * home page grid) that already provide a titled card. Defaults to false.\n */\n bare?: boolean;\n /** Ring diameter in px. Defaults to 56. */\n size?: number;\n /** Where the \"+N more\" key link points. Defaults to the Keys tab. */\n keysHref?: string;\n /** Where the module CTA points. Defaults to the LiteLLM page. */\n moduleHref?: string;\n /**\n * Called when the \"Generate New Key\" CTA is used. When omitted, the CTA\n * deep-links to the module with `?generate=1`, which opens the\n * generate-key dialog.\n */\n onCreateKey?: () => void;\n /**\n * Action-bar buttons to render, in order. Defaults to\n * `['module', 'all-limits']`; 'new-key' is added automatically for users with no keys. Pass `[]` to hide the bar; the\n * `all-limits` entry is dropped automatically when the user has no limits.\n */\n ctas?: BudgetCta[];\n /** Max key limits listed in the expanded view. Defaults to 8. */\n maxExpandedKeys?: number;\n /** Controlled expanded state for the all-limits view. */\n expanded?: boolean;\n /** Initial expanded state when uncontrolled. Defaults to false. */\n defaultExpanded?: boolean;\n /** Notified whenever the expanded state changes. */\n onExpandedChange?: (expanded: boolean) => void;\n /** Fully custom node pinned below the CTAs, below a divider. */\n action?: ReactNode;\n /**\n * Optional preloaded data to use instead of fetching via the hook.\n * When provided, the component uses these values directly without refetching.\n */\n userInfo?: UserInfo | null;\n teams?: TeamInfo[];\n keys?: VirtualKey[];\n}\n\n/** One-word level names, and the note shown when the level has no cap. */\nconst LEVEL: Record<BudgetGauge['kind'], { name: string; none: string }> = {\n key: { name: 'Key', none: 'No cap (unlimited)' },\n user: { name: 'User', none: 'No personal budget' },\n team: { name: 'Team', none: 'No team budget' },\n};\n\nconst CTA_LABELS: Record<BudgetCtaKind, string> = {\n 'new-key': 'Generate New Key',\n module: 'Open LiteLLM',\n 'all-limits': 'All limits',\n};\n\n/** Compact USD for the tight budget caption \u2014 drops trailing cents. */\nfunction fmtUsdShort(n: number): string {\n const v = n ?? 0;\n if (v >= 100 && Number.isInteger(v)) return `$${v}`;\n return fmtUsd(v);\n}\n\n/** Budget caption: \"$213.39 / $240\", or a note when dollars are redacted. */\nfunction spendCaption(limit: BudgetLimit): string {\n if (limit.hidden) return 'hidden by admin';\n return `${fmtUsdShort(limit.spend)} / ${fmtUsdShort(limit.budget)}`;\n}\n\n/** Reset-window line under the amount: \"resets every 30 days\" / \"never resets\". */\nfunction resetLabel(limit: BudgetLimit): string {\n const window = fmtBudgetDuration(limit.budgetDuration);\n return window ? `resets ${window}` : 'never resets';\n}\n\n/** Uppercase micro-label used for levels, KPIs and the chart caption. */\nconst Tag: FC<{ children: ReactNode; tone?: Tone; title?: string }> = ({ children, tone, title }) => (\n <Typography\n title={title}\n sx={theme => ({\n fontSize: 10.5,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n lineHeight: 1.3,\n color: tone ? toneColor(theme, tone) : theme.palette.text.secondary,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n })}\n >\n {children}\n </Typography>\n);\n\n/**\n * One inline KPI: uppercase label over a tabular value with a quiet hint\n * underneath. Fixed three-line shape, so two of them sit side by side\n * without their baselines drifting apart.\n */\nconst InlineStat: FC<{\n label: string;\n value: string;\n hint?: string;\n tone?: Tone;\n title?: string;\n}> = ({ label, value, hint, tone = 'accent', title }) => (\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.625, minWidth: 0 }}>\n <Box\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, tone),\n flexShrink: 0,\n })}\n />\n <Tag>{label}</Tag>\n </Box>\n <Typography\n title={title}\n sx={{\n fontSize: 19,\n fontWeight: 700,\n lineHeight: 1.15,\n mt: 0.25,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {value}\n </Typography>\n {/* Fixed height so rows of stats stay aligned even with an empty hint. */}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n mt: 0.25,\n fontSize: 10.5,\n minHeight: 14,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {hint ?? ''}\n </Typography>\n </Box>\n);\n\n/**\n * One enforcement level as a single row: ring on the left, level tag +\n * limit name + a short note (over cap, \"+N more\", key id) in the flexible\n * middle, spend-vs-cap dollars over the reset window right-aligned in a\n * fixed track.\n */\nconst LevelRow: FC<{ gauge: BudgetGauge; size: number; keysHref?: string }> = ({\n gauge,\n size,\n keysHref,\n}) => {\n const { name, none } = LEVEL[gauge.kind];\n const limit = gauge.limit;\n const tone = limit ? budgetTone(limit.pct) : 'neutral';\n const extra = gauge.kind === 'key' ? Math.max(0, gauge.count - 1) : 0;\n const overCap = Boolean(limit && limit.pct > 100);\n\n /**\n * Third line of the middle track. The over-cap flag earns the slot first\n * (the reset window below already lives in the right track, so repeating it\n * here would print the same caption twice), then the \"+N more\" link, then\n * the identifying detail \u2014 key id, email, team slug.\n */\n const subNote = (): ReactNode => {\n if (overCap) return 'Over cap';\n if (extra > 0 && keysHref) {\n return (\n <Typography\n component={Link}\n to={keysHref}\n variant=\"caption\"\n sx={{\n fontSize: 10.5,\n color: 'primary.main',\n textDecoration: 'none',\n '&:hover': { textDecoration: 'underline' },\n }}\n >\n +{extra} more\n </Typography>\n );\n }\n return limit?.sublabel ?? null;\n };\n\n const gaugeAriaLabel = limit\n ? `${name} budget used: ${Math.round(limit.pct)}%`\n : `${name} \u2014 no cap`;\n\n return (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: 'auto minmax(0, 1fr) auto',\n alignItems: 'center',\n gap: 1.25,\n py: 0.75,\n minWidth: 0,\n }}\n >\n <Gauge\n value={limit?.pct ?? 0}\n tone={tone}\n size={size}\n label={limit ? `${Math.round(limit.pct)}%` : '\u2014'}\n ariaLabel={gaugeAriaLabel}\n />\n\n <Box sx={{ minWidth: 0 }}>\n {/* The default accent tone would colour every healthy row; only a\n warning or an over-cap limit earns a coloured level tag. */}\n <Tag tone={tone === 'warning' || tone === 'danger' ? tone : undefined}>{name}</Tag>\n {limit ? (\n <>\n <Typography\n variant=\"caption\"\n title={limit.sublabel ? `${limit.label} \u00B7 ${limit.sublabel}` : limit.label}\n sx={{\n display: 'block',\n fontSize: 11.5,\n fontWeight: 600,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {limit.label}\n </Typography>\n <Typography\n variant=\"caption\"\n color={overCap ? 'error' : 'text.secondary'}\n sx={{\n display: 'block',\n fontSize: 10.5,\n fontWeight: overCap ? 700 : undefined,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {subNote()}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n fontSize: 10.5,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {none}\n </Typography>\n )}\n </Box>\n\n <Box sx={{ minWidth: 0, textAlign: 'right' }}>\n <Typography\n title={limit ? `${fmtUsd(limit.spend)} of ${fmtUsd(limit.budget)}` : undefined}\n sx={{\n display: 'block',\n fontSize: 12.5,\n fontWeight: 600,\n lineHeight: 1.35,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: limit ? undefined : 'text.secondary',\n }}\n >\n {amountCaption(limit)}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n fontSize: 10.5,\n lineHeight: 1.35,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {amountNote(limit)}\n </Typography>\n </Box>\n </Box>\n );\n};\n\n/** Right-track amount: \"$213 / $240\", or just the percentage when hidden. */\nfunction amountCaption(limit?: BudgetLimit): string {\n if (!limit) return '';\n return limit.hidden ? `${Math.round(limit.pct)}%` : spendCaption(limit);\n}\n\n/** Second right-track line: the reset window, or why dollars are missing. */\nfunction amountNote(limit?: BudgetLimit): string {\n if (!limit) return '';\n return limit.hidden ? 'hidden by admin' : resetLabel(limit);\n}\n\ninterface DailySpend {\n date: string;\n spend: number;\n}\n\n/**\n * Full-width strip below the rows: a sparkline of daily spend (MTD) with\n * the month's total on the same caption line as the range, so the number,\n * the window and the chart read as one unit.\n */\nconst SpendStrip: FC<{\n data: DailySpend[];\n mtdSpend: number;\n loading: boolean;\n height: number;\n usageUnavailable?: boolean;\n maxBudget?: number;\n}> = ({ data, mtdSpend, loading, height, usageUnavailable = false, maxBudget }) => {\n const renderPlot = () => {\n if (loading) {\n return <Skeleton variant=\"rectangular\" width=\"100%\" height=\"100%\" />;\n }\n if (data.length === 0) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n height=\"100%\"\n sx={theme => ({ color: theme.palette.text.secondary, fontSize: 18 })}\n >\n \u2014\n </Box>\n );\n }\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={data} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <XAxis dataKey=\"date\" hide />\n <Tooltip content={<ChartTooltip valueFormatter={fmtUsd} />} />\n {maxBudget !== undefined && (\n <ReferenceLine\n y={maxBudget}\n stroke={SERIES.budget}\n strokeDasharray=\"4 4\"\n strokeWidth={1}\n />\n )}\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n strokeWidth={1.5}\n fill={SERIES.spend}\n fillOpacity={0.25}\n dot={false}\n isAnimationActive={false}\n />\n </AreaChart>\n </ResponsiveContainer>\n );\n };\n\n const caption = (() => {\n if (loading) return '\u2026';\n if (usageUnavailable) return USAGE_UNAVAILABLE_MSG;\n if (data.length === 0) return 'No spend this month';\n return mtdCaption();\n })();\n\n return (\n <Box role=\"img\" aria-label={sparklineAriaLabel(data)} sx={{ minWidth: 0 }}>\n <Box sx={{ height, width: '100%' }}>{renderPlot()}</Box>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'baseline',\n justifyContent: 'space-between',\n gap: 1,\n mt: 0.5,\n minWidth: 0,\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.75, minWidth: 0 }}>\n <Tag>Spent (mtd)</Tag>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: 10.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {caption}\n </Typography>\n </Box>\n <Typography\n title={loading || usageUnavailable ? undefined : `${fmtUsd(mtdSpend)} spent month to date`}\n sx={{\n fontSize: 12.5,\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n }}\n >\n {loading || usageUnavailable ? '\u2014' : fmtUsd(mtdSpend)}\n </Typography>\n </Box>\n </Box>\n );\n};\n\n/** KPI value while loading / unavailable: '\u2026' \u2192 '\u2014' \u2192 the figure. */\nfunction statValue(loading: boolean, unavailable: boolean, value: string): string {\n if (loading) return '\u2026';\n if (unavailable) return '\u2014';\n return value;\n}\n\n/** KPI hint under `statValue`: nothing while loading, the reason when unavailable. */\nfunction statHint(loading: boolean, unavailable: boolean, hint?: string): string | undefined {\n if (loading) return undefined;\n if (unavailable) return USAGE_UNAVAILABLE_MSG;\n return hint;\n}\n\n// monthToDateRange is imported from dates.ts above; re-export for backwards compatibility\nexport { monthToDateRange } from '../dates';\n\nexport const LiteLLMBudgetGauges: FC<LiteLLMBudgetGaugesProps> = ({\n title = 'Budget',\n bare = false,\n size = 56,\n keysHref,\n moduleHref: propModuleHref,\n onCreateKey,\n ctas,\n maxExpandedKeys = 8,\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n action,\n userInfo: propUserInfo,\n teams: propTeams,\n keys: propKeys,\n}) => {\n const api = useApi(liteLlmApiRef);\n const theme = useTheme();\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));\n const gaugeSize = isSmallScreen ? Math.min(48, size) : size;\n const expandedRegionId = useId();\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const moduleHref = propModuleHref ?? moduleRouteRef?.();\n const { userInfo: hookUserInfo, teams: hookTeams, keys: hookKeys, loading: profileLoading, error: profileError } = useLiteLLMProfile();\n const [usageLoading, setUsageLoading] = useState(true);\n const [usageError, setUsageError] = useState<string | null>(null);\n const [dailySpend, setDailySpend] = useState<DailySpend[]>([]);\n const [mtdSpend, setMtdSpend] = useState(0);\n\n // Use provided props if available, otherwise use hook data\n const user = propUserInfo !== undefined ? propUserInfo : hookUserInfo;\n const teams = propTeams !== undefined ? propTeams : hookTeams;\n const keys = propKeys !== undefined ? propKeys : hookKeys;\n\n // Combine loading states: if props are provided, only usage matters; otherwise both profile and usage\n const loading = propUserInfo === undefined ? profileLoading : usageLoading;\n const error = propUserInfo === undefined ? profileError : usageError;\n\n const isControlled = expanded !== undefined;\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultExpanded);\n const isExpanded = isControlled ? expanded! : uncontrolledExpanded;\n\n const toggleExpanded = useCallback(() => {\n const next = !isExpanded;\n if (!isControlled) setUncontrolledExpanded(next);\n onExpandedChange?.(next);\n }, [isControlled, isExpanded, onExpandedChange]);\n\n const keysTabHref = keysHref ?? (moduleHref ? `${moduleHref}?tab=keys` : undefined);\n\n useEffect(() => {\n let cancelled = false;\n setUsageLoading(true);\n setUsageError(null);\n // The usage chart is frozen to month-to-date \u2014 no period selector.\n const { startDate, endDate } = monthToDateRange();\n api.getUsage(startDate, endDate)\n .then((usageResult) => {\n if (cancelled) return;\n // Usage degrades independently: a failed usage fetch leaves the\n // gauges untouched and the chart strip renders its empty state.\n const daily = usageResult.daily_usage ?? [];\n setDailySpend(\n daily.map(d => ({\n date: d.date,\n spend: d.spend ?? 0,\n })),\n );\n setMtdSpend(usageResult.total_spend ?? 0);\n setUsageLoading(false);\n })\n .catch((err) => {\n if (!cancelled) {\n setUsageError(err?.message ?? 'Failed to load usage data');\n setDailySpend([]);\n setMtdSpend(0);\n setUsageLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [api]);\n\n // Keep every budgeted key so the nearest-per-level gauge is accurate even\n // beyond the full widget's display cap.\n const summary = useMemo(\n () => buildBudgetSummary(user, teams, keys, keys.length),\n [user, teams, keys],\n );\n const gauges = useMemo(() => buildBudgetGauges(summary), [summary]);\n const headline = useMemo(() => budgetHeadline(summary), [summary]);\n\n // Expanded view: every concrete limit, but cap the key entries so a user\n // with dozens of keys doesn't get an endless list.\n const expandedSummary = useMemo(\n () => buildBudgetSummary(user, teams, keys, maxExpandedKeys),\n [user, teams, keys, maxExpandedKeys],\n );\n const expandedLimits = useMemo(\n () => allBudgetLimits(expandedSummary),\n [expandedSummary],\n );\n\n // Determine the overall widget state\n const viewState = useMemo(\n () => widgetViewState({\n loading,\n error: profileError,\n userInfo: user,\n usageError,\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [loading, profileError, user, usageError, keys],\n );\n\n // Today's spend (and yesterday's, for the hint) come from the same\n // month-to-date series the chart already fetched \u2014 no extra request.\n const today = new Date();\n const todaySpend = spendOnDay(dailySpend, today);\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n // No yesterday point when the month started today \u2014 say nothing rather\n // than imply the user spent nothing.\n const yesterdaySpend = dailySpend.some(d => d.date === toLocalDay(yesterday))\n ? spendOnDay(dailySpend, yesterday)\n : null;\n const todayHint = yesterdaySpend === null ? undefined : `vs ${fmtUsd(yesterdaySpend)} yesterday`;\n\n const summaryText =\n headline.count === 0\n ? 'no limits apply'\n : `${headline.count} limit${headline.count === 1 ? '' : 's'}`;\n\n const resolvedCtas = useMemo<(BudgetCtaSpec & { kind: BudgetCtaKind })[]>(() => {\n return resolveCtas({\n ctas,\n hasKeys: (keys?.length ?? 0) > 0,\n viewState,\n limitCount: headline.count,\n });\n }, [ctas, keys?.length, viewState, headline.count]);\n\n const renderCta = (cta: BudgetCtaSpec & { kind: BudgetCtaKind }, index: number) => {\n const label = cta.label ?? CTA_LABELS[cta.kind];\n const key = `${cta.kind}-${index}`;\n switch (cta.kind) {\n case 'new-key':\n // The shared plugin-page CTA \u2014 identical copy, icon and styling\n // everywhere. Deep-links to the module's generate-key dialog unless\n // the host takes over with `onCreateKey`.\n if (!onCreateKey && !moduleHref) return null;\n return onCreateKey ? (\n <GenerateKeyButton key={key} size=\"small\" label={label} onClick={onCreateKey} />\n ) : (\n <GenerateKeyButton key={key} size=\"small\" label={label} to={`${moduleHref}?generate=1`} />\n );\n case 'module':\n // Hide if route is not mounted\n if (!moduleHref) return null;\n return (\n <Button key={key} size=\"small\" variant=\"text\" component={Link} to={moduleHref}>\n {label}\n </Button>\n );\n case 'all-limits':\n return (\n <Button\n key={key}\n size=\"small\"\n variant=\"text\"\n onClick={toggleExpanded}\n aria-expanded={isExpanded}\n aria-controls={expandedRegionId}\n endIcon={\n <ExpandMore\n sx={muiTheme => ({\n transform: isExpanded ? 'rotate(180deg)' : 'none',\n transition: muiTheme.transitions.create('transform'),\n })}\n />\n }\n >\n {label}\n </Button>\n );\n /* istanbul ignore next \u2014 exhaustiveness */\n default:\n return null;\n }\n };\n\n const hasFooter = resolvedCtas.length > 0 || !!action;\n\n const Wrapper: ElementType = bare ? Box : Paper;\n\n return (\n <Wrapper sx={bare ? { height: '100%' } : { p: 2, height: '100%' }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1.5, minWidth: 0, justifyContent: bare ? 'flex-end' : undefined }}>\n {!bare && (\n <Typography variant=\"h6\" lineHeight={1.2} sx={{ minWidth: 0, flex: 1 }}>\n {title}\n </Typography>\n )}\n {!loading && !error && (\n <StatusPill\n label={summaryText}\n tone={budgetTone(headline.closest?.pct ?? 0)}\n dot={headline.count > 0}\n />\n )}\n </Box>\n\n {viewState.kind === 'loading' && (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25, minHeight: size }}>\n {[0, 1, 2].map(i => (\n <Box key={i} sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>\n <Skeleton variant=\"circular\" width={size} height={size} />\n <Box sx={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"70%\" height={12} sx={{ mb: 0.25 }} />\n <Skeleton variant=\"text\" width=\"45%\" height={11} />\n </Box>\n <Skeleton variant=\"text\" width={64} height={12} />\n </Box>\n ))}\n </Box>\n )}\n\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {viewState.message}\n </Typography>\n )}\n\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {viewState.kind === 'ready' && (\n <>\n {/* Spend KPIs: today first, month-to-date second. */}\n <Box\n sx={{\n display: 'flex',\n alignItems: 'stretch',\n gap: 2,\n mb: 1.25,\n minWidth: 0,\n }}\n >\n <InlineStat\n label=\"Today spent\"\n tone=\"accent\"\n value={statValue(usageLoading, viewState.usageUnavailable, fmtUsd(todaySpend))}\n hint={statHint(usageLoading, viewState.usageUnavailable, todayHint)}\n title={usageLoading || viewState.usageUnavailable ? undefined : 'Spend since local midnight'}\n />\n <Box sx={{ width: '1px', bgcolor: 'divider', flexShrink: 0 }} />\n <InlineStat\n label=\"Month to date\"\n value={statValue(usageLoading, viewState.usageUnavailable, fmtUsd(mtdSpend))}\n hint={statHint(usageLoading, viewState.usageUnavailable, mtdCaption())}\n title={usageLoading || viewState.usageUnavailable ? undefined : 'Spend from the 1st of this month'}\n />\n </Box>\n\n {/* One row per enforcement level, hairline-separated. */}\n <Box sx={{ borderTop: '1px solid', borderColor: 'divider' }}>\n {gauges.map((gauge, i) => (\n <Box\n key={gauge.kind}\n sx={i === 0 ? undefined : { borderTop: '1px solid', borderColor: 'divider' }}\n >\n <LevelRow gauge={gauge} size={gaugeSize} keysHref={keysTabHref} />\n </Box>\n ))}\n </Box>\n\n <Box sx={{ mt: 1.25 }}>\n <SpendStrip\n data={dailySpend}\n mtdSpend={mtdSpend}\n loading={usageLoading}\n height={gaugeSize}\n usageUnavailable={viewState.usageUnavailable}\n maxBudget={user?.max_budget ?? undefined}\n />\n </Box>\n\n <Collapse in={isExpanded} unmountOnExit>\n <Box\n id={expandedRegionId}\n sx={{\n mt: 1.5,\n // Bound the expanded list so a user with many limits still\n // keeps the card compact and the toggle within reach.\n maxHeight: 300,\n overflowY: 'auto',\n }}\n >\n <LimitListPanel>\n <BudgetLimitList\n limits={expandedLimits}\n hiddenKeyCount={expandedSummary.hiddenBudgetedKeys}\n keysHref={keysTabHref}\n />\n </LimitListPanel>\n </Box>\n </Collapse>\n </>\n )}\n\n {hasFooter && (\n <Box\n sx={muiTheme => ({\n mt: 2,\n pt: 2,\n borderTop: `1px solid ${muiTheme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n flexWrap: 'wrap',\n })}\n >\n {resolvedCtas.map(renderCta)}\n {action}\n </Box>\n )}\n </Wrapper>\n );\n};\n", "/** Preset action-bar buttons. `label` overrides the default copy. */\nexport type BudgetCtaKind = 'new-key' | 'module' | 'all-limits';\nexport interface BudgetCtaSpec {\n kind: BudgetCtaKind;\n /** Override the default label. */\n label?: string;\n}\n/** Either a bare kind (`'module'`) or a spec object (`{ kind: 'module' }`). */\nexport type BudgetCta = BudgetCtaKind | BudgetCtaSpec;\n\nexport const DEFAULT_CTAS: BudgetCtaKind[] = ['module', 'all-limits'];\n\n/**\n * Resolves which action-bar buttons to render.\n *\n * - `new-key` is shown when explicitly listed, or automatically (first) when\n * the user has no keys yet \u2014 but never while loading or when the profile\n * errored / the user isn't provisioned (a generate flow would fail).\n * - `all-limits` is dropped when there are no limits to expand.\n */\nexport function resolveCtas(spec: {\n ctas?: BudgetCta[];\n hasKeys: boolean;\n viewState: { kind: string };\n limitCount: number;\n}): Array<BudgetCtaSpec & { kind: BudgetCtaKind }> {\n const list = (spec.ctas ?? DEFAULT_CTAS).map(cta =>\n typeof cta === 'string' ? { kind: cta } : cta,\n );\n const canGenerate = spec.viewState.kind === 'ready';\n const out = list.filter(cta => {\n if (cta.kind === 'new-key') return canGenerate;\n if (cta.kind === 'all-limits') return spec.limitCount > 0;\n return true;\n });\n if (\n spec.ctas === undefined &&\n !spec.hasKeys &&\n canGenerate &&\n !out.some(c => c.kind === 'new-key')\n ) {\n out.unshift({ kind: 'new-key' });\n }\n return out;\n}\n", "import { FC } from 'react';\nimport { GenerateKeyRequest, GenerateKeyResponse, LiteLlmConfig, ModelInfo, TeamInfo, VirtualKey } from '../types';\nimport { KeyFormDialog } from './KeyFormDialog';\n\n/**\n * @deprecated Use {@link KeyFormDialog} with `mode=\"create\"` instead \u2014 this\n * wrapper only forwards props for backwards compatibility with the public\n * entrypoint and will be removed in a future release.\n */\nexport const GenerateKeyDialog: FC<{\n open: boolean;\n onClose: () => void;\n keys: VirtualKey[];\n models: ModelInfo[];\n teams: TeamInfo[];\n username?: string;\n keyGenerationSettings?: { allowUnlimitedBudget: boolean; teamRequired: boolean };\n onGenerateKey: (request: GenerateKeyRequest) => Promise<GenerateKeyResponse>;\n onGetConfig: () => Promise<LiteLlmConfig>;\n}> = props => (\n <KeyFormDialog\n open={props.open}\n onClose={props.onClose}\n mode=\"create\"\n keys={props.keys}\n models={props.models}\n teams={props.teams}\n username={props.username}\n keyGenerationSettings={props.keyGenerationSettings}\n onCreateKey={props.onGenerateKey}\n onUpdateKey={async () => {}}\n onGetConfig={props.onGetConfig}\n />\n);"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_frontend_plugin_api", "Paper", "Typography", "Box", "import_Box", "import_styles", "import_jsx_runtime", "Box", "Box", "ButtonBase", "import_Box", "import_Paper", "import_Typography", "import_styles", "import_jsx_runtime", "Paper", "Typography", "import_Box", "import_styles", "import_jsx_runtime", "Box", "import_Box", "import_Typography", "import_styles", "import_jsx_runtime", "Box", "Typography", "import_jsx_runtime", "Button", "import_Box", "import_Typography", "import_Paper", "import_ButtonBase", "import_styles", "import_jsx_runtime", "Box", "Typography", "ButtonBase", "Paper", "Skeleton", "Divider", "import_react", "import_core_plugin_api", "import_react", "import_core_plugin_api", "Typography", "CircularProgress", "Box", "import_react", "import_Button", "import_Box", "import_Typography", "import_Skeleton", "import_styles", "import_icons_material", "import_jsx_runtime", "TableRow", "TableCell", "Skeleton", "Tooltip", "IconButton", "TextField", "InputAdornment", "Button", "Chip", "TableContainer", "Table", "TableHead", "TableSortLabel", "TableBody", "Dialog", "DialogTitle", "DialogContent", "DialogActions", "import_backstage_plugin_litellm_common", "import_react", "import_Box", "import_Typography", "import_IconButton", "import_Tooltip", "import_icons_material", "import_jsx_runtime", "Box", "Tabs", "Tab", "Typography", "Tooltip", "IconButton", "import_react", "import_Box", "import_Typography", "import_Dialog", "import_DialogTitle", "import_DialogContent", "import_DialogActions", "import_TextField", "import_Button", "import_IconButton", "import_CircularProgress", "import_Tooltip", "import_InputAdornment", "import_Chip", "import_icons_material", "import_plugin_permission_react", "import_backstage_plugin_litellm_common", "import_jsx_runtime", "Box", "Chip", "Typography", "Autocomplete", "TextField", "Button", "CircularProgress", "Dialog", "DialogTitle", "DialogContent", "Alert", "Tooltip", "IconButton", "FormControlLabel", "Checkbox", "InputAdornment", "MenuItem", "Accordion", "AccordionSummary", "AccordionDetails", "DialogActions", "import_react", "import_Dialog", "import_DialogTitle", "import_DialogContent", "import_DialogActions", "import_TextField", "import_Button", "import_Alert", "import_Checkbox", "import_FormControlLabel", "import_Autocomplete", "import_CircularProgress", "import_MenuItem", "import_Box", "import_Divider", "import_Typography", "import_IconButton", "import_Tooltip", "import_Paper", "import_Table", "import_TableBody", "import_TableCell", "import_TableContainer", "import_TableHead", "import_TableRow", "import_icons_material", "import_core_plugin_api", "import_jsx_runtime", "Dialog", "DialogTitle", "DialogContent", "Alert", "
|
|
3
|
+
"sources": ["../src/profileCache.ts", "../src/api.ts", "../src/routes.ts", "../src/components/ui/tokens.tsx", "../src/components/ui/charts.tsx", "../src/components/ui/pills.tsx", "../src/components/ui/surfaces.tsx", "../src/components/ui/Meter.tsx", "../src/components/ui/Gauge.tsx", "../src/components/ui/index.ts", "../src/components/GenerateKeyButton.tsx", "../src/components/DashboardHeader.tsx", "../src/hooks/useCopyToClipboard.ts", "../src/hooks/useLiteLLMProfile.ts", "../src/hooks/index.ts", "../src/keyLabels.ts", "../src/format.ts", "../src/keyFilter.ts", "../src/components/KeysTable.tsx", "../src/keyFormValidation.ts", "../src/components/keyFormHelpers.ts", "../src/components/KeySnippets.tsx", "../src/components/KeyFormDialog.tsx", "../src/components/ManageTeamDialog.tsx", "../src/budget.ts", "../src/components/UsageStats.tsx", "../src/widgetState.ts", "../src/components/BudgetLimitList.tsx", "../src/routeHelpers.ts", "../src/components/LiteLLMBudgetWidget.tsx", "../src/components/TeamUsage.tsx", "../src/components/ModelsTable.tsx", "../src/components/AuditLog.tsx", "../src/dates.ts", "../src/feedback.ts", "../src/teamMemberManager.ts", "../src/unprovisionedCopy.ts", "../src/components/LiteLLMPage.tsx", "../src/index.ts", "../src/plugin.tsx", "../src/components/LiteLLMHomeWidget.tsx", "../src/homeWidgetHelpers.ts", "../src/components/LiteLLMBudgetGauges.tsx", "../src/ctas.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * A per-API-instance promise cache with TTL and single-flight deduplication.\n * Used to memoize the profile hook's result and reduce redundant fetches.\n *\n * Each API instance gets its own cache entry; entries expire after a TTL.\n * Concurrent callers for the same key within the TTL share a single promise\n * and wait for its result rather than issuing parallel requests.\n *\n * Injectable clock for testing.\n */\n\nimport { LiteLlmApiInterface } from './api';\n\nexport interface Clock {\n now(): number;\n}\n\nexport const systemClock: Clock = {\n now: () => Date.now(),\n};\n\nexport interface ProfileCacheEntry {\n result: unknown;\n timestamp: number;\n}\n\n/**\n * Inflight tracker for single-flight deduplication.\n * Maps a key \u2192 a promise that resolves when the fetch completes.\n */\ninterface InflightEntry {\n promise: Promise<unknown>;\n resolveTime: number;\n}\n\nexport class ProfileCache {\n private cache = new WeakMap<LiteLlmApiInterface, Record<string, ProfileCacheEntry>>();\n private inflight = new WeakMap<LiteLlmApiInterface, Record<string, InflightEntry>>();\n private ttlMs: number;\n private clock: Clock;\n\n constructor(ttlMs: number = 30_000, clock: Clock = systemClock) {\n this.ttlMs = ttlMs;\n this.clock = clock;\n }\n\n /**\n * Fetch or return a cached value. If a concurrent call with the same key\n * is in-flight, wait for it rather than issuing a parallel request.\n *\n * @param api The API instance (cache is scoped to it).\n * @param key A string key for the result (e.g., 'profile' or a team ID).\n * @param fetcher A thunk that returns the value to cache.\n * @returns The cached value (hit or miss) or the result of fetcher().\n */\n async memoize<T>(\n api: LiteLlmApiInterface,\n key: string,\n fetcher: () => Promise<T>,\n ): Promise<T> {\n const now = this.clock.now();\n\n // Check if there's a valid cached entry.\n const cached = this.cache.get(api)?.[key];\n if (cached && now - cached.timestamp < this.ttlMs) {\n return cached.result as T;\n }\n\n // Check if there's an inflight promise we can reuse (but not if it failed).\n const inflight = this.inflight.get(api)?.[key];\n if (inflight && now - inflight.resolveTime < this.ttlMs) {\n return inflight.promise as Promise<T>;\n }\n\n // Fetch and cache, with single-flight protection.\n // Errors are not cached, so each retry fetches fresh.\n const promise = fetcher()\n .then(result => {\n // Cache the successful result.\n if (!this.cache.has(api)) this.cache.set(api, {});\n this.cache.get(api)![key] = { result, timestamp: this.clock.now() };\n return result;\n })\n .catch(err => {\n // Don't cache failures; remove the inflight entry so the next call retries.\n const inflightEntries = this.inflight.get(api);\n if (inflightEntries) {\n delete inflightEntries[key];\n }\n throw err;\n });\n\n // Track the inflight request.\n if (!this.inflight.has(api)) this.inflight.set(api, {});\n this.inflight.get(api)![key] = { promise, resolveTime: this.clock.now() };\n\n return promise as Promise<T>;\n }\n\n /**\n * Invalidate all cached entries for an API instance, including inflight requests.\n */\n invalidate(api: LiteLlmApiInterface): void {\n this.cache.delete(api);\n this.inflight.delete(api);\n }\n\n /**\n * Invalidate every profile entry (`profile`, `profile-userInfo`,\n * `profile-keys`, ...) and its in-flight promise, leaving unrelated keys alone.\n */\n invalidateProfile(api: LiteLlmApiInterface): void {\n const isProfileKey = (k: string) => k === 'profile' || k.startsWith('profile-');\n for (const store of [this.cache.get(api), this.inflight.get(api)]) {\n if (!store) continue;\n for (const k of Object.keys(store)) {\n if (isProfileKey(k)) delete store[k];\n }\n }\n }\n}\n\n// Singleton cache instance shared by all hooks using the same API ref.\nexport const profileCacheInstance = new ProfileCache();\n", "import { createApiRef, type FetchApi, type DiscoveryApi } from '@backstage/frontend-plugin-api';\nimport {\n UserInfo,\n VirtualKey,\n ModelInfo,\n UsageMetrics,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n UpdateKeyRequest,\n AuditLogsParams,\n PaginatedAuditLogs,\n LiteLlmConfig,\n VectorStoreInfo,\n McpServerInfo,\n CreateTeamRequest,\n CreateTeamResponse,\n UpdateTeamRequest,\n} from './types';\nimport { profileCacheInstance } from './profileCache';\n\nexport class ApiError extends Error {\n body: unknown;\n status: number;\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n\nexport interface LiteLlmApiInterface {\n getUserInfo(): Promise<UserInfo>;\n listKeys(): Promise<VirtualKey[]>;\n generateKey(request: GenerateKeyRequest): Promise<GenerateKeyResponse>;\n updateKey(keyId: string, request: UpdateKeyRequest): Promise<VirtualKey>;\n deleteKey(keyId: string): Promise<{ success: boolean }>;\n blockKey(keyId: string): Promise<void>;\n unblockKey(keyId: string): Promise<void>;\n resetKeySpend(keyId: string): Promise<void>;\n pruneExpiredKeys(): Promise<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }>;\n listModels(): Promise<ModelInfo[]>;\n getTeams(): Promise<TeamInfo[]>;\n getManagedTeams(): Promise<TeamInfo[]>;\n addTeamMember(\n teamId: string,\n body: { userEntityRef: string; maxBudgetInTeam?: number },\n ): Promise<TeamInfo>;\n removeTeamMember(teamId: string, userEntityRef: string): Promise<TeamInfo>;\n getVectorStores(): Promise<VectorStoreInfo[]>;\n setTeamKnowledgeBases(teamId: string, vectorStores: string[]): Promise<TeamInfo>;\n getMcpServers(): Promise<McpServerInfo[]>;\n setTeamMcpServers(teamId: string, mcpServers: string[]): Promise<TeamInfo>;\n getUsage(startDate: string, endDate: string): Promise<UsageMetrics>;\n getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics>;\n getAuditLogs(params: AuditLogsParams): Promise<PaginatedAuditLogs>;\n getConfig(): Promise<LiteLlmConfig>;\n createTeam(request: CreateTeamRequest): Promise<CreateTeamResponse>;\n updateTeam(teamId: string, request: UpdateTeamRequest): Promise<TeamInfo>;\n}\n\nexport const liteLlmApiRef = createApiRef<LiteLlmApiInterface>({\n id: 'plugin.litellm.api',\n});\n\nexport type ExpiryStatus = 'expired' | 'soon' | 'ok';\n\nexport function expiryStatus(expiresAt?: string): ExpiryStatus | null {\n if (!expiresAt) return null;\n const diff = new Date(expiresAt).getTime() - Date.now();\n const days = diff / (1000 * 60 * 60 * 24);\n if (days < 0) return 'expired';\n if (days < 7) return 'soon';\n return 'ok';\n}\n\nexport class LiteLlmApi implements LiteLlmApiInterface {\n private fetchApi: FetchApi;\n private base: string | DiscoveryApi;\n\n /**\n * @param base A DiscoveryApi (the plugin base URL is resolved per request via\n * `discoveryApi.getBaseUrl('litellm')`) or a fixed base URL/path string.\n */\n constructor(fetchApi: FetchApi, base: string | DiscoveryApi = '/api/litellm') {\n this.fetchApi = fetchApi;\n this.base = base;\n }\n\n private async basePath(): Promise<string> {\n return typeof this.base === 'string'\n ? this.base\n : this.base.getBaseUrl('litellm');\n }\n\n private async throwIfNotOk(response: Response): Promise<void> {\n if (!response.ok) {\n let body: unknown;\n try { body = await response.json(); } catch { body = await response.text().catch(() => ''); }\n const errorText =\n typeof body === 'object' && body && typeof (body as any).error === 'string'\n ? (body as any).error\n : undefined;\n // Validation failures carry the reason in `details` (\"max_budget: must not\n // exceed 100\"); without it the user would only see \"Invalid request body\".\n const details =\n typeof body === 'object' && body && typeof (body as any).details === 'string'\n ? (body as any).details\n : undefined;\n let message = `${response.status} ${response.statusText}`;\n if (errorText) {\n message = details ? `${errorText}: ${details}` : errorText;\n }\n throw new ApiError(message, response.status, body);\n }\n }\n\n private async get<T>(path: string, params?: Record<string, string>): Promise<T> {\n const url = new URL(`${await this.basePath()}${path}`, window.location.origin);\n if (params) {\n Object.entries(params).forEach(([key, value]) => url.searchParams.append(key, value));\n }\n const response = await this.fetchApi.fetch(url.toString());\n await this.throwIfNotOk(response);\n return response.json();\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async del<T>(path: string): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'DELETE',\n headers: { 'Content-Type': 'application/json' },\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async patch<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n private async put<T>(path: string, body: unknown): Promise<T> {\n const response = await this.fetchApi.fetch(`${await this.basePath()}${path}`, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n });\n await this.throwIfNotOk(response);\n // Any successful write can change the profile (budget, keys, teams).\n profileCacheInstance.invalidateProfile(this);\n return response.json();\n }\n\n // User identity is resolved server-side from the Backstage Bearer token.\n // No user_id param needed on the frontend.\n async getUserInfo(): Promise<UserInfo> {\n return this.get<UserInfo>('/user/info');\n }\n\n async listKeys(): Promise<VirtualKey[]> {\n return this.get<VirtualKey[]>('/keys');\n }\n\n async generateKey(request: GenerateKeyRequest): Promise<GenerateKeyResponse> {\n return this.post<GenerateKeyResponse>('/keys/generate', request);\n }\n\n async updateKey(keyId: string, request: UpdateKeyRequest): Promise<VirtualKey> {\n return this.post<VirtualKey>(`/keys/${encodeURIComponent(keyId)}/update`, request);\n }\n\n async deleteKey(keyId: string): Promise<{ success: boolean }> {\n return this.del<{ success: boolean }>(`/keys/${encodeURIComponent(keyId)}`);\n }\n\n async blockKey(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/block`, {});\n }\n\n async unblockKey(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/unblock`, {});\n }\n\n async resetKeySpend(keyId: string): Promise<void> {\n await this.post(`/keys/${encodeURIComponent(keyId)}/reset_spend`, {});\n }\n\n async pruneExpiredKeys(): Promise<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }> {\n return this.post<{ pruned: number; failed: number; failures?: { keyId: string; error: string }[] }>(\n '/keys/prune-expired',\n {},\n );\n }\n\n async getAuditLogs(params: AuditLogsParams): Promise<PaginatedAuditLogs> {\n const strParams: Record<string, string> = {};\n if (params.page !== undefined) strParams.page = String(params.page);\n if (params.page_size !== undefined) strParams.page_size = String(params.page_size);\n if (params.start_date) strParams.start_date = params.start_date;\n if (params.end_date) strParams.end_date = params.end_date;\n if (params.action) strParams.action = params.action;\n if (params.table_name) strParams.table_name = params.table_name;\n if (params.changed_by) strParams.changed_by = params.changed_by;\n return this.get<PaginatedAuditLogs>('/audit', strParams);\n }\n\n async listModels(): Promise<ModelInfo[]> {\n return this.get<ModelInfo[]>('/models');\n }\n\n async getTeams(): Promise<TeamInfo[]> {\n return this.get<TeamInfo[]>('/teams');\n }\n\n // Teams whose owning_group the caller administers (server-scoped). Distinct\n // from getTeams(), which returns only the teams the caller is a member of.\n async getManagedTeams(): Promise<TeamInfo[]> {\n return this.get<TeamInfo[]>('/teams/managed');\n }\n\n async addTeamMember(\n teamId: string,\n body: { userEntityRef: string; maxBudgetInTeam?: number },\n ): Promise<TeamInfo> {\n return this.post<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/members`,\n body,\n );\n }\n\n async removeTeamMember(\n teamId: string,\n userEntityRef: string,\n ): Promise<TeamInfo> {\n return this.del<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/members?userEntityRef=${encodeURIComponent(\n userEntityRef,\n )}`,\n );\n }\n\n // Vector stores (knowledge bases) the caller may attach \u2014 already filtered\n // server-side to the operator's allowlist.\n async getVectorStores(): Promise<VectorStoreInfo[]> {\n return this.get<VectorStoreInfo[]>('/vector-stores');\n }\n\n async setTeamKnowledgeBases(\n teamId: string,\n vectorStores: string[],\n ): Promise<TeamInfo> {\n return this.put<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/knowledge-bases`,\n { vector_stores: vectorStores },\n );\n }\n\n async getMcpServers(): Promise<McpServerInfo[]> {\n return this.get<McpServerInfo[]>('/mcp-servers');\n }\n\n async setTeamMcpServers(\n teamId: string,\n mcpServers: string[],\n ): Promise<TeamInfo> {\n return this.put<TeamInfo>(\n `/teams/${encodeURIComponent(teamId)}/mcp-servers`,\n { mcp_servers: mcpServers },\n );\n }\n\n async getUsage(startDate: string, endDate: string): Promise<UsageMetrics> {\n return this.get<UsageMetrics>('/usage', { start_date: startDate, end_date: endDate });\n }\n\n async getTeamUsage(teamId: string, startDate: string, endDate: string): Promise<UsageMetrics> {\n return this.get<UsageMetrics>(`/teams/${encodeURIComponent(teamId)}/usage`, {\n start_date: startDate,\n end_date: endDate,\n });\n }\n\n async getConfig(): Promise<LiteLlmConfig> {\n return this.get<LiteLlmConfig>('/config');\n }\n\n async createTeam(request: CreateTeamRequest): Promise<CreateTeamResponse> {\n return this.post<CreateTeamResponse>('/teams', request);\n }\n\n async updateTeam(teamId: string, request: UpdateTeamRequest): Promise<TeamInfo> {\n return this.patch<TeamInfo>(`/teams/${encodeURIComponent(teamId)}`, request);\n }\n}\n", "import { createRouteRef } from '@backstage/frontend-plugin-api';\n\nexport const rootRouteRef = createRouteRef();\n", "import { alpha, useTheme } from '@mui/material/styles';\nimport type { Theme } from '@mui/material/styles';\n\n// \u2500\u2500 formatting \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];\n\n/** `2026-08-16` \u2192 `Aug 16`. Falls back to the raw value for anything else. */\nexport const fmtDateShort = (value: string): string => {\n const m = /^(\\d{4})-(\\d{2})-(\\d{2})/.exec(value ?? '');\n if (!m) return value;\n return `${MONTHS[Number(m[2]) - 1]} ${Number(m[3])}`;\n};\n\n/** 54253484 \u2192 `54.3M`. Keeps axis labels from swallowing the plot area. */\nexport const fmtCompact = (n: number): string => {\n const v = n ?? 0;\n const abs = Math.abs(v);\n if (abs >= 1e9) return `${(v / 1e9).toFixed(abs >= 1e10 ? 0 : 1)}B`;\n if (abs >= 1e6) return `${(v / 1e6).toFixed(abs >= 1e7 ? 0 : 1)}M`;\n if (abs >= 1e3) return `${(v / 1e3).toFixed(abs >= 1e4 ? 0 : 1)}K`;\n return String(Math.round(v));\n};\n\n/** Compact currency for axis ticks \u2014 `$24`, `$1.2K`. */\nexport const fmtUsdCompact = (n: number): string => {\n const v = n ?? 0;\n if (Math.abs(v) >= 1000) return `$${fmtCompact(v)}`;\n if (Math.abs(v) >= 10) return `$${v.toFixed(0)}`;\n return `$${v.toFixed(2)}`;\n};\n\n// \u2500\u2500 chart palette \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Categorical ramp, ordered so neighbouring series stay distinguishable. */\nexport const CHART_COLORS = [\n '#6366F1', // indigo\n '#14B8A6', // teal\n '#F59E0B', // amber\n '#EC4899', // pink\n '#38BDF8', // sky\n '#84CC16', // lime\n '#F97316', // orange\n '#A855F7', // violet\n] as const;\n\n/** Fixed colours for series that carry meaning rather than identity. */\nexport const SERIES = {\n input: '#6366F1',\n output: '#14B8A6',\n success: '#0d9488',\n failure: '#ea580c',\n spend: '#F59E0B',\n budget: '#ea580c',\n} as const;\n\nconst OTHER_COLOR = '#94A3B8';\n\n/** Stable colour per series name, so a model keeps its colour across charts. */\nexport function chartColor(name: string): string {\n if (name === 'Other') return OTHER_COLOR;\n let h = 5381;\n for (let i = 0; i < name.length; i++) h = ((h << 5) + h + name.charCodeAt(i)) >>> 0;\n return CHART_COLORS[h % CHART_COLORS.length];\n}\n\n/** Axis / grid / legend props shared by every chart, derived from the theme. */\nexport function useChartTheme() {\n const theme = useTheme();\n const tickFill = theme.palette.text.secondary;\n return {\n grid: {\n stroke: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.12 : 0.08),\n strokeDasharray: '2 4',\n vertical: false,\n },\n axis: {\n tick: { fontSize: 11, fill: tickFill },\n tickLine: false,\n axisLine: { stroke: alpha(theme.palette.text.primary, 0.12) },\n },\n legend: {\n wrapperStyle: {\n fontSize: 11,\n color: tickFill,\n paddingTop: 8,\n },\n iconType: 'circle' as const,\n iconSize: 8,\n },\n cursor: { fill: alpha(theme.palette.text.primary, 0.05) },\n };\n}\n\n\n// \u2500\u2500 status pills \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport type Tone = 'neutral' | 'success' | 'warning' | 'danger' | 'info' | 'accent';\n\nexport function toneColor(theme: Theme, tone: Tone): string {\n switch (tone) {\n case 'success': return theme.palette.success.main;\n case 'warning': return theme.palette.warning.main;\n case 'danger': return theme.palette.error.main;\n case 'info': return theme.palette.info.main;\n case 'accent': return theme.palette.primary.main;\n default: return theme.palette.text.secondary;\n }\n}\n\n", "import { FC } from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { fmtDateShort } from './tokens';\n\ninterface ChartTooltipProps {\n active?: boolean;\n label?: string | number;\n payload?: Array<{ name?: string; value?: number; color?: string; dataKey?: string | number }>;\n /** Formats each series value; defaults to a localised integer. */\n valueFormatter?: (value: number) => string;\n /** Formats the header; defaults to the short date form. */\n labelFormatter?: (label: string) => string;\n /** Drop zero-valued series \u2014 useful for stacked charts with many series. */\n hideZero?: boolean;\n}\n\n/**\n * Recharts' default tooltip is an opaque white card with a hard border \u2014 it\n * disappears on dark themes. This one uses the theme's own surface tokens.\n */\nexport const ChartTooltip: FC<ChartTooltipProps> = ({\n active,\n label,\n payload,\n valueFormatter = (v: number) => v.toLocaleString(),\n labelFormatter = fmtDateShort,\n hideZero = false,\n}) => {\n if (!active || !payload?.length) return null;\n const rows = payload.filter(\n p => p.value !== undefined && p.value !== null && (!hideZero || p.value !== 0),\n );\n if (!rows.length) return null;\n return (\n <Paper\n elevation={8}\n sx={{\n px: 1.5,\n py: 1,\n borderRadius: 1.5,\n border: '1px solid',\n borderColor: 'divider',\n minWidth: 150,\n pointerEvents: 'none',\n }}\n >\n <Typography\n variant=\"caption\"\n sx={{ display: 'block', fontWeight: 700, mb: 0.75, letterSpacing: '0.02em' }}\n >\n {typeof label === 'string' ? labelFormatter(label) : label}\n </Typography>\n {rows.map((row, i) => (\n <Box\n key={`${row.dataKey ?? row.name ?? i}`}\n sx={{ display: 'flex', alignItems: 'center', gap: 1, mt: i === 0 ? 0 : 0.5 }}\n >\n <Box\n sx={{\n width: 8,\n height: 8,\n borderRadius: '50%',\n bgcolor: row.color,\n flexShrink: 0,\n }}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ flex: 1, mr: 1.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {row.name}\n </Typography>\n <Typography variant=\"caption\" sx={{ fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>\n {valueFormatter(row.value as number)}\n </Typography>\n </Box>\n ))}\n </Paper>\n );\n};\n\n/**\n * Colour key rendered outside the SVG. Recharts' own `<Legend>` cannot ellipsize,\n * so a handful of fully-qualified model names (\"bedrock/eu.anthropic.\u2026\") wrap\n * into a ragged block that eats the plot area.\n */\nexport const SeriesLegend: FC<{ series: Array<{ name: string; color: string }> }> = ({\n series,\n}) => (\n <Box\n sx={{\n display: 'flex',\n flexWrap: 'wrap',\n gap: 0.5,\n columnGap: 2,\n rowGap: 0.5,\n mt: 1.5,\n }}\n >\n {series.map(s => (\n <Box key={s.name} sx={{ display: 'flex', alignItems: 'center', gap: 0.75, minWidth: 0 }}>\n <Box\n sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: s.color, flexShrink: 0 }}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n title={s.name}\n sx={{\n fontSize: 11,\n maxWidth: 190,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {s.name}\n </Typography>\n </Box>\n ))}\n </Box>\n);\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport { alpha } from '@mui/material/styles';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * A soft status badge. Deliberately *not* MUI's filled `Chip` \u2014 host themes\n * tend to render those as saturated pills, and a table with one screaming\n * orange pill per row is unreadable. Tinted background, hairline border,\n * squared-off corners.\n */\nexport const StatusPill: FC<{\n label: ReactNode;\n tone?: Tone;\n /** Show the leading tone dot. */\n dot?: boolean;\n title?: string;\n sx?: SxProps<Theme>;\n}> = ({ label, tone = 'neutral', dot = true, title, sx }) => (\n <Box\n component=\"span\"\n title={title}\n sx={[\n theme => {\n const c = toneColor(theme, tone);\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: 0.625,\n height: 22,\n px: 0.875,\n borderRadius: '6px',\n border: '1px solid',\n borderColor: alpha(c, tone === 'neutral' ? 0.25 : 0.35),\n bgcolor: alpha(c, tone === 'neutral' ? 0.06 : 0.12),\n color: tone === 'neutral' ? theme.palette.text.secondary : c,\n fontSize: 11.5,\n fontWeight: 600,\n lineHeight: 1,\n letterSpacing: '0.01em',\n whiteSpace: 'nowrap',\n maxWidth: '100%',\n };\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n {dot && (\n <Box\n component=\"span\"\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, tone),\n flexShrink: 0,\n })}\n />\n )}\n <Box component=\"span\" sx={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>\n {label}\n </Box>\n </Box>\n);\n\n/** Quiet monospace tag for identifiers: model names, team slugs, roles. */\nexport const TagChip: FC<{ label: ReactNode; title?: string; mono?: boolean }> = ({\n label,\n title,\n mono = true,\n}) => (\n <Box\n component=\"span\"\n title={title}\n sx={theme => ({\n display: 'inline-flex',\n alignItems: 'center',\n height: 20,\n px: 0.75,\n borderRadius: '5px',\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.08 : 0.05),\n color: theme.palette.text.secondary,\n fontFamily: mono ? 'ui-monospace, SFMono-Regular, Menlo, monospace' : undefined,\n fontSize: 11,\n lineHeight: 1,\n whiteSpace: 'nowrap',\n maxWidth: 220,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n })}\n >\n {label}\n </Box>\n);\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { alpha } from '@mui/material/styles';\nimport type { SxProps, Theme } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n// \u2500\u2500 surfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/** Page-level surface with a consistent title row. */\nexport const SectionCard: FC<{\n title?: ReactNode;\n subtitle?: ReactNode;\n actions?: ReactNode;\n /** Set when the body renders its own edge-to-edge content (e.g. a table). */\n flush?: boolean;\n children: ReactNode;\n}> = ({ title, subtitle, actions, flush = false, children }) => (\n <Paper sx={{ borderRadius: 2, overflow: 'hidden' }}>\n {(title || actions) && (\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n flexWrap: 'wrap',\n px: 2.5,\n py: 2,\n }}\n >\n <Box sx={{ minWidth: 0 }}>\n <Typography variant=\"h6\" sx={{ lineHeight: 1.2 }}>{title}</Typography>\n {subtitle && (\n <Typography variant=\"caption\" color=\"text.secondary\">{subtitle}</Typography>\n )}\n </Box>\n {actions && (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>\n {actions}\n </Box>\n )}\n </Box>\n )}\n <Box sx={flush ? undefined : { px: 2.5, pb: 2.5, pt: title ? 0 : 2.5 }}>{children}</Box>\n </Paper>\n);\n\n/** Bordered frame around a single chart, with its own caption row. */\nexport const ChartCard: FC<{\n title: ReactNode;\n meta?: ReactNode;\n height?: number;\n children: ReactNode;\n}> = ({ title, meta, height = 240, children }) => (\n // The plot area must have an explicit height, never a flex-derived one:\n // Recharts' ResponsiveContainer measures its parent, so a parent that sizes\n // itself from its children instead spins in a measure/resize loop.\n <Paper variant=\"outlined\" sx={{ p: 2, borderRadius: 2, height: '100%' }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 1, mb: 1.5, flexWrap: 'wrap' }}>\n <Typography\n variant=\"subtitle2\"\n sx={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase' }}\n >\n {title}\n </Typography>\n {meta && (\n <Typography variant=\"caption\" color=\"text.secondary\">{meta}</Typography>\n )}\n </Box>\n <Box sx={{ height, width: '100%' }}>{children}</Box>\n </Paper>\n);\n\n// \u2500\u2500 metrics \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nexport interface MetricDef {\n label: string;\n value: string;\n hint?: string;\n tone?: Tone;\n}\n\n/**\n * KPI row rendered as one framed strip divided into cells, rather than four\n * loose cards. Cells share a baseline grid so the numbers line up even when\n * only some of them carry a hint.\n */\nexport const MetricStrip: FC<{ metrics: MetricDef[] }> = ({ metrics }) => (\n <Paper\n variant=\"outlined\"\n sx={{\n borderRadius: 2,\n display: 'grid',\n gridTemplateColumns: { xs: '1fr 1fr', md: `repeat(${metrics.length}, 1fr)` },\n overflow: 'hidden',\n }}\n >\n {metrics.map((m, i) => (\n <Box\n key={m.label}\n sx={theme => ({\n px: 2.5,\n py: 2,\n borderLeft: i === 0 ? 0 : '1px solid',\n borderTop: 0,\n borderColor: 'divider',\n [theme.breakpoints.down('md')]: {\n borderLeft: i % 2 === 0 ? 0 : '1px solid',\n borderTop: i < 2 ? 0 : '1px solid',\n borderColor: 'divider',\n },\n })}\n >\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.875, mb: 0.75 }}>\n <Box\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, m.tone ?? 'accent'),\n flexShrink: 0,\n })}\n />\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: 11, fontWeight: 600, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n {m.label}\n </Typography>\n </Box>\n <Typography\n sx={{ fontSize: 26, fontWeight: 700, lineHeight: 1.15, fontVariantNumeric: 'tabular-nums' }}\n >\n {m.value}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', mt: 0.5, minHeight: 16 }}\n >\n {m.hint ?? '\u00A0'}\n </Typography>\n </Box>\n ))}\n </Paper>\n);\n\n/** Label + value pair used inside cards. */\nexport const Stat: FC<{ label: string; value: ReactNode }> = ({ label, value }) => (\n <Box sx={{ minWidth: 0 }}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 10.5, fontWeight: 600, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n {label}\n </Typography>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', mt: 0.25 }}\n >\n {value}\n </Typography>\n </Box>\n);\n\n\n// \u2500\u2500 segmented control \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Secondary navigation inside a card. Hand-rolled rather than a second set of\n * `Tabs` so it reads as subordinate to the page tabs instead of competing\n * with them, and so host theme overrides on `MuiTab` don't leak in.\n */\nexport function SegmentedControl<T extends string>({\n value,\n onChange,\n options,\n}: {\n value: T;\n onChange: (value: T) => void;\n options: Array<{ value: T; label: string }>;\n}) {\n return (\n <Box\n role=\"tablist\"\n sx={theme => ({\n display: 'inline-flex',\n gap: 0.25,\n p: 0.375,\n borderRadius: 1.5,\n border: '1px solid',\n borderColor: theme.palette.divider,\n })}\n >\n {options.map(opt => {\n const selected = opt.value === value;\n return (\n <ButtonBase\n key={opt.value}\n role=\"tab\"\n aria-selected={selected}\n onClick={() => onChange(opt.value)}\n sx={theme => ({\n px: 1.5,\n height: 28,\n borderRadius: 1,\n fontSize: 13,\n fontWeight: selected ? 700 : 500,\n // Tint the selection with the accent rather than swapping in a\n // surface colour: on a dark theme `background.paper` sits *behind*\n // the track, so the selected chip would read as recessed.\n color: selected ? theme.palette.primary.main : theme.palette.text.secondary,\n bgcolor: selected\n ? alpha(theme.palette.primary.main, theme.palette.mode === 'dark' ? 0.2 : 0.11)\n : 'transparent',\n transition: theme.transitions.create(['background-color', 'color']),\n '&:hover': {\n color: selected ? theme.palette.primary.main : theme.palette.text.primary,\n bgcolor: selected\n ? alpha(theme.palette.primary.main, theme.palette.mode === 'dark' ? 0.26 : 0.15)\n : alpha(theme.palette.text.primary, 0.05),\n },\n })}\n >\n {opt.label}\n </ButtonBase>\n );\n })}\n </Box>\n );\n}\n\n// \u2500\u2500 tables \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Shared table chrome: quiet uppercase headers, hairline row rules, a hover\n * highlight, and tabular figures so numeric columns align.\n */\nexport const dataTableSx: SxProps<Theme> = theme => ({\n // Element selectors, not `.MuiTableCell-head`: host apps may set a MUI\n // classname prefix (Backstage ships `v5-`), which breaks global class targeting.\n '& thead th': {\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: '0.07em',\n textTransform: 'uppercase',\n color: theme.palette.text.secondary,\n backgroundColor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.04 : 0.02),\n borderBottom: `1px solid ${theme.palette.divider}`,\n whiteSpace: 'nowrap',\n paddingTop: theme.spacing(1.25),\n paddingBottom: theme.spacing(1.25),\n },\n '& tbody td': {\n borderBottom: `1px solid ${alpha(theme.palette.divider, 0.6)}`,\n paddingTop: theme.spacing(1.25),\n paddingBottom: theme.spacing(1.25),\n fontVariantNumeric: 'tabular-nums',\n },\n '& tbody tr:last-of-type td': {\n borderBottom: 0,\n },\n '& tbody tr:hover': {\n backgroundColor: alpha(theme.palette.text.primary, 0.03),\n },\n});\n\n/** Muted icon button that only picks up its semantic colour on hover. */\nexport const quietIconButtonSx = (tone: Tone = 'neutral'): SxProps<Theme> => theme => ({\n color: theme.palette.text.secondary,\n '&:hover': {\n color: toneColor(theme, tone),\n bgcolor: alpha(toneColor(theme, tone), 0.1),\n },\n});\n\n/** Centered empty / loading state for a card body. */\nexport const EmptyState: FC<{\n message: string;\n hint?: string;\n height?: number;\n action?: ReactNode;\n}> = ({ message, hint, height, action }) => (\n <Box\n sx={{\n height,\n minHeight: height ? undefined : 120,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 1,\n textAlign: 'center',\n py: 3,\n }}\n >\n <Typography variant=\"body2\" color=\"text.secondary\">{message}</Typography>\n {hint && <Typography variant=\"caption\" color=\"text.secondary\">{hint}</Typography>}\n {action}\n </Box>\n);\n\n", "import { FC } from 'react';\nimport Box from '@mui/material/Box';\nimport { alpha } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * Progress meter with an explicitly drawn track. MUI's `LinearProgress` tints\n * its track from the bar colour, which makes an empty bar look full.\n */\nexport const Meter: FC<{\n value: number;\n tone?: Tone;\n height?: number;\n /** Optional aria-label for accessibility. */\n ariaLabel?: string;\n}> = ({\n value,\n tone = 'accent',\n height = 5,\n ariaLabel,\n}) => {\n const clamped = Math.max(0, Math.min(100, value));\n const isOverCap = value > 100;\n\n return (\n <Box>\n <Box\n sx={theme => ({\n height,\n borderRadius: height,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.12 : 0.08),\n overflow: 'hidden',\n })}\n role=\"meter\"\n aria-valuenow={clamped}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n aria-valuetext={isOverCap ? `${Math.round(value)}% \u2014 over cap` : undefined}\n >\n <Box\n sx={theme => ({\n height: '100%',\n width: `${clamped}%`,\n borderRadius: height,\n bgcolor: toneColor(theme, tone),\n transition: theme.transitions.create('width'),\n })}\n />\n </Box>\n {isOverCap && (\n <Box\n sx={{\n textAlign: 'center',\n fontSize: 10,\n fontWeight: 600,\n color: 'text.primary',\n mt: 0.25,\n }}\n >\n Over cap\n </Box>\n )}\n </Box>\n );\n};\n\n", "import { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { alpha } from '@mui/material/styles';\nimport { toneColor, type Tone } from './tokens';\n/**\n * Ring gauge for at-a-glance ratios. Hand-drawn SVG rather than MUI's\n * `CircularProgress`: the track has to stay a neutral hairline (MUI tints it\n * from the bar colour, so an empty ring reads as full), and the value may\n * legitimately exceed 100% \u2014 the arc clamps at a full turn while the centre\n * label keeps the real number.\n */\nexport const Gauge: FC<{\n /** Share consumed, 0..100+ (unclamped for the label). */\n value: number;\n tone?: Tone;\n /** Outer diameter in px. */\n size?: number;\n /** Ring thickness in px. */\n thickness?: number;\n /** Centre content; defaults to the rounded percentage. */\n label?: ReactNode;\n /** Small caption under the value, inside the ring. */\n caption?: ReactNode;\n /** Optional aria-label for accessibility. */\n ariaLabel?: string;\n}> = ({ value, tone = 'accent', size = 72, thickness = 6, label, caption, ariaLabel }) => {\n const clamped = Math.max(0, Math.min(100, value ?? 0));\n const r = (size - thickness) / 2;\n const c = 2 * Math.PI * r;\n const dash = (clamped / 100) * c;\n const isOverCap = value > 100;\n\n return (\n <Box\n sx={theme => ({\n position: 'relative',\n width: size,\n height: size,\n color: toneColor(theme, tone),\n })}\n role=\"meter\"\n aria-valuenow={clamped}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={ariaLabel}\n aria-valuetext={isOverCap ? `${Math.round(value)}% \u2014 over cap` : undefined}\n >\n <Box\n component=\"svg\"\n viewBox={`0 0 ${size} ${size}`}\n width={size}\n height={size}\n sx={{ display: 'block', transform: 'rotate(-90deg)' }}\n >\n <Box\n component=\"circle\"\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n strokeWidth={thickness}\n sx={theme => ({\n stroke: alpha(\n theme.palette.text.primary,\n theme.palette.mode === 'dark' ? 0.14 : 0.09,\n ),\n })}\n />\n <Box\n component=\"circle\"\n cx={size / 2}\n cy={size / 2}\n r={r}\n fill=\"none\"\n strokeWidth={thickness}\n strokeLinecap=\"round\"\n strokeDasharray={`${dash} ${c - dash}`}\n sx={theme => ({\n stroke: 'currentColor',\n transition: theme.transitions.create('stroke-dasharray'),\n })}\n />\n </Box>\n <Box\n sx={{\n position: 'absolute',\n inset: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n }}\n >\n {/* Past 100% the number stays visible \u2014 a wide \"Over cap\" word in a\n small ring both overflows and collides with the stroke, so the\n status is spelled out in the row that owns the gauge instead. */}\n <Typography\n sx={{\n fontSize: size <= 64 ? 15 : 18,\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n color: isOverCap ? 'currentColor' : 'text.primary',\n }}\n >\n {label ?? `${Math.round(value)}%`}\n </Typography>\n {caption && (\n <Typography\n variant=\"caption\"\n sx={{\n fontSize: 9.5,\n color: 'text.secondary',\n mt: 0.25,\n whiteSpace: 'nowrap',\n }}\n >\n {caption}\n </Typography>\n )}\n </Box>\n </Box>\n );\n};\n\n", "export * from './tokens';\nexport * from './charts';\nexport * from './pills';\nexport * from './surfaces';\nexport * from './Meter';\nexport * from './Gauge';\n", "import { FC } from 'react';\nimport Button from '@mui/material/Button';\nimport { Add } from '@mui/icons-material';\nimport { Link } from '@backstage/core-components';\n\n/**\n * The single \"create a key\" call-to-action used everywhere in the plugin \u2014\n * the plugin page (header, keys table) and the homepage budget card all\n * render this instead of their own inline `Button`, so the copy, icon and\n * styling stay identical.\n */\nexport interface GenerateKeyButtonProps {\n /** Deep-link target (e.g. `/litellm?generate=1`). Ignored when `onClick` is set. */\n to?: string;\n /** Click handler. Takes precedence over `to` when both are given. */\n onClick?: () => void;\n /** Override the default `Generate New Key` copy (e.g. empty-state variants). */\n label?: string;\n /** Button size \u2014 card footers use `small`, page headers the default. */\n size?: 'small' | 'medium' | 'large';\n /** Stretch to the container width (card-footers). Defaults to false. */\n fullWidth?: boolean;\n /** Disabled state (e.g. until the account data loads). A disabled `to` renders inert. */\n disabled?: boolean;\n}\n\nexport const GenerateKeyButton: FC<GenerateKeyButtonProps> = ({\n to,\n onClick,\n label = 'Generate New Key',\n size,\n fullWidth = false,\n disabled = false,\n}) => {\n if (onClick && !disabled) {\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n onClick={onClick}\n >\n {label}\n </Button>\n );\n }\n if (to && !disabled) {\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n component={Link}\n to={to}\n >\n {label}\n </Button>\n );\n }\n return (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n size={size}\n fullWidth={fullWidth}\n startIcon={<Add />}\n disabled\n >\n {label}\n </Button>\n );\n};\n", "import { FC, ReactNode, useMemo } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Paper from '@mui/material/Paper';\nimport Divider from '@mui/material/Divider';\nimport ButtonBase from '@mui/material/ButtonBase';\nimport { alpha } from '@mui/material/styles';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { expiryStatus } from '../api';\nimport { TagChip, Tone } from './ui';\nimport { GenerateKeyButton } from './GenerateKeyButton';\n\ninterface DashboardHeaderProps {\n userInfo: UserInfo;\n teams: TeamInfo[];\n keys: VirtualKey[];\n loading: boolean;\n keysError?: Error;\n onGenerateKeyClick: () => void;\n onNavigateToFilter?: (filter: 'expired' | 'expiring') => void;\n /** Page tab bar, rendered flush with the bottom edge of the header card. */\n tabs?: ReactNode;\n}\n\n/** Two initials from an email or username, for the identity badge. */\nfunction initials(name: string): string {\n const local = name.split('@')[0] ?? name;\n const parts = local.split(/[.\\-_\\s]+/).filter(Boolean);\n if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();\n return local.slice(0, 2).toUpperCase();\n}\n\nconst CountStat: FC<{\n value: number | null;\n label: string;\n tone: Tone;\n clickable?: boolean;\n onClick?: () => void;\n}> = ({ value, label, tone, clickable, onClick }) => {\n // Zero counts stay grey: only a real expiry deserves a colour.\n // Null indicates a fetch error and displays as \"\u2013\" without a coloured dot.\n const active = value !== null && value > 0;\n const display = value === null ? '\u2013' : value;\n const isClickable = clickable && active && onClick;\n\n const content = (\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>\n <Box\n aria-hidden=\"true\"\n sx={theme => ({\n width: 7,\n height: 7,\n borderRadius: '50%',\n flexShrink: 0,\n bgcolor: active\n ? (tone === 'danger' && theme.palette.error.main) ||\n (tone === 'warning' && theme.palette.warning.main) ||\n theme.palette.primary.main\n : alpha(theme.palette.text.primary, 0.25),\n })}\n />\n <Typography\n component=\"span\"\n sx={{\n fontSize: 15,\n fontWeight: 700,\n lineHeight: 1,\n fontVariantNumeric: 'tabular-nums',\n ...(isClickable && { cursor: 'pointer', textDecoration: 'underline' }),\n }}\n >\n {display}\n </Typography>\n <Typography\n component=\"span\"\n color=\"text.secondary\"\n sx={{\n fontSize: 11,\n fontWeight: 600,\n letterSpacing: '0.07em',\n textTransform: 'uppercase',\n ...(isClickable && { cursor: 'pointer' }),\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n\n if (isClickable) {\n return (\n <ButtonBase onClick={onClick} sx={{ borderRadius: 0.5, px: 0.5, py: 0.25 }}>\n {content}\n </ButtonBase>\n );\n }\n\n return content;\n};\n\nexport const DashboardHeader: FC<DashboardHeaderProps> = ({\n userInfo,\n teams,\n keys,\n loading,\n keysError,\n onGenerateKeyClick,\n onNavigateToFilter,\n tabs,\n}) => {\n const counts = useMemo(() => {\n if (keysError) {\n return { total: null, expired: null, expiringSoon: null };\n }\n const expired = keys.filter(k => expiryStatus(k.expires_at) === 'expired').length;\n const expiringSoon = keys.filter(k => expiryStatus(k.expires_at) === 'soon').length;\n return { total: keys.length, expired, expiringSoon };\n }, [keys, keysError]);\n\n const displayName = userInfo.user_email ?? userInfo.email ?? userInfo.user_id;\n\n return (\n <Paper sx={{ borderRadius: 2, overflow: 'hidden' }}>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'flex-start',\n gap: 2,\n flexWrap: 'wrap',\n px: 2.5,\n pt: 2.5,\n pb: 2,\n }}\n >\n <Box\n sx={theme => ({\n width: 44,\n height: 44,\n borderRadius: 1.5,\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette.primary.main, 0.12),\n color: theme.palette.primary.main,\n fontSize: 15,\n fontWeight: 700,\n letterSpacing: '0.02em',\n })}\n >\n {initials(displayName)}\n </Box>\n\n <Box sx={{ flexGrow: 1, minWidth: 220 }}>\n <Typography variant=\"h6\" sx={{ lineHeight: 1.25, wordBreak: 'break-word' }}>\n {displayName}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {userInfo.user_id}\n </Typography>\n\n <Box sx={{ display: 'flex', gap: 0.75, flexWrap: 'wrap', mt: 1, minHeight: 20 }}>\n {loading ? (\n <Skeleton variant=\"rounded\" width={140} height={20} />\n ) : (\n teams.map(team => (\n <TagChip\n key={team.team_id}\n label={team.team_alias || team.team_id}\n title={team.team_id}\n />\n ))\n )}\n </Box>\n </Box>\n\n <GenerateKeyButton onClick={onGenerateKeyClick} />\n </Box>\n\n <Divider />\n\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 2.5,\n flexWrap: 'wrap',\n px: 2.5,\n py: 1.5,\n }}\n >\n <CountStat value={counts.total} label=\"keys\" tone=\"accent\" />\n <Divider orientation=\"vertical\" flexItem sx={{ my: 0.25 }} aria-hidden=\"true\" />\n <CountStat\n value={counts.expired}\n label=\"expired\"\n tone=\"danger\"\n clickable\n onClick={() => onNavigateToFilter?.('expired')}\n />\n <Divider orientation=\"vertical\" flexItem sx={{ my: 0.25 }} aria-hidden=\"true\" />\n <CountStat\n value={counts.expiringSoon}\n label=\"expiring soon\"\n tone=\"warning\"\n clickable\n onClick={() => onNavigateToFilter?.('expiring')}\n />\n </Box>\n\n {tabs && (\n <>\n <Divider />\n <Box sx={{ px: 1 }}>{tabs}</Box>\n </>\n )}\n </Paper>\n );\n};\n", "import { useState, useEffect, useRef } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { alertApiRef } from '@backstage/core-plugin-api';\n\n/**\n * Pure helper: determine if the Clipboard API is available.\n */\nexport function isClipboardApiAvailable(): boolean {\n return typeof navigator !== 'undefined' && !!navigator.clipboard?.writeText;\n}\n\n/**\n * Pure helper: fallback copy via textarea and document.execCommand.\n * Returns true if successful, false otherwise.\n */\nfunction fallbackCopyToClipboard(text: string): boolean {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.opacity = '0';\n textarea.style.pointerEvents = 'none';\n document.body.appendChild(textarea);\n try {\n textarea.select();\n const success = document.execCommand('copy');\n document.body.removeChild(textarea);\n return success;\n } catch {\n document.body.removeChild(textarea);\n return false;\n }\n}\n\n/**\n * Pure helper: create a timer for the copied state.\n * Returns the timer ID so the caller can manage cleanup.\n */\nexport function startCopiedTimer(\n onCopiedChange: (copied: boolean) => void,\n durationMs: number = 2000,\n): ReturnType<typeof setTimeout> {\n return setTimeout(() => {\n onCopiedChange(false);\n }, durationMs);\n}\n\n/**\n * Hook: copy text to clipboard with visual feedback.\n *\n * @returns {copy, copied, error} - async copy function, copied state, and error if any\n *\n * - `copy(text)`: async function that copies text and returns true if successful\n * - `copied`: true for 2s after successful copy, then resets\n * - `error`: error object if copy failed; shows via alertApi\n *\n * Uses navigator.clipboard.writeText with fallback to textarea + execCommand.\n */\nexport function useCopyToClipboard(): {\n copy: (text: string) => Promise<boolean>;\n copied: boolean;\n error: Error | null;\n} {\n const alertApi = useApi(alertApiRef);\n const [copied, setCopied] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Clear timer on unmount\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const copy = async (text: string): Promise<boolean> => {\n // Clear any existing timer\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n timerRef.current = null;\n }\n setError(null);\n\n try {\n if (isClipboardApiAvailable()) {\n await navigator.clipboard.writeText(text);\n } else {\n const success = fallbackCopyToClipboard(text);\n if (!success) {\n throw new Error('Clipboard copy failed');\n }\n }\n setCopied(true);\n timerRef.current = startCopiedTimer(setCopied, 2000);\n return true;\n } catch (err) {\n const copyError = err instanceof Error ? err : new Error('Copy to clipboard failed');\n setError(copyError);\n alertApi.post({\n message: 'Could not copy to clipboard',\n severity: 'error',\n });\n return false;\n }\n };\n\n return { copy, copied, error };\n}\n", "/**\n * Unified hook for fetching the user's LiteLLM profile: userInfo, teams, keys, models, and config.\n * Results are cached per API instance with a 30s TTL and single-flight deduplication.\n * Callers can invalidate the cache after mutations to ensure fresh data.\n */\n\nimport { useEffect, useState, useCallback, useRef } from 'react';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { liteLlmApiRef, LiteLlmApiInterface } from '../api';\nimport { UserInfo, TeamInfo, VirtualKey, ModelInfo, LiteLlmConfig } from '../types';\nimport { profileCacheInstance, ProfileCache } from '../profileCache';\n\nexport interface LiteLLMProfileResult {\n userInfo: UserInfo | null;\n teams: TeamInfo[];\n keys: VirtualKey[];\n models: ModelInfo[];\n config: LiteLlmConfig | null;\n loading: boolean;\n error: string | null;\n retry: () => void;\n}\n\ninterface ProfileData {\n userInfo: UserInfo | null;\n teams: TeamInfo[];\n keys: VirtualKey[];\n models: ModelInfo[];\n config: LiteLlmConfig | null;\n}\n\n/**\n * Fetch the complete user profile (userInfo, teams, keys, models, config).\n * Results are cached with a 30s TTL and single-flight deduplication per API instance.\n * Call the returned `retry()` after mutations to invalidate the cache.\n */\nexport function useLiteLLMProfile(cache: ProfileCache = profileCacheInstance): LiteLLMProfileResult {\n const api = useApi(liteLlmApiRef);\n const [data, setData] = useState<ProfileData>({\n userInfo: null,\n teams: [],\n keys: [],\n models: [],\n config: null,\n });\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const retryCounterRef = useRef(0);\n\n const fetchProfile = useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const [userInfo, teams, keys, models, config] = await Promise.all([\n cache.memoize(api, 'profile-userInfo', () => api.getUserInfo()),\n cache.memoize(api, 'profile-teams', () => api.getTeams()),\n cache.memoize(api, 'profile-keys', () => api.listKeys()),\n cache.memoize(api, 'profile-models', () => api.listModels()),\n cache.memoize(api, 'profile-config', () => api.getConfig()),\n ]);\n\n setData({ userInfo, teams, keys, models, config });\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n }, [api, cache]);\n\n useEffect(() => {\n fetchProfile();\n }, [api, fetchProfile]);\n\n const retry = useCallback(() => {\n cache.invalidateProfile(api);\n retryCounterRef.current++;\n fetchProfile();\n }, [api, cache, fetchProfile]);\n\n return {\n ...data,\n loading,\n error,\n retry,\n };\n}\n\n/**\n * Invalidate the profile cache for an API instance after a mutation\n * (e.g., after creating/updating/deleting a key or team).\n *\n * @param api The API instance to invalidate.\n * @param cache The cache instance (defaults to the singleton).\n */\nexport function invalidateLiteLLMProfile(\n api: LiteLlmApiInterface,\n cache: ProfileCache = profileCacheInstance,\n): void {\n cache.invalidateProfile(api);\n}\n", "export { useCopyToClipboard } from './useCopyToClipboard';\nexport { useLiteLLMProfile, invalidateLiteLLMProfile } from './useLiteLLMProfile';\nexport type { LiteLLMProfileResult } from './useLiteLLMProfile';\n", "import type { VirtualKey } from './types';\n\n/**\n * Returns a display label for a key: alias if present, otherwise the masked key.\n * Handles missing alias and odd/short masked strings gracefully.\n */\nexport function keyDisplayLabel(key: VirtualKey): string {\n if (key.key_alias) {\n return key.key_alias;\n }\n return key.key || '\u2014';\n}\n\n/**\n * Extracts the last 4 characters from a key's masked value.\n * Returns empty string if the key is shorter than 4 chars.\n */\nexport function keyLast4(key: VirtualKey): string {\n if (!key.key || key.key.length < 4) {\n return '';\n }\n return key.key.slice(-4);\n}\n\n/**\n * Generates the confirmation copy for pruning expired keys.\n * Handles singular and plural correctly.\n */\nexport function pruneCopy(n: number): string {\n if (n === 1) {\n return 'Remove 1 expired key from the list. It already doesn\\'t work.';\n }\n return `Remove ${n} expired keys from the list. They already don't work.`;\n}\n\n/** Outcome of one permission check: granted, refused, or still loading (neither). */\nexport interface PermissionState {\n allowed: boolean;\n denied: boolean;\n}\n\n/**\n * Label and enabled-state of the row's block/unblock button. Blocking needs the\n * key-manage permission; unblocking needs the dedicated unblock permission (the\n * server does not let owners lift a block on their own say-so). \"No permission\"\n * wording only appears after a real denial, never while permissions load.\n */\nexport function blockButtonState(\n blocked: boolean | undefined,\n manage: PermissionState,\n unblock: PermissionState,\n): { label: string; disabled: boolean } {\n if (blocked) {\n return {\n label: unblock.denied ? 'No permission to unblock keys' : 'Unblock key',\n disabled: !unblock.allowed,\n };\n }\n return {\n label: manage.denied\n ? 'No permission to block keys'\n : 'Block key \\u2014 suspends without revoking',\n disabled: !manage.allowed,\n };\n}\n", "const currencyFormatter = new Intl.NumberFormat('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n});\n\n/**\n * Format a number as USD currency with 2 decimals. Non-zero values below\n * one cent render as `<$0.01`. Zero, null, undefined, or NaN render as `$0.00`.\n * Negative values keep the leading minus sign.\n */\nexport const fmtUsd = (n: number | null | undefined): string => {\n if (n === null || n === undefined || Number.isNaN(n)) {\n return '$0.00';\n }\n if (n === 0) {\n return '$0.00';\n }\n // Non-zero values below one cent\n const abs = Math.abs(n);\n if (abs > 0 && abs < 0.01) {\n return n < 0 ? '-<$0.01' : '<$0.01';\n }\n return currencyFormatter.format(n);\n};\n\nexport const fmtInt = (n: number) => (n ?? 0).toLocaleString();\n\n/**\n * Format a count for display, showing \"\u2013\" when the value is null or undefined.\n * Used to indicate that data failed to load, distinct from a zero count.\n */\nexport const formatCount = (n: number | null | undefined): string => {\n return n === null || n === undefined ? '\u2013' : fmtInt(n);\n};\n\n/**\n * Estimate how many tokens a USD budget buys at a given per-token price.\n * Returns null when the price is missing or non-positive.\n */\nexport const estimateTokensFromBudget = (budget: number, pricePerToken?: number): number | null => {\n if (!pricePerToken || pricePerToken <= 0 || !budget || budget <= 0) return null;\n return Math.floor(budget / pricePerToken);\n};\n\n/**\n * Format TPM and RPM limits for display. When neither limit is set (both null/undefined),\n * returns 'Unlimited'. Otherwise returns formatted values with 'Unlimited' for the missing limit.\n * Uses fmtInt for digit grouping.\n */\nexport const fmtLimits = (tpm: number | null | undefined, rpm: number | null | undefined): string => {\n const tpmStr = tpm ? fmtInt(tpm) : 'Unlimited';\n const rpmStr = rpm ? fmtInt(rpm) : 'Unlimited';\n if (tpmStr === 'Unlimited' && rpmStr === 'Unlimited') {\n return 'Unlimited';\n }\n return `${tpmStr} / ${rpmStr}`;\n};\n\nexport interface ModelInfo {\n model_name: string;\n}\n\nexport interface UsageModelBreakdown {\n total_spend: number;\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n api_requests: number;\n successful_requests: number;\n failed_requests: number;\n}\n\n/**\n * Filter models to only those that have usage data in the given period.\n * Keeps 'all' as a first option and extracts model names from the full list,\n * then filters to only those present in the usage breakdown.\n */\nexport const modelsWithUsage = (\n usage: { usage_by_model?: Record<string, UsageModelBreakdown> } | null,\n models: ModelInfo[],\n): string[] => {\n if (!usage?.usage_by_model) {\n return models.map(m => m.model_name);\n }\n const usedNames = Object.keys(usage.usage_by_model);\n const modelsInUsage = new Set(usedNames);\n const known = models.map(m => m.model_name);\n // Keep the accessible-models order, then append models that appear in usage\n // but are no longer listed (e.g. removed from the proxy since) so they can\n // still be filtered on.\n return [\n ...known.filter(name => modelsInUsage.has(name)),\n ...usedNames.filter(name => !known.includes(name)),\n ];\n};\n", "/**\n * Pure filtering functions for key lists.\n */\n\nimport { VirtualKey } from './types';\nimport { expiryStatus } from './api';\n\nexport type KeyFilterType = 'expired' | 'expiring' | undefined;\n\n/**\n * Filter keys by expiry status.\n * @param keys List of keys to filter\n * @param filter Filter type: 'expired', 'expiring', or undefined (no filter)\n * @returns Filtered list of keys\n */\nexport function filterKeysByStatus(keys: VirtualKey[], filter: KeyFilterType): VirtualKey[] {\n if (!filter) return keys;\n\n return keys.filter(key => {\n const status = expiryStatus(key.expires_at);\n if (filter === 'expired') return status === 'expired';\n if (filter === 'expiring') return status === 'soon';\n return true;\n });\n}\n", "import { FC, useMemo, useState } from 'react';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableSortLabel from '@mui/material/TableSortLabel';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Skeleton from '@mui/material/Skeleton';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Tooltip from '@mui/material/Tooltip';\nimport Chip from '@mui/material/Chip';\nimport { alpha } from '@mui/material/styles';\nimport { ContentCopy, Delete, Edit, Autorenew, Search, Lock, LockOpen, Check, Close } from '@mui/icons-material';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n litellmKeyManagePermission,\n litellmKeyRevokePermission,\n litellmKeyUnblockPermission,\n} from '@acarmisc/backstage-plugin-litellm-common';\nimport { useCopyToClipboard } from '../hooks';\nimport { expiryStatus } from '../api';\nimport { keyDisplayLabel, keyLast4, pruneCopy, blockButtonState } from '../keyLabels';\nimport { fmtUsd, fmtLimits } from '../format';\nimport { filterKeysByStatus, type KeyFilterType } from '../keyFilter';\nimport { GenerateKeyButton } from './GenerateKeyButton';\nimport {\n VirtualKey,\n} from '../types';\nimport {\n EmptyState,\n Meter,\n SectionCard,\n StatusPill,\n TagChip,\n Tone,\n dataTableSx,\n quietIconButtonSx,\n} from './ui';\n\ninterface KeysTableProps {\n keys: VirtualKey[];\n /** Opens the shared key form dialog in create mode (rendered at page level). */\n onGenerateKeyClick: () => void;\n /** Opens the shared key form dialog in edit mode for the given key. */\n onEditKey: (key: VirtualKey) => void;\n loading: boolean;\n onBlockKey: (keyId: string) => Promise<void>;\n onUnblockKey: (keyId: string) => Promise<void>;\n onDeleteKey: (keyId: string) => Promise<void>;\n onPruneExpiredKeys: () => Promise<{ pruned: number }>;\n filter?: KeyFilterType;\n onClearFilter?: () => void;\n}\n\nconst shortKeyId = (token: string): string => {\n if (!token) return '-';\n if (token.length <= 16) return token;\n return `${token.slice(0, 12)}\u2026`;\n};\n\nconst formatDate = (dateStr: string): string => {\n try {\n return new Date(dateStr).toLocaleDateString();\n } catch {\n return dateStr;\n }\n};\n\nfunction expiryChipLabel(status: 'expired' | 'soon' | 'ok', expiresAt: string): string {\n if (status === 'expired') return 'Expired';\n if (status === 'soon') return `${Math.ceil((new Date(expiresAt).getTime() - Date.now()) / 86400000)}d left`;\n return formatDate(expiresAt);\n}\n\nfunction expiryTone(status: 'expired' | 'soon' | 'ok'): Tone {\n if (status === 'expired') return 'danger';\n if (status === 'soon') return 'warning';\n return 'neutral';\n}\n\nfunction ExpiryCell({ expiresAt }: { expiresAt?: string }) {\n const status = expiryStatus(expiresAt);\n if (!status) {\n return <Typography variant=\"body2\" color=\"text.secondary\">Never</Typography>;\n }\n // A key that is simply valid needs no badge \u2014 plain text keeps the column\n // quiet so the handful of expired/expiring rows actually stand out.\n if (status === 'ok') {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\">\n {formatDate(expiresAt!)}\n </Typography>\n );\n }\n return (\n <StatusPill\n label={expiryChipLabel(status, expiresAt!)}\n tone={expiryTone(status)}\n title={`Expires ${formatDate(expiresAt!)}`}\n />\n );\n}\n\nfunction budgetTone(pct: number): Tone {\n if (pct >= 100) return 'danger';\n if (pct >= 80) return 'warning';\n return 'accent';\n}\n\nfunction keyBlockIcon(isBlocking: boolean, blocked?: boolean) {\n if (isBlocking) return <CircularProgress size={18} />;\n if (blocked) return <LockOpen fontSize=\"small\" />;\n return <Lock fontSize=\"small\" />;\n}\n\nfunction BudgetCell({ spend, maxBudget }: { spend: number; maxBudget?: number }) {\n if (!maxBudget) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtUsd(spend)}\n <Typography component=\"span\" variant=\"caption\" sx={{ ml: 0.5, opacity: 0.7 }}>\n / Unlimited\n </Typography>\n </Typography>\n );\n }\n const pct = Math.min(100, (spend / maxBudget) * 100);\n return (\n <Box minWidth={104}>\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums', mb: 0.5 }}>\n {fmtUsd(spend)}\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\" sx={{ ml: 0.5 }}>\n / {fmtUsd(maxBudget)}\n </Typography>\n </Typography>\n <Meter value={pct} tone={budgetTone(pct)} height={4} />\n </Box>\n );\n}\n\ntype SortKey = 'alias' | 'created' | 'expires' | 'budget' | 'limits' | 'models';\ntype SortDirection = 'asc' | 'desc';\n\nfunction compareKeys(a: VirtualKey, b: VirtualKey, sortKey: SortKey): number {\n switch (sortKey) {\n case 'alias': return (a.key_alias ?? '').localeCompare(b.key_alias ?? '');\n case 'created': return a.created_at.localeCompare(b.created_at);\n case 'expires': return (a.expires_at ?? '').localeCompare(b.expires_at ?? '');\n case 'budget': return (a.max_budget ?? Infinity) - (b.max_budget ?? Infinity);\n case 'limits': return (a.tpm_limit ?? Infinity) - (b.tpm_limit ?? Infinity) || (a.rpm_limit ?? Infinity) - (b.rpm_limit ?? Infinity);\n case 'models': return (a.models ?? []).join(',').localeCompare((b.models ?? []).join(','));\n default: return 0;\n }\n}\n\nexport const KeysTable: FC<KeysTableProps> = ({\n keys,\n loading,\n onGenerateKeyClick,\n onEditKey,\n onBlockKey,\n onUnblockKey,\n onDeleteKey,\n onPruneExpiredKeys,\n filter,\n onClearFilter,\n}) => {\n // Permission checks\n const managePermission = usePermission({ permission: litellmKeyManagePermission });\n const revokePermission = usePermission({ permission: litellmKeyRevokePermission });\n const unblockPermission = usePermission({ permission: litellmKeyUnblockPermission });\n const canManageKeys = !managePermission.loading && managePermission.allowed;\n const canRevokeKeys = !revokePermission.loading && revokePermission.allowed;\n // Only claim \"no permission\" after a real denial, not while still checking.\n const manageDenied = !managePermission.loading && !managePermission.allowed;\n const revokeDenied = !revokePermission.loading && !revokePermission.allowed;\n const canUnblockKeys = !unblockPermission.loading && unblockPermission.allowed;\n const unblockDenied = !unblockPermission.loading && !unblockPermission.allowed;\n\n // Block confirmation\n const [blockConfirmKey, setBlockConfirmKey] = useState<VirtualKey | null>(null);\n const [blockSubmitting, setBlockSubmitting] = useState(false);\n\n // Delete confirmation\n const [deleteConfirmKey, setDeleteConfirmKey] = useState<VirtualKey | null>(null);\n const [deleteSubmitting, setDeleteSubmitting] = useState(false);\n\n // Reset spend moved into the shared KeyFormDialog (edit mode)\n\n // Clipboard\n const clipboard = useCopyToClipboard();\n\n // Filter\n const [filterText, setFilterText] = useState('');\n const [sortKey, setSortKey] = useState<SortKey>('created');\n const [sortDirection, setSortDirection] = useState<SortDirection>('desc');\n\n const handleSort = (nextSortKey: SortKey) => {\n if (sortKey === nextSortKey) {\n setSortDirection(current => current === 'asc' ? 'desc' : 'asc');\n } else {\n setSortKey(nextSortKey);\n setSortDirection('asc');\n }\n };\n\n const filteredKeys = useMemo(() => {\n let result = keys;\n // Apply status filter (expired/expiring)\n result = filterKeysByStatus(result, filter);\n // Apply text filter\n if (filterText.trim()) {\n const q = filterText.toLowerCase();\n result = result.filter(k =>\n (k.key_alias ?? '').toLowerCase().includes(q) ||\n k.models?.some(m => m.toLowerCase().includes(q)),\n );\n }\n return [...result].sort((a, b) => {\n const comparison = compareKeys(a, b, sortKey);\n return sortDirection === 'asc' ? comparison : -comparison;\n });\n }, [keys, filterText, sortKey, sortDirection, filter]);\n\n const handleOpenEdit = (k: VirtualKey) => {\n onEditKey(k);\n };\n\n const performUnblock = async (key: VirtualKey) => {\n const keyId = key.token ?? key.key;\n setBlockSubmitting(true);\n try {\n await onUnblockKey(keyId);\n } finally {\n setBlockSubmitting(false);\n }\n };\n\n const performBlock = async (key: VirtualKey) => {\n if (!blockConfirmKey) return;\n const keyId = key.token ?? key.key;\n setBlockSubmitting(true);\n try {\n await onBlockKey(keyId);\n } finally {\n setBlockSubmitting(false);\n setBlockConfirmKey(null);\n }\n };\n\n const handleToggleBlock = (key: VirtualKey) => {\n if (key.blocked) {\n // Unblock is safe (one-click) \u2014 no confirmation\n performUnblock(key);\n } else {\n // Block requires confirmation\n setBlockConfirmKey(key);\n }\n };\n\n const handleConfirmDelete = async () => {\n if (!deleteConfirmKey) return;\n setDeleteSubmitting(true);\n try {\n const keyId = deleteConfirmKey.token ?? deleteConfirmKey.key;\n await onDeleteKey(keyId);\n } finally {\n setDeleteSubmitting(false);\n setDeleteConfirmKey(null);\n }\n };\n\n\n // Prune expired keys\n const [pruneConfirmCount, setPruneConfirmCount] = useState<number | null>(null);\n const [pruneSubmitting, setPruneSubmitting] = useState(false);\n\n const expiredKeys = useMemo(() => {\n return keys.filter(k => expiryStatus(k.expires_at) === 'expired');\n }, [keys]);\n\n const handlePruneExpired = async () => {\n if (pruneConfirmCount === null || pruneConfirmCount === 0) return;\n setPruneSubmitting(true);\n try {\n await onPruneExpiredKeys();\n } finally {\n setPruneSubmitting(false);\n setPruneConfirmCount(null);\n }\n };\n\n const renderTableBody = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={8} sx={{ py: 2 }}>\n <Skeleton variant=\"rounded\" height={140} />\n </TableCell>\n </TableRow>\n );\n }\n if (filteredKeys.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={8}>\n {filterText ? (\n <EmptyState\n message=\"No keys match that filter\"\n hint=\"Try a different alias or model name.\"\n />\n ) : (\n <EmptyState\n message=\"No keys yet\"\n hint=\"Generate your first key to start calling models.\"\n action={\n <GenerateKeyButton\n size=\"small\"\n label=\"Generate Your First Key\"\n onClick={onGenerateKeyClick}\n />\n }\n />\n )}\n </TableCell>\n </TableRow>\n );\n }\n return filteredKeys.map((key) => {\n const keyId = key.token ?? key.key;\n const keyModels = key.models ?? [];\n const blockState = blockButtonState(\n key.blocked,\n { allowed: canManageKeys, denied: manageDenied },\n { allowed: canUnblockKeys, denied: unblockDenied },\n );\n return (\n <TableRow\n key={keyId}\n sx={\n key.blocked\n ? theme => ({\n // A left rule reads as \"suspended\" without greying the row into\n // illegibility the way a full background tint does.\n boxShadow: `inset 3px 0 0 0 ${theme.palette.error.main}`,\n '& td': { color: theme.palette.text.secondary },\n })\n : undefined\n }\n >\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={1} flexWrap=\"wrap\">\n <Typography variant=\"body2\">\n {key.key_alias || '\u2014'}\n </Typography>\n {key.blocked && <StatusPill label=\"Blocked\" tone=\"danger\" />}\n </Box>\n </TableCell>\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={0.5}>\n <Typography\n variant=\"body2\"\n component=\"code\"\n color=\"text.secondary\"\n title={keyId}\n sx={theme => ({\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n fontSize: 12,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.08 : 0.05),\n px: 0.75,\n py: 0.375,\n borderRadius: '5px',\n whiteSpace: 'nowrap',\n })}\n >\n {shortKeyId(keyId)}\n </Typography>\n <Tooltip title={clipboard.copied ? 'Copied' : 'Copy Key ID'} placement=\"top\">\n <IconButton\n size=\"small\"\n onClick={() => clipboard.copy(keyId)}\n aria-label=\"Copy key ID\"\n sx={quietIconButtonSx('accent')}\n >\n {clipboard.copied ? <Check sx={{ fontSize: 15 }} /> : <ContentCopy sx={{ fontSize: 15 }} />}\n </IconButton>\n </Tooltip>\n </Box>\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\">{formatDate(key.created_at)}</Typography>\n </TableCell>\n <TableCell>\n <ExpiryCell expiresAt={key.expires_at} />\n </TableCell>\n <TableCell>\n <BudgetCell spend={key.spend ?? 0} maxBudget={key.max_budget} />\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtLimits(key.tpm_limit, key.rpm_limit)}\n </Typography>\n </TableCell>\n <TableCell>\n {keyModels.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\">All models</Typography>\n ) : (\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {keyModels.slice(0, 2).map((model) => (\n <TagChip key={model} label={model} title={model} />\n ))}\n {keyModels.length > 2 && (\n <TagChip\n label={`+${keyModels.length - 2}`}\n mono={false}\n title={keyModels.slice(2).join(', ')}\n />\n )}\n </Box>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <Box display=\"flex\" justifyContent=\"flex-end\" gap={0.25}>\n <Tooltip describeChild title={manageDenied ? 'No permission to edit keys' : 'Edit key'} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => handleOpenEdit(key)}\n disabled={!canManageKeys}\n aria-label={manageDenied ? 'No permission to edit keys' : 'Edit key'}\n sx={quietIconButtonSx('accent')}\n >\n <Edit fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n <Tooltip describeChild title={blockState.label} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => handleToggleBlock(key)}\n disabled={blockSubmitting || blockState.disabled}\n aria-label={blockState.label}\n sx={quietIconButtonSx('warning')}\n >\n {keyBlockIcon(blockSubmitting, key.blocked)}\n </IconButton>\n </span>\n </Tooltip>\n <Tooltip describeChild title={revokeDenied ? 'No permission to revoke keys' : 'Revoke key'} placement=\"top\">\n <span>\n <IconButton\n size=\"small\"\n onClick={() => setDeleteConfirmKey(key)}\n disabled={!canRevokeKeys}\n aria-label={revokeDenied ? 'No permission to revoke keys' : 'Revoke key'}\n sx={quietIconButtonSx('danger')}\n >\n <Delete fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n </Box>\n </TableCell>\n </TableRow>\n );\n });\n };\n\n return (\n <>\n <SectionCard\n title=\"Virtual Keys\"\n subtitle={\n loading\n ? 'Loading\u2026'\n : `${filteredKeys.length}${filterText ? ` of ${keys.length}` : ''} key${filteredKeys.length === 1 ? '' : 's'}`\n }\n flush\n actions={\n <>\n <TextField\n size=\"small\"\n label=\"Search alias or model\"\n placeholder=\"Search alias or model\u2026\"\n value={filterText}\n onChange={e => setFilterText(e.target.value)}\n sx={{ minWidth: 240 }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <Search fontSize=\"small\" color=\"disabled\" />\n </InputAdornment>\n ),\n }}\n />\n {expiredKeys.length > 0 && (\n <Button\n variant=\"outlined\"\n color=\"inherit\"\n startIcon={<Autorenew />}\n onClick={() => setPruneConfirmCount(expiredKeys.length)}\n sx={theme => ({\n color: theme.palette.text.secondary,\n borderColor: theme.palette.divider,\n '&:hover': {\n color: theme.palette.error.main,\n borderColor: alpha(theme.palette.error.main, 0.5),\n bgcolor: alpha(theme.palette.error.main, 0.06),\n },\n })}\n >\n Prune expired ({expiredKeys.length})\n </Button>\n )}\n </>\n }\n >\n {filter && (\n <Box sx={{ px: 2, py: 1, borderBottom: theme => `1px solid ${theme.palette.divider}` }}>\n <Chip\n size=\"small\"\n label={`Showing: ${filter === 'expired' ? 'expired' : 'expiring'} keys`}\n onDelete={onClearFilter}\n deleteIcon={<Close />}\n variant=\"outlined\"\n />\n </Box>\n )}\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sortDirection={sortKey === 'alias' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'alias'} direction={sortKey === 'alias' ? sortDirection : 'asc'} onClick={() => handleSort('alias')}>Alias</TableSortLabel>\n </TableCell>\n <TableCell>Key ID</TableCell>\n <TableCell sortDirection={sortKey === 'created' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'created'} direction={sortKey === 'created' ? sortDirection : 'asc'} onClick={() => handleSort('created')}>Created</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'expires' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'expires'} direction={sortKey === 'expires' ? sortDirection : 'asc'} onClick={() => handleSort('expires')}>Expires</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'budget' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'budget'} direction={sortKey === 'budget' ? sortDirection : 'asc'} onClick={() => handleSort('budget')}>Budget</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'limits' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'limits'} direction={sortKey === 'limits' ? sortDirection : 'asc'} onClick={() => handleSort('limits')}>TPM / RPM (per min)</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'models' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'models'} direction={sortKey === 'models' ? sortDirection : 'asc'} onClick={() => handleSort('models')}>Models</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\">Actions</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderTableBody()}\n </TableBody>\n </Table>\n </TableContainer>\n </SectionCard>\n\n {/* Block confirmation dialog */}\n <Dialog\n open={!!blockConfirmKey}\n onClose={() => !blockSubmitting && setBlockConfirmKey(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>Block key?</DialogTitle>\n <DialogContent>\n <Typography>\n Block <strong>{keyDisplayLabel(blockConfirmKey ?? ({} as VirtualKey))}</strong>? Integrations using it will fail immediately.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button\n onClick={() => setBlockConfirmKey(null)}\n disabled={blockSubmitting}\n >\n Cancel\n </Button>\n <Button\n onClick={() => blockConfirmKey && performBlock(blockConfirmKey)}\n variant=\"contained\"\n color=\"warning\"\n disabled={blockSubmitting}\n >\n {blockSubmitting ? <CircularProgress size={20} /> : 'Block'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* Delete confirmation dialog */}\n <Dialog\n open={!!deleteConfirmKey}\n onClose={() => !deleteSubmitting && setDeleteConfirmKey(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>\n Revoke <strong>{deleteConfirmKey ? keyDisplayLabel(deleteConfirmKey) : ''}</strong>{deleteConfirmKey && keyLast4(deleteConfirmKey) ? ` (sk-\u2026${keyLast4(deleteConfirmKey)})` : ''}?\n </DialogTitle>\n <DialogContent>\n <Typography>\n This will permanently revoke the key. Any integrations using it will stop working immediately.\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setDeleteConfirmKey(null)} disabled={deleteSubmitting}>\n Cancel\n </Button>\n <Button\n onClick={handleConfirmDelete}\n variant=\"contained\"\n color=\"error\"\n disabled={deleteSubmitting}\n >\n {deleteSubmitting ? <CircularProgress size={20} /> : 'Revoke'}\n </Button>\n </DialogActions>\n </Dialog>\n\n {/* Prune expired keys confirmation dialog */}\n <Dialog\n open={pruneConfirmCount !== null}\n onClose={() => !pruneSubmitting && setPruneConfirmCount(null)}\n maxWidth=\"xs\"\n fullWidth\n >\n <DialogTitle>Prune Expired Keys?</DialogTitle>\n <DialogContent>\n <Typography>\n {pruneConfirmCount !== null && pruneCopy(pruneConfirmCount)}\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setPruneConfirmCount(null)} disabled={pruneSubmitting}>\n Cancel\n </Button>\n <Button\n onClick={handlePruneExpired}\n variant=\"contained\"\n color=\"error\"\n disabled={pruneSubmitting}\n >\n {pruneSubmitting ? <CircularProgress size={20} /> : 'Prune'}\n </Button>\n </DialogActions>\n </Dialog>\n </>\n );\n};\n", "import { GenerateKeyRequest, UpdateKeyRequest } from './types';\n\nexport interface ValidationErrors {\n alias?: string;\n team?: string;\n budget?: string;\n duration?: string;\n models?: string;\n}\n\nexport interface ValidationOptions {\n teamRequired?: boolean;\n /** True when the user has ticked the 'Unlimited budget' checkbox. */\n unlimitedBudget?: boolean;\n isCreate?: boolean;\n}\n\n/**\n * Validates a key form (create or edit mode).\n * Returns a map of field names to error messages.\n * A field with no error is absent from the map.\n */\nexport function validateKeyForm(\n formData: GenerateKeyRequest | UpdateKeyRequest,\n options: ValidationOptions = {},\n): ValidationErrors {\n const {\n teamRequired = true,\n unlimitedBudget = false,\n isCreate = true,\n } = options;\n\n const errors: ValidationErrors = {};\n\n // Alias validation\n const alias = (isCreate ? (formData as GenerateKeyRequest).alias : (formData as UpdateKeyRequest).key_alias) ?? '';\n if (!alias.trim()) {\n errors.alias = 'Alias is required';\n }\n // A duplicate alias is only a warning in the UI (see aliasDuplicate), never a blocking error.\n\n // Team validation (create mode only)\n if (isCreate) {\n const teamId = (formData as GenerateKeyRequest).team_id;\n if (teamRequired && !teamId) {\n errors.team = 'Team is required';\n }\n }\n\n // Budget validation\n const maxBudget = formData.max_budget;\n if (!unlimitedBudget && (maxBudget === undefined || maxBudget === null || maxBudget <= 0)) {\n errors.budget = 'Enter a positive budget or tick \"Unlimited\"';\n }\n\n return errors;\n}\n\n/**\n * Returns the first field with an error, in a consistent order.\n * Used to focus the first invalid field on submit.\n */\nexport function firstInvalidField(\n errors: ValidationErrors,\n isCreate: boolean = true,\n): string | null {\n const fieldOrder = isCreate\n ? ['team', 'alias', 'budget', 'duration', 'models']\n : ['alias', 'budget', 'models'];\n\n for (const field of fieldOrder) {\n if (errors[field as keyof ValidationErrors]) {\n return field;\n }\n }\n return null;\n}\n\n/**\n * Compute the expiry date from a duration string and the current date.\n * Supported: 'd' (days), 'w' (weeks), 'm' (months), 'y' (years).\n * Example: expiryPreview('30d', new Date('2026-09-29')) => 'Expires Oct 29, 2026'\n */\nexport function expiryPreview(duration: string | undefined, now: Date = new Date()): string | null {\n if (!duration) return null;\n\n const match = duration.match(/^(\\d+)([dwmy])$/);\n if (!match) return null;\n\n const [, countStr, unit] = match;\n const count = parseInt(countStr, 10);\n if (isNaN(count)) return null;\n\n const expiry = new Date(now);\n\n switch (unit) {\n case 'd':\n expiry.setDate(expiry.getDate() + count);\n break;\n case 'w':\n expiry.setDate(expiry.getDate() + count * 7);\n break;\n case 'm':\n expiry.setMonth(expiry.getMonth() + count);\n break;\n case 'y':\n expiry.setFullYear(expiry.getFullYear() + count);\n break;\n default:\n return null;\n }\n\n // Format as \"Expires Oct 29, 2026\"\n const month = expiry.toLocaleString('en-US', { month: 'short' });\n const day = expiry.getDate();\n const year = expiry.getFullYear();\n return `Expires ${month} ${day}, ${year}`;\n}\n\n/**\n * Find the priciest input cost among selected models.\n * Returns null if no models have pricing data.\n */\nexport function priciestInputPrice(\n selectedModels: Array<{ input_cost_per_token?: number }>,\n): number | null {\n const inputCosts = selectedModels\n .map(m => m.input_cost_per_token)\n .filter((c): c is number => typeof c === 'number' && c > 0);\n if (inputCosts.length === 0) return null;\n return Math.max(...inputCosts);\n}\n", "import { VirtualKey, ModelInfo, GenerateKeyRequest, UpdateKeyRequest } from '../types';\nimport { fmtInt } from '../format';\nimport { isModelAllowed } from '@acarmisc/backstage-plugin-litellm-common';\n\nconst generateDefaultAlias = (username?: string): string => {\n const base = (username || 'user')\n .split('@')[0]\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '') || 'user';\n const hash = Math.random().toString(36).slice(2, 8);\n return `${base}-${hash}`;\n};\n\nexport const createForm = (username?: string): GenerateKeyRequest => ({\n alias: generateDefaultAlias(username),\n models: [],\n duration: '30d',\n max_budget: 100,\n tpm_limit: undefined,\n rpm_limit: undefined,\n team_id: undefined,\n key_type: 'llm_api',\n});\n\nexport const editForm = (k: VirtualKey): UpdateKeyRequest => ({\n key_alias: k.key_alias ?? '',\n models: k.models ?? [],\n max_budget: k.max_budget,\n tpm_limit: k.tpm_limit,\n rpm_limit: k.rpm_limit,\n});\n\n// LiteLLM sentinel: a team's `models` list is `[\"all-proxy-models\"]` when the\n// team isn't restricted to specific models. A team's `models` entries can\n// also be access-group names (see litellm model_info.access_groups) rather\n// than literal model_name values. Treating either case as a literal\n// model_name allowlist matches nothing, which previously made the whole\n// \"Models\" field disappear for such teams.\nexport function isModelAllowedByTeam(model: ModelInfo, teamModels?: string[]): boolean {\n return isModelAllowed(model, teamModels);\n}\n\nexport function aliasHelperText(aliasError: boolean, aliasDuplicate: boolean): string | undefined {\n if (aliasError) return 'Alias is required';\n if (aliasDuplicate) return 'This alias is already used by one of your keys \u2014 LiteLLM requires aliases to be unique across all keys';\n return undefined;\n}\n\nexport function teamHelperText(teamError: boolean, teamRequired: boolean): string {\n if (teamError) return 'Team is required';\n if (teamRequired) return 'Bind this key to a team for scoped access';\n return 'Optional: bind this key to a specific team for scoped access';\n}\n\nexport function budgetHelperText(budgetInvalid: boolean, budgetEstimate: number | null, unlimited: boolean): string | undefined {\n if (budgetInvalid && !unlimited) return 'Enter a positive budget or tick \"Unlimited\"';\n if (budgetEstimate !== null) return `\u2248 ${fmtInt(budgetEstimate)} tokens at the priciest selected model`;\n return 'Lifetime cap for this key. It never resets';\n}\n\n\nconst sameStrings = (a: string[] = [], b: string[] = []) =>\n a.length === b.length && a.every((v, i) => v === b[i]);\n\n/**\n * The fields of an edit that actually changed. Sending only these means an\n * untouched field (say a legacy budget above the current ceiling) can't make an\n * unrelated edit fail server-side validation. Returns `{}` when nothing changed.\n */\nexport function changedEditFields(\n original: UpdateKeyRequest,\n current: UpdateKeyRequest,\n unlimitedBudget: boolean,\n): UpdateKeyRequest {\n const out: UpdateKeyRequest = {};\n if ((current.key_alias ?? '') !== (original.key_alias ?? '')) {\n out.key_alias = current.key_alias;\n }\n if (!sameStrings(current.models, original.models)) {\n out.models = current.models ?? [];\n }\n const nextBudget = unlimitedBudget ? null : current.max_budget;\n if ((nextBudget ?? null) !== (original.max_budget ?? null)) {\n out.max_budget = nextBudget;\n }\n if (current.tpm_limit !== original.tpm_limit) out.tpm_limit = current.tpm_limit;\n if (current.rpm_limit !== original.rpm_limit) out.rpm_limit = current.rpm_limit;\n return out;\n}\n", "import { FC, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport IconButton from '@mui/material/IconButton';\nimport Tabs from '@mui/material/Tabs';\nimport Tab from '@mui/material/Tab';\nimport Tooltip from '@mui/material/Tooltip';\nimport { ContentCopy, Check } from '@mui/icons-material';\n\nfunction trimSlash(url: string): string {\n return url.replace(/\\/+$/, '');\n}\n\nexport interface Snippets {\n curl: string;\n openai: string;\n opencode: string;\n pi: string;\n claudeCode: string;\n publicEndpoint: string;\n}\n\nexport function buildSnippets(baseUrl: string | null, key: string, model: string): Snippets {\n if (!baseUrl) {\n throw new Error('baseUrl not configured');\n }\n const base = trimSlash(baseUrl);\n const apiBase = `${base}/v1`;\n return {\n publicEndpoint: apiBase,\n curl: `curl ${apiBase}/chat/completions \\\\\n -H \"Authorization: Bearer ${key}\" \\\\\n -H \"Content-Type: application/json\" \\\\\n -d '{\n \"model\": \"${model}\",\n \"messages\": [{ \"role\": \"user\", \"content\": \"Hello!\" }]\n }'`,\n openai: `from openai import OpenAI\n\nclient = OpenAI(\n api_key=\"${key}\",\n base_url=\"${apiBase}\",\n)\n\nresponse = client.chat.completions.create(\n model=\"${model}\",\n messages=[{ \"role\": \"user\", \"content\": \"Hello!\" }],\n)\nprint(response.choices[0].message.content)`,\n opencode: `{\n \"$schema\": \"https://opencode.ai/config.json\",\n \"provider\": {\n \"litellm\": {\n \"npm\": \"@ai-sdk/openai-compatible\",\n \"name\": \"LiteLLM\",\n \"options\": {\n \"baseURL\": \"${apiBase}\",\n \"apiKey\": \"${key}\"\n },\n \"models\": {\n \"${model}\": {}\n }\n }\n }\n}`,\n pi: `{\n \"litellm\": {\n \"baseUrl\": \"${apiBase}\",\n \"apiKey\": \"${key}\",\n \"api\": \"openai-completions\",\n \"models\": [\n { \"id\": \"${model}\", \"name\": \"${model}\" }\n ]\n }\n}`,\n claudeCode: `# Option 1 \u2014 Static key (store in environment or .env)\nexport ANTHROPIC_AUTH_TOKEN=\"${key}\"\nexport ANTHROPIC_BASE_URL=\"${base}\"\nclaude --model ${model}\n\n# Option 2 \u2014 Read from OS keychain (macOS or Linux)\n# 1. Store this key in your system keychain:\n# macOS:\nsecurity add-generic-password -s litellm-api-key -a \"$USER\" -w '<paste key>'\n# Linux (secret-tool):\nsecret-tool store --label=\"LiteLLM\" service litellm-api-key\n\n# 2. Add to ~/.claude/settings.json (apiKeyHelper is a shell command whose\n# stdout is the key):\n# macOS:\n# { \"apiKeyHelper\": \"security find-generic-password -s litellm-api-key -w\" }\n# Linux:\n# { \"apiKeyHelper\": \"secret-tool lookup service litellm-api-key\" }\n\n# 3. Optional: refresh interval in ms (default 1h):\nexport CLAUDE_CODE_API_KEY_HELPER_TTL_MS=3600000`,\n };\n}\n\ninterface SnippetTabsProps {\n snippets: Snippets;\n model: string;\n copyState: { copy: (text: string) => Promise<boolean>; copied: boolean };\n}\n\ntype SnippetTab = 'curl' | 'openai' | 'opencode' | 'pi' | 'claude-code';\n\nconst SNIPPET_FILE_HINTS: Partial<Record<SnippetTab, string>> = {\n opencode: 'Add to ~/.config/opencode/opencode.json',\n pi: 'Add to ~/.pi/agent/models.json',\n 'claude-code': 'Store the key in your OS keychain and point apiKeyHelper at it in ~/.claude/settings.json',\n};\n\nexport const SnippetTabs: FC<SnippetTabsProps> = ({ snippets, model, copyState }) => {\n const [tab, setTab] = useState<SnippetTab>('curl');\n const snippetKey = tab === 'claude-code' ? 'claudeCode' : tab;\n const code = snippets[snippetKey as keyof Snippets];\n const fileHint = SNIPPET_FILE_HINTS[tab];\n return (\n <Box>\n <Tabs value={tab} onChange={(_, v) => setTab(v as SnippetTab)} sx={{ mb: 1 }} variant=\"scrollable\">\n <Tab label=\"curl\" value=\"curl\" />\n <Tab label=\"OpenAI SDK\" value=\"openai\" />\n <Tab label=\"opencode\" value=\"opencode\" />\n <Tab label=\"pi\" value=\"pi\" />\n <Tab label=\"Claude Code\" value=\"claude-code\" />\n </Tabs>\n {fileHint && (\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mb={0.5}>\n {fileHint}\n </Typography>\n )}\n <Box\n position=\"relative\"\n p={1.5}\n sx={{ backgroundColor: 'action.hover', border: '1px solid', borderColor: 'divider', borderRadius: 1 }}\n >\n <Tooltip title={copyState.copied ? 'Copied' : 'Copy snippet'} placement=\"top\">\n <IconButton\n size=\"small\"\n onClick={() => copyState.copy(code)}\n aria-label=\"Copy snippet\"\n sx={{ position: 'absolute', top: 4, right: 4 }}\n >\n {copyState.copied ? <Check fontSize=\"small\" /> : <ContentCopy fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n <Typography\n component=\"pre\"\n sx={{\n fontFamily: 'monospace',\n fontSize: 12,\n whiteSpace: 'pre-wrap',\n wordBreak: 'break-all',\n mb: 0,\n pr: 4,\n }}\n >\n {code}\n </Typography>\n {model && (\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mt={1}>\n Using model \u201C{model}\u201D \u2014 swap it for any model you have access to.\n </Typography>\n )}\n </Box>\n </Box>\n );\n};\n\n", "import { FC, useEffect, useMemo, useRef, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Button from '@mui/material/Button';\nimport IconButton from '@mui/material/IconButton';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Alert from '@mui/material/Alert';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport Tooltip from '@mui/material/Tooltip';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport Chip from '@mui/material/Chip';\nimport { ContentCopy, Code, ExpandMore, Check } from '@mui/icons-material';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport {\n VirtualKey,\n ModelInfo,\n TeamInfo,\n GenerateKeyRequest,\n GenerateKeyResponse,\n UpdateKeyRequest,\n LiteLlmConfig,\n} from '../types';\nimport { DEFAULT_KEY_DURATIONS, litellmKeyResetSpendPermission, formatDurationLabel } from '@acarmisc/backstage-plugin-litellm-common';\nimport { estimateTokensFromBudget } from '../format';\nimport { useCopyToClipboard } from '../hooks';\nimport { validateKeyForm, firstInvalidField, expiryPreview, priciestInputPrice } from '../keyFormValidation';\n\n/**\n * Single form dialog for both key creation (`mode=\"create\"`) and key editing\n * (`mode=\"edit\"`).\n *\n * Create mode: alias (pre-filled), team, models, duration, budget (+unlimited\n * when gated on), TPM/RPM in the Advanced accordion, and the post-generation\n * screen with copyable key + starter snippets.\n *\n * Edit mode: the same shared fields but no duration (expiry is immutable after\n * creation) and no team switch (LiteLLM /key/update semantics); adds a masked\n * key header and the Danger Zone (reset spend). Budget validation, the\n * unlimited toggle and the team-scoped model filtering behave exactly as they\n * do at creation time.\n */\nimport {\n createForm,\n editForm,\n changedEditFields,\n isModelAllowedByTeam,\n aliasHelperText,\n teamHelperText,\n budgetHelperText,\n} from './keyFormHelpers';\nimport { buildSnippets, SnippetTabs, type Snippets } from './KeySnippets';\n\nexport type KeyFormDialogMode = 'create' | 'edit';\n\nexport interface KeyFormDialogProps {\n open: boolean;\n onClose: () => void;\n /** `create` generates a new key; `edit` updates an existing one. */\n mode: KeyFormDialogMode;\n /** Key being edited (edit mode only). */\n keyToEdit?: VirtualKey | null;\n keys: VirtualKey[];\n models: ModelInfo[];\n modelsError?: Error;\n onRetryModels?: () => void;\n teams: TeamInfo[];\n /** Current user's LiteLLM user id, used to pre-fill a default key alias. */\n username?: string;\n /** Controls for the key form; see litellm.keyGeneration in app-config.yaml. */\n keyGenerationSettings?: { allowUnlimitedBudget: boolean; teamRequired: boolean };\n onCreateKey: (request: GenerateKeyRequest) => Promise<GenerateKeyResponse>;\n onUpdateKey: (keyId: string, request: UpdateKeyRequest) => Promise<void>;\n onResetKeySpend?: (keyId: string) => Promise<void>;\n onGetConfig: () => Promise<LiteLlmConfig>;\n}\n\nexport const KeyFormDialog: FC<KeyFormDialogProps> = ({\n open,\n onClose,\n mode,\n keyToEdit = null,\n keys,\n models,\n modelsError,\n onRetryModels,\n teams,\n username,\n keyGenerationSettings,\n onCreateKey,\n onUpdateKey,\n onResetKeySpend,\n onGetConfig,\n}) => {\n const isCreate = mode === 'create';\n const [generateForm, setGenerateForm] = useState<GenerateKeyRequest>(createForm(username));\n const [editFormState, setEditFormState] = useState<UpdateKeyRequest>({});\n const [unlimitedBudget, setUnlimitedBudget] = useState(false);\n const [submitting, setSubmitting] = useState(false);\n const [newKeyValue, setNewKeyValue] = useState<string | null>(null);\n const [newKeySnippets, setNewKeySnippets] = useState<Snippets | null>(null);\n const [newKeyModel, setNewKeyModel] = useState<string>('');\n const [generateError, setGenerateError] = useState<string | null>(null);\n const [editError, setEditError] = useState<string | null>(null);\n const [resetSpendConfirm, setResetSpendConfirm] = useState(false);\n const [resetSpendSubmitting, setResetSpendSubmitting] = useState(false);\n const [config, setConfig] = useState<LiteLlmConfig | null>(null);\n const [secretCopied, setSecretCopied] = useState(false);\n const [closeWithoutCopyConfirm, setCloseWithoutCopyConfirm] = useState(false);\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n const [submitAttempted, setSubmitAttempted] = useState(false);\n\n // Refs for focusing first invalid field\n const teamInputRef = useRef<HTMLInputElement>(null);\n const aliasInputRef = useRef<HTMLInputElement>(null);\n const budgetInputRef = useRef<HTMLInputElement>(null);\n\n // Clipboard hook for all copy operations\n const clipboardSecret = useCopyToClipboard();\n const clipboardSnippet = useCopyToClipboard();\n const clipboardEndpoint = useCopyToClipboard();\n\n // Permission check for reset spend\n const resetSpendPermission = usePermission({ permission: litellmKeyResetSpendPermission });\n const canResetSpend = !resetSpendPermission.loading && resetSpendPermission.allowed;\n\n // Re-arm the form each time the dialog opens so a stale result from a\n // previous run (or another user's session) is never shown.\n useEffect(() => {\n if (open) {\n if (isCreate) {\n setGenerateForm(createForm(username));\n } else if (keyToEdit) {\n setEditFormState(editForm(keyToEdit));\n setUnlimitedBudget(\n keyGenerationSettings?.allowUnlimitedBudget === true &&\n (keyToEdit.max_budget === null || keyToEdit.max_budget === undefined),\n );\n } else {\n setEditFormState({});\n setUnlimitedBudget(false);\n }\n setNewKeyValue(null);\n setNewKeySnippets(null);\n setNewKeyModel('');\n setGenerateError(null);\n setEditError(null);\n setResetSpendConfirm(false);\n setSecretCopied(false);\n setCloseWithoutCopyConfirm(false);\n setTouched({});\n setSubmitAttempted(false);\n }\n }, [open, isCreate, keyToEdit, username, keyGenerationSettings?.allowUnlimitedBudget]);\n\n // Fetch config to check key action capabilities. Kept separate from the\n // reset effect above and reading `onGetConfig` through a ref: parents often\n // pass an inline callback, and depending on its identity would re-run the\n // reset on every parent render, wiping a freshly generated key (or the\n // user's in-progress input).\n const onGetConfigRef = useRef(onGetConfig);\n onGetConfigRef.current = onGetConfig;\n useEffect(() => {\n if (!open) return undefined;\n let cancelled = false;\n onGetConfigRef.current()\n .then(c => { if (!cancelled) setConfig(c); })\n .catch(() => { if (!cancelled) setConfig(null); });\n return () => { cancelled = true; };\n }, [open]);\n\n const allowUnlimitedBudget = keyGenerationSettings?.allowUnlimitedBudget ?? false;\n const teamRequired = keyGenerationSettings?.teamRequired ?? true;\n\n const formData = isCreate ? generateForm : editFormState;\n const setFormData = (patch: Partial<GenerateKeyRequest> & Partial<UpdateKeyRequest>) => {\n if (isCreate) {\n setGenerateForm(prev => ({ ...prev, ...patch }));\n } else {\n setEditFormState(prev => ({ ...prev, ...patch }));\n }\n };\n\n // Create mode names the field `alias`; edit mode `key_alias` (matching the\n // LiteLLM payload shapes). One accessor keeps the shared JSX mode-agnostic.\n const currentAlias = (isCreate ? generateForm.alias : editFormState.key_alias) ?? '';\n const setAliasField = (value: string) => {\n if (isCreate) setFormData({ alias: value });\n else setFormData({ key_alias: value });\n };\n\n const selectedTeam = teams.find(t => t.team_id === (isCreate ? generateForm.team_id : undefined)) ?? null;\n\n // In edit mode, filter models by the key's team_id (fixed after creation).\n // In create mode, filter by the currently selected team.\n const teamIdForModels = isCreate ? generateForm.team_id : keyToEdit?.team_id;\n const teamForModels = teams.find(t => t.team_id === teamIdForModels) ?? null;\n\n // Once a team is selected, only offer models that team is actually allowed\n // to use \u2014 `models` here is already scoped to what the user can access.\n // Applies on edit too, so a key can no longer drift out of its team's\n // allowlist via /key/update.\n const availableModels = useMemo(() => {\n return models.filter(m => isModelAllowedByTeam(m, teamForModels?.models));\n }, [models, teamForModels]);\n\n const selectedModels = availableModels.filter(m => (formData.models || []).includes(m.model_name));\n\n // \u2500\u2500 Validation using the validation module \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const validationErrors = validateKeyForm(formData, {\n teamRequired,\n unlimitedBudget,\n isCreate,\n });\n\n // Show errors only if the field was touched or submit was attempted\n const showError = (field: string) => touched[field] || submitAttempted;\n const aliasError = showError('alias') && !!validationErrors.alias;\n const teamError = showError('team') && !!validationErrors.team;\n const budgetInvalid = showError('budget') && !!validationErrors.budget;\n\n // Issue #35: warn (don't block) when the alias already matches one of the\n // user's loaded keys \u2014 LiteLLM enforces globally-unique aliases.\n const aliasDuplicate = !!currentAlias && keys.some(k => k.key_alias === currentAlias && k !== keyToEdit);\n\n // \u2500\u2500 Budget estimate at the priciest selected model's input rate \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const budgetEstimate = useMemo(() => {\n if (unlimitedBudget || budgetInvalid) return null;\n const pricePerToken = priciestInputPrice(selectedModels);\n if (pricePerToken === null) return null;\n return estimateTokensFromBudget(formData.max_budget ?? 0, pricePerToken);\n }, [formData.max_budget, selectedModels, unlimitedBudget, budgetInvalid]);\n\n const handleGenerate = async () => {\n // Validate before submitting\n const errors = validateKeyForm(generateForm, {\n teamRequired,\n unlimitedBudget,\n isCreate: true,\n });\n\n if (Object.keys(errors).length > 0) {\n setSubmitAttempted(true);\n // Focus first invalid field\n const firstInvalid = firstInvalidField(errors, true);\n if (firstInvalid === 'team' && teamInputRef.current) {\n teamInputRef.current.focus();\n } else if (firstInvalid === 'alias' && aliasInputRef.current) {\n aliasInputRef.current.focus();\n } else if (firstInvalid === 'budget' && budgetInputRef.current) {\n budgetInputRef.current.focus();\n }\n return;\n }\n\n setSubmitting(true);\n setGenerateError(null);\n try {\n const request: GenerateKeyRequest = {\n ...(generateForm as GenerateKeyRequest),\n max_budget: unlimitedBudget ? null : generateForm.max_budget,\n };\n const response = await onCreateKey(request);\n // When the key allows all models (none explicitly picked), fall back to\n // the first model actually allowed for the chosen team so snippets show\n // a working example rather than an empty model name.\n const model = generateForm.models?.[0] ?? availableModels[0]?.model_name ?? '';\n setNewKeyValue(response.key);\n setNewKeyModel(model);\n setNewKeySnippets(null);\n try {\n const fetchedConfig = await onGetConfig();\n if (fetchedConfig.baseUrl) {\n setNewKeySnippets(buildSnippets(fetchedConfig.baseUrl, response.key, model));\n }\n } catch {\n // Snippets are a nice-to-have; the raw key is still shown.\n }\n setGenerateForm(createForm(username));\n setUnlimitedBudget(false);\n } catch (error: any) {\n setGenerateError(error?.message ?? 'Failed to generate key');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleUpdate = async () => {\n if (!keyToEdit) return;\n\n // Validate before submitting\n const errors = validateKeyForm(editFormState, {\n teamRequired,\n unlimitedBudget,\n isCreate: false,\n });\n\n if (Object.keys(errors).length > 0) {\n setSubmitAttempted(true);\n // Focus first invalid field\n const firstInvalid = firstInvalidField(errors, false);\n if (firstInvalid === 'alias' && aliasInputRef.current) {\n aliasInputRef.current.focus();\n } else if (firstInvalid === 'budget' && budgetInputRef.current) {\n budgetInputRef.current.focus();\n }\n return;\n }\n\n setSubmitting(true);\n setEditError(null);\n try {\n const request = changedEditFields(editForm(keyToEdit), editFormState, unlimitedBudget);\n if (Object.keys(request).length > 0) {\n await onUpdateKey(keyToEdit.token ?? keyToEdit.key, request);\n }\n onClose();\n } catch (error: any) {\n setEditError(error?.message ?? 'Failed to update key');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleResetSpend = async () => {\n if (!keyToEdit || !onResetKeySpend) return;\n setResetSpendSubmitting(true);\n try {\n await onResetKeySpend(keyToEdit.token ?? keyToEdit.key);\n setResetSpendConfirm(false);\n onClose();\n } catch (e: any) {\n // Keep the dialog open and say what went wrong instead of closing as if it worked.\n setResetSpendConfirm(false);\n setEditError(e?.message ?? 'Failed to reset spend');\n } finally {\n setResetSpendSubmitting(false);\n }\n };\n\n const handleCloseWithoutConfirm = () => {\n onClose();\n setGenerateError(null);\n setEditError(null);\n setNewKeyValue(null);\n setNewKeySnippets(null);\n setGenerateForm(createForm(username));\n setEditFormState({});\n setUnlimitedBudget(false);\n setResetSpendConfirm(false);\n setSecretCopied(false);\n setCloseWithoutCopyConfirm(false);\n };\n\n // Handle close when showing the secret \u2014 check if copied first\n const handleCloseSecretDialog = () => {\n if (newKeyValue && !secretCopied) {\n // Show confirmation before closing\n setCloseWithoutCopyConfirm(true);\n } else {\n handleCloseWithoutConfirm();\n }\n };\n\n const handleConfirmCloseWithoutCopy = () => {\n setCloseWithoutCopyConfirm(false);\n handleCloseWithoutConfirm();\n };\n\n // Handle Dialog close events (Escape, backdrop click)\n const handleDialogClose = (_event: unknown, reason: string) => {\n // If showing a secret, ignore backdrop and escape\n if (newKeyValue && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n handleCloseSecretDialog();\n };\n\n const modelOption = (m: ModelInfo) => {\n const inCost = fmtCost(m.input_cost_per_token);\n const outCost = fmtCost(m.output_cost_per_token);\n const ctx = formatContextWindow(m.max_input_tokens, m.max_output_tokens);\n return (\n <Box>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5, mb: 0.5 }}>\n <span>{m.model_name}</span>\n {m.supports_function_calling && <Chip size=\"small\" variant=\"outlined\" label=\"Tools\" />}\n {m.supports_vision && <Chip size=\"small\" variant=\"outlined\" label=\"Vision\" />}\n </Box>\n {ctx && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ ml: 1 }}>\n {ctx}\n </Typography>\n )}\n {(inCost || outCost) && (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ ml: 1 }}>\n {inCost} in \u00B7 {outCost} out\n </Typography>\n )}\n </Box>\n );\n };\n\n const renderTeamField = () => {\n if (teams.length > 0) {\n return (\n <Autocomplete\n options={teams}\n getOptionLabel={t => t.team_alias || t.team_id}\n value={selectedTeam}\n onChange={(_e, team) => {\n const restrictedModels = (formData.models || []).filter(name => {\n const model = models.find(m => m.model_name === name);\n return model ? isModelAllowedByTeam(model, team?.models) : false;\n });\n setFormData({ team_id: team?.team_id, models: restrictedModels });\n }}\n disabled={!isCreate}\n onBlur={() => setTouched(prev => ({ ...prev, team: true }))}\n renderInput={params => (\n <TextField\n {...params}\n inputRef={teamInputRef}\n label=\"Team\"\n error={teamError}\n helperText={\n isCreate\n ? teamHelperText(teamError, teamRequired)\n : 'Team binding is fixed after creation \u2014 delete and recreate the key to change it'\n }\n required={isCreate && teamRequired}\n fullWidth\n />\n )}\n />\n );\n }\n if (teamRequired && isCreate) {\n return (\n <Typography variant=\"body2\" color=\"error\">\n Team selection is required, but you don't belong to any team yet \u2014 contact your administrator.\n </Typography>\n );\n }\n return null;\n };\n\n const editKeyId = keyToEdit?.token ?? keyToEdit?.key ?? '';\n\n const renderDangerZone = () => {\n if (isCreate || !onResetKeySpend) return null;\n // Hide the danger zone if allowOwnerResetSpend is false or permission not granted\n if (!config?.keyActions?.allowOwnerResetSpend || !canResetSpend) return null;\n return (\n <Box mt={1} pt={2} borderTop=\"1px solid\" sx={{ borderColor: 'divider' }}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" mb={1}>\n Danger Zone\n </Typography>\n {!resetSpendConfirm ? (\n <Button\n size=\"small\"\n color=\"warning\"\n variant=\"outlined\"\n onClick={() => setResetSpendConfirm(true)}\n >\n Reset Spend to $0\n </Button>\n ) : (\n <Box display=\"flex\" alignItems=\"center\" gap={1} flexWrap=\"wrap\">\n <Typography variant=\"body2\" color=\"warning.main\">\n Zero out spend counter?\n </Typography>\n <Button\n size=\"small\"\n color=\"warning\"\n variant=\"contained\"\n disabled={resetSpendSubmitting}\n onClick={handleResetSpend}\n >\n {resetSpendSubmitting ? <CircularProgress size={16} /> : 'Confirm'}\n </Button>\n <Button size=\"small\" onClick={() => setResetSpendConfirm(false)}>\n Cancel\n </Button>\n </Box>\n )}\n </Box>\n );\n };\n\n const maskKey = (key: string): string => {\n if (key.length <= 8) return '***';\n return `${key.slice(0, 4)}...${key.slice(-4)}`;\n };\n\n let dialogTitle = 'Edit Key';\n if (newKeyValue) dialogTitle = 'Key Generated';\n else if (isCreate) dialogTitle = 'Generate New Key';\n\n const submitLabel = isCreate ? 'Generate' : 'Save';\n return (\n <Dialog\n open={open}\n onClose={handleDialogClose}\n disableEscapeKeyDown={!!newKeyValue}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>{dialogTitle}</DialogTitle>\n <DialogContent>\n {newKeyValue ? (\n <Box>\n <Alert severity=\"warning\" sx={{ mb: 2 }}>\n Copy this key now. It will never be shown again.\n </Alert>\n <Box\n display=\"flex\"\n alignItems=\"center\"\n gap={1}\n mt={2}\n p={2}\n sx={{\n backgroundColor: 'action.hover',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n }}\n >\n <Typography\n component=\"code\"\n color=\"text.primary\"\n sx={{ fontFamily: 'monospace', wordBreak: 'break-all', flex: 1 }}\n >\n {newKeyValue}\n </Typography>\n <Tooltip title={clipboardSecret.copied ? 'Copied' : 'Copy API key'} placement=\"top\">\n <IconButton\n aria-label=\"Copy API key\"\n onClick={async () => {\n const success = await clipboardSecret.copy(newKeyValue);\n if (success) {\n setSecretCopied(true);\n }\n }}\n >\n {clipboardSecret.copied ? <Check /> : <ContentCopy />}\n </IconButton>\n </Tooltip>\n </Box>\n\n {newKeyValue && !newKeySnippets && (\n <Box mt={2}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" gutterBottom>\n Public endpoint\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\">\n Endpoint not configured\n </Typography>\n </Box>\n )}\n\n {newKeySnippets && (\n <Box mt={2}>\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\" gutterBottom>\n Public endpoint \u2014 paste into any tool's base URL / API base field\n </Typography>\n <Box\n display=\"flex\"\n alignItems=\"center\"\n gap={1}\n p={1.5}\n sx={{\n backgroundColor: 'action.hover',\n border: '1px solid',\n borderColor: 'divider',\n borderRadius: 1,\n }}\n >\n <Typography\n component=\"code\"\n color=\"text.primary\"\n sx={{ fontFamily: 'monospace', fontSize: 13, wordBreak: 'break-all', flex: 1 }}\n >\n {newKeySnippets.publicEndpoint}\n </Typography>\n <Tooltip title={clipboardEndpoint.copied ? 'Copied' : 'Copy endpoint'} placement=\"top\">\n <IconButton\n size=\"small\"\n aria-label=\"Copy endpoint\"\n onClick={() => clipboardEndpoint.copy(newKeySnippets.publicEndpoint)}\n >\n {clipboardEndpoint.copied ? <Check fontSize=\"small\" /> : <ContentCopy fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n </Box>\n )}\n\n {newKeySnippets && (\n <Box mt={3}>\n <Box display=\"flex\" alignItems=\"center\" gap={1} mb={1}>\n <Code fontSize=\"small\" color=\"action\" />\n <Typography variant=\"subtitle2\">\n Start calling the proxy \u2014 paste and run\n </Typography>\n </Box>\n <SnippetTabs snippets={newKeySnippets} model={newKeyModel} copyState={clipboardSnippet} />\n </Box>\n )}\n </Box>\n ) : (\n <Box display=\"flex\" flexDirection=\"column\" gap={2} mt={1}>\n {!isCreate && (\n <Typography variant=\"body2\" color=\"text.secondary\">\n <code style={{ fontFamily: 'monospace', color: 'inherit' }}>{maskKey(editKeyId)}</code>\n </Typography>\n )}\n {generateError && (\n <Alert severity=\"error\" onClose={() => setGenerateError(null)}>\n {generateError}\n </Alert>\n )}\n {editError && (\n <Alert severity=\"error\" onClose={() => setEditError(null)}>\n {editError}\n </Alert>\n )}\n\n {/* Field order: Team \u2192 Models \u2192 Budget \u2192 Duration \u2192 Alias \u2192 Advanced */}\n {renderTeamField()}\n\n {(availableModels.length > 0 || modelsError) && (\n <>\n {modelsError ? (\n <TextField\n label=\"Models\"\n disabled\n value=\"\"\n helperText=\"Couldn't load models. Retry\"\n fullWidth\n />\n ) : (\n <Autocomplete\n multiple\n options={availableModels}\n groupBy={m => m.mode || 'other'}\n getOptionLabel={m => m.model_name}\n value={selectedModels}\n onChange={(_e, selected) =>\n setFormData({ models: selected.map(m => m.model_name) })\n }\n renderOption={(props, m) => <li {...props}>{modelOption(m)}</li>}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Models\"\n helperText={\n teamForModels\n ? 'Leave empty to allow all models available to this team'\n : 'Leave empty to allow all models'\n }\n fullWidth\n />\n )}\n />\n )}\n {modelsError && onRetryModels && (\n <Button size=\"small\" onClick={onRetryModels}>\n Retry\n </Button>\n )}\n </>\n )}\n\n {allowUnlimitedBudget && (\n <FormControlLabel\n control={\n <Checkbox\n checked={unlimitedBudget}\n onChange={(e) => {\n setUnlimitedBudget(e.target.checked);\n if (e.target.checked) {\n setFormData({ max_budget: null });\n } else {\n setFormData({ max_budget: editFormState.max_budget ?? generateForm.max_budget ?? 100 });\n }\n }}\n />\n }\n label=\"Unlimited budget\"\n />\n )}\n <TextField\n inputRef={budgetInputRef}\n label=\"Max Budget\"\n type=\"number\"\n value={unlimitedBudget ? '' : formData.max_budget ?? ''}\n onChange={(e) => {\n setFormData({ max_budget: e.target.value ? Number(e.target.value) : undefined });\n setGenerateError(null);\n setEditError(null);\n }}\n onBlur={() => setTouched(prev => ({ ...prev, budget: true }))}\n error={budgetInvalid}\n helperText={budgetHelperText(budgetInvalid, budgetEstimate, unlimitedBudget)}\n disabled={unlimitedBudget}\n required\n fullWidth\n InputProps={{\n startAdornment: <InputAdornment position=\"start\">$</InputAdornment>,\n }}\n inputProps={{ min: 0, step: 0.01 }}\n />\n\n {!isCreate ? null : (\n <>\n <TextField\n select\n label=\"Duration\"\n value={generateForm.duration || '30d'}\n onChange={(e) => setFormData({ duration: e.target.value })}\n fullWidth\n >\n {DEFAULT_KEY_DURATIONS.map((duration) => (\n <MenuItem key={duration} value={duration}>\n {formatDurationLabel(duration)}\n </MenuItem>\n ))}\n </TextField>\n {generateForm.duration && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {expiryPreview(generateForm.duration)}\n </Typography>\n )}\n </>\n )}\n\n <TextField\n inputRef={aliasInputRef}\n label=\"Alias\"\n value={currentAlias}\n onChange={(e) => {\n setAliasField(e.target.value);\n setGenerateError(null);\n setEditError(null);\n }}\n onBlur={() => setTouched(prev => ({ ...prev, alias: true }))}\n error={aliasError}\n color={aliasDuplicate ? 'warning' : undefined}\n helperText={aliasHelperText(aliasError, aliasDuplicate)}\n required\n fullWidth\n />\n\n <Accordion disableGutters elevation={0} sx={{ border: '1px solid', borderColor: 'divider', '&:before': { display: 'none' } }}>\n <AccordionSummary expandIcon={<ExpandMore />}>\n <Typography variant=\"body2\" fontWeight={600}>Advanced</Typography>\n </AccordionSummary>\n <AccordionDetails sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <TextField\n label=\"TPM Limit\"\n type=\"number\"\n value={formData.tpm_limit ?? ''}\n onChange={(e) =>\n setFormData({ tpm_limit: e.target.value ? Number(e.target.value) : undefined })\n }\n helperText=\"Max tokens per minute this key can consume across all models. Leave blank for no limit.\"\n fullWidth\n />\n <TextField\n label=\"RPM Limit\"\n type=\"number\"\n value={formData.rpm_limit ?? ''}\n onChange={(e) =>\n setFormData({ rpm_limit: e.target.value ? Number(e.target.value) : undefined })\n }\n helperText=\"Max requests per minute this key can make across all models. Leave blank for no limit.\"\n fullWidth\n />\n </AccordionDetails>\n </Accordion>\n {renderDangerZone()}\n </Box>\n )}\n </DialogContent>\n <DialogActions>\n {newKeyValue ? (\n <Button onClick={handleCloseSecretDialog} variant=\"contained\" color=\"success\">\n Done\n </Button>\n ) : (\n <>\n <Button onClick={handleCloseWithoutConfirm}>Cancel</Button>\n <Button\n onClick={isCreate ? handleGenerate : handleUpdate}\n variant=\"contained\"\n color=\"primary\"\n disabled={submitting}\n >\n {submitting ? <CircularProgress size={24} /> : submitLabel}\n </Button>\n </>\n )}\n </DialogActions>\n\n {/* Confirm close without copying the secret */}\n <Dialog open={closeWithoutCopyConfirm} onClose={() => setCloseWithoutCopyConfirm(false)} maxWidth=\"xs\" fullWidth>\n <DialogTitle>Close Without Copying?</DialogTitle>\n <DialogContent>\n <Typography>\n You haven't copied the key. Close anyway?\n </Typography>\n </DialogContent>\n <DialogActions>\n <Button onClick={() => setCloseWithoutCopyConfirm(false)}>\n Go back\n </Button>\n <Button\n onClick={handleConfirmCloseWithoutCopy}\n variant=\"contained\"\n color=\"error\"\n >\n Close anyway\n </Button>\n </DialogActions>\n </Dialog>\n </Dialog>\n );\n};\n\nfunction fmtCost(perToken?: number): string | null {\n if (!perToken) return null;\n const per1k = perToken * 1000;\n return per1k < 0.01 ? `$${(perToken * 1_000_000).toFixed(2)}/M` : `$${per1k.toFixed(3)}/1K`;\n}\n\nfunction formatContextWindow(\n maxInput?: number,\n maxOutput?: number,\n): string | null {\n if (!maxInput && !maxOutput) return null;\n const fmt = (n?: number) => {\n if (!n) return null;\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${Math.round(n / 1000)}K`;\n return String(n);\n };\n const inPart = fmt(maxInput);\n const outPart = fmt(maxOutput);\n if (inPart && outPart) return `ctx ${inPart} in / ${outPart} out`;\n if (inPart) return `ctx ${inPart}`;\n if (outPart) return `ctx ${outPart} out`;\n return null;\n}", "import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport Dialog from '@mui/material/Dialog';\nimport DialogTitle from '@mui/material/DialogTitle';\nimport DialogContent from '@mui/material/DialogContent';\nimport DialogActions from '@mui/material/DialogActions';\nimport TextField from '@mui/material/TextField';\nimport Button from '@mui/material/Button';\nimport Alert from '@mui/material/Alert';\nimport Checkbox from '@mui/material/Checkbox';\nimport FormControlLabel from '@mui/material/FormControlLabel';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport MenuItem from '@mui/material/MenuItem';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport Typography from '@mui/material/Typography';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport Paper from '@mui/material/Paper';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport { Delete as DeleteIcon } from '@mui/icons-material';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { stringifyEntityRef, UserEntity } from '@backstage/catalog-model';\nimport { TeamInfo, ModelInfo, LiteLlmConfig, CreateTeamRequest, UpdateTeamRequest, VectorStoreInfo, McpServerInfo } from '../types';\nimport { StatusPill, dataTableSx } from './ui';\n\n/** A catalog User entity flattened into what the member picker needs. */\nexport interface InitialMember {\n userEntityRef: string;\n maxBudgetInTeam?: number;\n}\n\n/** A member picked while creating a team, added after the team exists. */\ninterface PendingMember extends InitialMember {\n label: string;\n}\n\ninterface UserOption {\n ref: string;\n label: string;\n email?: string;\n}\n\n/** Spend-reset periods offered for a team budget (LiteLLM `budget_duration`). */\nconst BUDGET_DURATION_OPTIONS: Array<{ value: string; label: string }> = [\n { value: '1d', label: 'Daily (1d)' },\n { value: '7d', label: 'Weekly (7d)' },\n { value: '30d', label: 'Monthly (30d)' },\n { value: '90d', label: 'Quarterly (90d)' },\n { value: '365d', label: 'Yearly (365d)' },\n];\nconst DEFAULT_BUDGET_DURATION = '30d';\nconst FALLBACK_BUDGET_CEILING = 1000;\n\ninterface ManageTeamDialogProps {\n open: boolean;\n onClose: () => void;\n mode: 'create' | 'edit';\n team?: TeamInfo;\n allModels: ModelInfo[];\n config?: LiteLlmConfig;\n /**\n * Saves the team. In create mode, `initialMembers` lists the members picked\n * in the dialog; the parent adds them once the team exists.\n */\n onSubmit: (\n payload: CreateTeamRequest | UpdateTeamRequest,\n initialMembers?: InitialMember[],\n ) => Promise<void>;\n /** When true, the Members section (edit mode only) exposes add/remove controls. */\n canManageMembers?: boolean;\n /** Called to add a member; the parent is expected to refresh `team` on success. */\n onAddMember?: (userEntityRef: string, maxBudgetInTeam?: number) => Promise<void>;\n /** Called to remove a member; the parent is expected to refresh `team` on success. */\n onRemoveMember?: (userEntityRef: string) => Promise<void>;\n /** When true, the Knowledge Bases section (edit mode only) is shown. */\n canManageKnowledgeBases?: boolean;\n /** Vector stores the caller may attach (already allowlist-filtered server-side). */\n vectorStores?: VectorStoreInfo[];\n /** Called to replace the team's attached knowledge bases; parent refreshes `team`. */\n onSaveKnowledgeBases?: (vectorStoreIds: string[]) => Promise<void>;\n /** When true, the MCP Servers section (edit mode only) is shown. */\n canManageMcpServers?: boolean;\n /** MCP servers the caller may attach (already allowlist-filtered server-side). */\n mcpServers?: McpServerInfo[];\n /** Called to replace the team's attached MCP servers; parent refreshes `team`. */\n onSaveMcpServers?: (mcpServerIds: string[]) => Promise<void>;\n /** When true, only members section is shown (not budget/models/KB/MCP); title changes; Save becomes Done. */\n membersOnly?: boolean;\n /** Current user's LiteLLM ID; used in membersOnly mode to prevent self-removal and role-restricted removal. */\n currentUserId?: string;\n /** Roles that can manage members in membersOnly mode; used to disable removal of role holders. */\n memberManagerRoles?: string[];\n}\n\nexport const ManageTeamDialog: FC<ManageTeamDialogProps> = ({\n open,\n onClose,\n mode,\n team,\n allModels,\n config,\n onSubmit,\n canManageMembers,\n onAddMember,\n onRemoveMember,\n canManageKnowledgeBases,\n vectorStores,\n onSaveKnowledgeBases,\n canManageMcpServers,\n mcpServers,\n onSaveMcpServers,\n membersOnly,\n currentUserId,\n memberManagerRoles,\n}) => {\n const [alias, setAlias] = useState('');\n const [models, setModels] = useState<string[]>([]);\n const [maxBudget, setMaxBudget] = useState<string>('');\n const [unlimited, setUnlimited] = useState(false);\n const [budgetDuration, setBudgetDuration] = useState('');\n const [submitting, setSubmitting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n // memberQuery is the text shown in the picker; memberRef is the entity ref\n // that will actually be submitted (either a picked catalog user's ref, or\n // whatever was typed, as a fallback for catalog lookup failures).\n const [memberQuery, setMemberQuery] = useState('');\n const [memberRef, setMemberRef] = useState('');\n const [memberBudget, setMemberBudget] = useState('');\n const [memberBusy, setMemberBusy] = useState(false);\n const [memberError, setMemberError] = useState<string | null>(null);\n const [pendingMembers, setPendingMembers] = useState<PendingMember[]>([]);\n\n const [kbIds, setKbIds] = useState<string[]>([]);\n const [kbBusy, setKbBusy] = useState(false);\n const [kbError, setKbError] = useState<string | null>(null);\n\n const [mcpIds, setMcpIds] = useState<string[]>([]);\n const [mcpBusy, setMcpBusy] = useState(false);\n const [mcpError, setMcpError] = useState<string | null>(null);\n\n const allowUnlimitedBudget = config?.teamManagement?.allowUnlimitedBudget ?? false;\n const maxBudgetCeiling =\n config?.teamManagement?.maxBudgetCeiling ?? FALLBACK_BUDGET_CEILING;\n // When budgets are hidden even from managers, the field becomes write-only:\n // the current value is never shown, and leaving it blank keeps it unchanged.\n const hideBudgetForManagers = config?.display?.hideTeamBudgetForManagers ?? false;\n const budgetWriteOnly = hideBudgetForManagers && mode === 'edit';\n\n const creating = mode === 'create';\n // While creating, the table lists the picked members (added on save).\n const members = useMemo(\n () =>\n creating\n ? pendingMembers.map(p => ({\n user_id: p.userEntityRef,\n user_email: p.label,\n role: 'user',\n }))\n : team?.members_with_roles ?? [],\n [creating, pendingMembers, team],\n );\n const showMembers = !!canManageMembers || !!membersOnly;\n // Settings and members side by side; members-only stays a narrow dialog.\n const wide = showMembers && !membersOnly;\n\n // Catalog users for the member picker, fetched on demand with debounced search.\n // Failures degrade to an empty option list \u2014 the field stays usable as a\n // plain entity-ref input either way.\n const catalogApi = useApi(catalogApiRef);\n const [searchUsers, setSearchUsers] = useState<UserEntity[]>([]);\n const [usersLoading, setUsersLoading] = useState(false);\n const debounceTimerRef = useRef<NodeJS.Timeout>();\n\n const handleUserSearch = useCallback(async (term: string) => {\n // Clear any pending debounce.\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n\n if (!term.trim()) {\n setSearchUsers([]);\n return;\n }\n\n setUsersLoading(true);\n debounceTimerRef.current = setTimeout(async () => {\n try {\n const { items } = await catalogApi.queryEntities({\n filter: { kind: 'User' },\n fullTextFilter: {\n term: term.trim(),\n fields: ['metadata.name', 'spec.profile.displayName', 'spec.profile.email'],\n },\n limit: 20,\n });\n setSearchUsers(items as UserEntity[]);\n } catch {\n setSearchUsers([]);\n } finally {\n setUsersLoading(false);\n }\n }, 300); // 300ms debounce\n }, [catalogApi]);\n\n const userOptions = useMemo<UserOption[]>(() => {\n const existingEmails = new Set(\n members\n .map(m => m.user_email?.toLowerCase())\n .filter((e): e is string => !!e),\n );\n return (searchUsers ?? [])\n .map(e => {\n const ref = stringifyEntityRef(e);\n const displayName =\n e.spec?.profile?.displayName || e.metadata.title || e.metadata.name;\n const email = e.spec?.profile?.email;\n return {\n ref,\n email,\n label: email ? `${displayName} (${email})` : displayName,\n };\n })\n .filter(o => !(o.email && existingEmails.has(o.email.toLowerCase())))\n .filter(o => !pendingMembers.some(p => p.userEntityRef === o.ref))\n .sort((a, b) => a.label.localeCompare(b.label));\n }, [searchUsers, members, pendingMembers]);\n\n // Clean up debounce timer on unmount.\n useEffect(() => {\n return () => {\n if (debounceTimerRef.current) {\n clearTimeout(debounceTimerRef.current);\n }\n };\n }, []);\n\n useEffect(() => {\n if (open) {\n if (mode === 'edit' && team) {\n setAlias(team.team_alias ?? '');\n setModels(team.models ?? []);\n if (hideBudgetForManagers) {\n // Write-only: never prefill (the backend redacts the value anyway).\n setMaxBudget('');\n } else {\n setMaxBudget(\n team.max_budget ? String(team.max_budget) : String(maxBudgetCeiling),\n );\n }\n setUnlimited(allowUnlimitedBudget && !team.max_budget);\n setBudgetDuration(team.budget_duration ?? DEFAULT_BUDGET_DURATION);\n } else {\n setAlias('');\n setModels([]);\n // Default a new team's budget to the ceiling; the admin can lower it.\n setMaxBudget(String(maxBudgetCeiling));\n setUnlimited(allowUnlimitedBudget);\n setBudgetDuration(DEFAULT_BUDGET_DURATION);\n }\n setError(null);\n setMemberQuery('');\n setMemberRef('');\n setMemberBudget('');\n setMemberError(null);\n setPendingMembers([]);\n setKbIds(team?.object_permission?.vector_stores ?? []);\n setKbError(null);\n setMcpIds(team?.object_permission?.mcp_servers ?? []);\n setMcpError(null);\n }\n }, [open, mode, team, allowUnlimitedBudget, maxBudgetCeiling, hideBudgetForManagers]);\n\n const handleSubmit = async () => {\n setError(null);\n\n if (!alias.trim()) {\n setError('Team alias is required');\n return;\n }\n\n if (models.length === 0) {\n setError('At least one model is required');\n return;\n }\n\n if (!unlimited) {\n // Write-only mode: a blank budget leaves the hidden value unchanged.\n const budgetLeftBlank = budgetWriteOnly && !maxBudget.trim();\n if (!budgetLeftBlank) {\n if (!maxBudget) {\n setError('Budget is required when unlimited budgets are disabled');\n return;\n }\n const budget = parseFloat(maxBudget);\n if (isNaN(budget) || budget <= 0) {\n setError('Budget must be a positive number');\n return;\n }\n if (budget > maxBudgetCeiling) {\n setError(`Budget cannot exceed $${maxBudgetCeiling}`);\n return;\n }\n }\n }\n\n try {\n setSubmitting(true);\n let payload: CreateTeamRequest | UpdateTeamRequest;\n\n if (mode === 'create') {\n payload = {\n team_alias: alias.trim(),\n models,\n ...(unlimited ? { max_budget: null } : { max_budget: parseFloat(maxBudget) }),\n ...(budgetDuration && { budget_duration: budgetDuration }),\n } as CreateTeamRequest;\n } else {\n // Write-only mode: a blank budget omits the field (leave unchanged).\n // Otherwise validation above guarantees a non-empty value here.\n let budgetField: { max_budget?: number | null } = {};\n if (unlimited) {\n budgetField = { max_budget: null };\n } else if (maxBudget.trim()) {\n budgetField = { max_budget: parseFloat(maxBudget) };\n }\n payload = {\n team_alias: alias.trim(),\n models,\n ...budgetField,\n ...(budgetDuration && { budget_duration: budgetDuration }),\n } as UpdateTeamRequest;\n }\n\n await onSubmit(\n payload,\n creating\n ? pendingMembers.map(({ userEntityRef, maxBudgetInTeam }) => ({\n userEntityRef,\n ...(maxBudgetInTeam !== undefined && { maxBudgetInTeam }),\n }))\n : undefined,\n );\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : 'An error occurred');\n } finally {\n setSubmitting(false);\n }\n };\n\n const handleAddMember = async () => {\n if (!memberRef.trim() || (!creating && !onAddMember)) return;\n setMemberError(null);\n // Members-only managers cannot set member budgets (server refuses it).\n const budget =\n !membersOnly && memberBudget ? parseFloat(memberBudget) : undefined;\n if (budget !== undefined && (isNaN(budget) || budget <= 0)) {\n setMemberError('Max budget in team must be a positive number');\n return;\n }\n if (creating) {\n const ref = memberRef.trim();\n if (!pendingMembers.some(p => p.userEntityRef === ref)) {\n setPendingMembers(list => [\n ...list,\n { userEntityRef: ref, label: memberQuery.trim() || ref, maxBudgetInTeam: budget },\n ]);\n }\n setMemberQuery('');\n setMemberRef('');\n setMemberBudget('');\n return;\n }\n try {\n setMemberBusy(true);\n await onAddMember!(memberRef.trim(), budget);\n setMemberQuery('');\n setMemberRef('');\n setMemberBudget('');\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to add member');\n } finally {\n setMemberBusy(false);\n }\n };\n\n const handleRemoveMember = async (userId: string) => {\n if (creating) {\n setPendingMembers(list => list.filter(p => p.userEntityRef !== userId));\n return;\n }\n if (!onRemoveMember) return;\n setMemberError(null);\n try {\n setMemberBusy(true);\n await onRemoveMember(userId);\n } catch (err) {\n setMemberError(err instanceof Error ? err.message : 'Failed to remove member');\n } finally {\n setMemberBusy(false);\n }\n };\n\n const handleSaveKnowledgeBases = async () => {\n if (!onSaveKnowledgeBases) return;\n setKbError(null);\n try {\n setKbBusy(true);\n await onSaveKnowledgeBases(kbIds);\n } catch (err) {\n setKbError(err instanceof Error ? err.message : 'Failed to save knowledge bases');\n } finally {\n setKbBusy(false);\n }\n };\n\n const handleSaveMcpServers = async () => {\n if (!onSaveMcpServers) return;\n setMcpError(null);\n try {\n setMcpBusy(true);\n await onSaveMcpServers(mcpIds);\n } catch (err) {\n setMcpError(err instanceof Error ? err.message : 'Failed to save MCP servers');\n } finally {\n setMcpBusy(false);\n }\n };\n\n const modelNames = allModels.map(m => m.model_name);\n // Keep an unusual existing value (e.g. \"14d\", \"1mo\") selectable so editing a\n // team doesn't silently rewrite its duration.\n const durationOptions = BUDGET_DURATION_OPTIONS.some(o => o.value === budgetDuration)\n ? BUDGET_DURATION_OPTIONS\n : [...BUDGET_DURATION_OPTIONS, { value: budgetDuration, label: budgetDuration }];\n const showKnowledgeBases = mode === 'edit' && !!canManageKnowledgeBases;\n const kbOptions = (vectorStores ?? []).map(v => v.id);\n const kbLabel = (id: string) =>\n (vectorStores ?? []).find(v => v.id === id)?.name ?? id;\n const showMcpServers = mode === 'edit' && !!canManageMcpServers;\n const mcpOptions = (mcpServers ?? []).map(s => s.id);\n const mcpLabel = (id: string) =>\n (mcpServers ?? []).find(s => s.id === id)?.name ?? id;\n\n // In membersOnly mode, determine if a member removal is disabled\n const isRemovalDisabled = (memberUserId: string, memberRole: string): { disabled: boolean; reason?: string } => {\n if (!membersOnly) return { disabled: false };\n if (memberUserId === currentUserId) {\n return { disabled: true, reason: \"You can't remove yourself\" };\n }\n if (memberManagerRoles?.includes(memberRole)) {\n return { disabled: true, reason: `Only platform admins can remove a team ${memberRole}` };\n }\n return { disabled: false };\n };\n\n const submitLabel = creating ? 'Create team' : 'Save';\n\n const getDialogTitle = () => {\n if (membersOnly) {\n return `Manage members \u2014 ${team?.team_alias || 'Untitled team'}`;\n }\n return mode === 'create' ? 'Create Team' : 'Edit Team';\n };\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth={wide ? 'md' : 'sm'} fullWidth>\n <DialogTitle>{getDialogTitle()}</DialogTitle>\n <DialogContent sx={{ pt: 2, display: 'flex', flexDirection: 'column', gap: 2 }}>\n {error && <Alert severity=\"error\">{error}</Alert>}\n\n {membersOnly && (\n <Alert severity=\"info\">\n As a team {team?.members_with_roles?.find(m => m.user_id === currentUserId)?.role || 'member'} you can add or remove members. Budgets and models are managed by your platform admins.\n </Alert>\n )}\n\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: {\n xs: '1fr',\n md: wide ? 'minmax(0, 1fr) minmax(0, 1fr)' : '1fr',\n },\n gap: 3,\n alignItems: 'start',\n }}\n >\n {!membersOnly && (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n {wide && <Typography variant=\"subtitle2\">Settings</Typography>}\n <TextField\n label=\"Team Alias\"\n value={alias}\n onChange={e => setAlias(e.target.value)}\n disabled={submitting}\n fullWidth\n />\n\n <Autocomplete\n multiple\n options={modelNames}\n value={models}\n onChange={(_, newValue) => setModels(newValue)}\n disabled={submitting}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Models\"\n required\n helperText=\"Only models your admin allow-listed for teams. At least one is required.\"\n />\n )}\n />\n\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: '1fr', sm: '1fr 1fr' },\n gap: 2,\n }}\n >\n <TextField\n label={budgetWriteOnly ? 'New Max Budget ($)' : 'Max Budget ($)'}\n type=\"number\"\n value={maxBudget}\n onChange={e => setMaxBudget(e.target.value)}\n disabled={submitting || unlimited}\n inputProps={{ min: 0, max: maxBudgetCeiling }}\n helperText={\n budgetWriteOnly\n ? 'Current budget is hidden \u2014 leave blank to keep it, or enter a new value'\n : `Maximum: $${maxBudgetCeiling}`\n }\n fullWidth\n />\n\n <TextField\n select\n label=\"Budget Duration\"\n value={budgetDuration}\n onChange={e => setBudgetDuration(e.target.value)}\n disabled={submitting || unlimited}\n helperText=\"Spend-reset period for the team budget\"\n fullWidth\n >\n {durationOptions.map(o => (\n <MenuItem key={o.value} value={o.value}>\n {o.label}\n </MenuItem>\n ))}\n </TextField>\n </Box>\n\n {allowUnlimitedBudget && (\n <FormControlLabel\n control={<Checkbox checked={unlimited} onChange={e => setUnlimited(e.target.checked)} disabled={submitting} />}\n label=\"Unlimited Budget\"\n />\n )}\n </Box>\n )}\n\n {showMembers && (\n <Box>\n <Typography variant=\"subtitle2\" sx={{ mb: creating ? 0.25 : 1 }}>\n {creating ? 'Initial members' : 'Members'}\n </Typography>\n {creating && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n Added as team users right after the team is created.\n </Typography>\n )}\n {memberError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setMemberError(null)}>\n {memberError}\n </Alert>\n )}\n {members.length === 0 ? (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n {creating ? 'No members picked yet \u2014 you can also add them later.' : 'No members yet.'}\n </Typography>\n ) : (\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 1.5, mb: 1.5 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>User</TableCell>\n <TableCell align=\"right\">Role</TableCell>\n <TableCell align=\"right\" sx={{ width: 40 }} />\n </TableRow>\n </TableHead>\n <TableBody>\n {members.map(m => (\n <TableRow key={m.user_id}>\n <TableCell>\n {m.user_email ? (\n <>\n <Typography variant=\"body2\">{m.user_email}</Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {m.user_id}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"body2\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {m.user_id}\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <StatusPill label={m.role} tone={m.role === 'admin' ? 'accent' : 'neutral'} dot={false} />\n </TableCell>\n <TableCell align=\"right\">\n {(() => {\n const { disabled, reason } = isRemovalDisabled(m.user_id, m.role);\n // span wrapper: a disabled button emits no hover events\n return (\n <Tooltip title={reason ?? ''}>\n <span>\n <IconButton\n edge=\"end\"\n size=\"small\"\n aria-label={`remove ${m.user_id}`}\n disabled={memberBusy || disabled}\n onClick={() => handleRemoveMember(m.user_id)}\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n </span>\n </Tooltip>\n );\n })()}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n <Box sx={{ display: 'flex', gap: 1, alignItems: 'flex-start', flexWrap: 'wrap' }}>\n <Autocomplete\n freeSolo\n autoHighlight\n options={userOptions}\n loading={usersLoading}\n inputValue={memberQuery}\n onInputChange={(_, newInputValue, reason) => {\n setMemberQuery(newInputValue);\n // 'reset' fires when a selection sets the input programmatically \u2014\n // memberRef is already set by onChange in that case, so only sync\n // free typing (and clearing) back into the submitted ref here.\n if (reason === 'input' || reason === 'clear') {\n setMemberRef(newInputValue);\n // Trigger a debounced search for new results.\n handleUserSearch(newInputValue);\n }\n }}\n onChange={(_, newValue) => {\n if (newValue && typeof newValue !== 'string') {\n setMemberQuery(newValue.label);\n setMemberRef(newValue.ref);\n }\n }}\n getOptionLabel={o => (typeof o === 'string' ? o : o.label)}\n isOptionEqualToValue={(o, v) => o.ref === (typeof v === 'string' ? v : v.ref)}\n disabled={memberBusy}\n sx={{ flex: '1 1 240px' }}\n renderInput={params => (\n <TextField\n {...params}\n label=\"Add member\"\n placeholder=\"Search by name or email\u2026\"\n size=\"small\"\n helperText=\"Pick a catalog user, or paste a user entity ref\"\n InputProps={{\n ...params.InputProps,\n endAdornment: (\n <>\n {usersLoading ? <CircularProgress color=\"inherit\" size={14} /> : null}\n {params.InputProps.endAdornment}\n </>\n ),\n }}\n />\n )}\n />\n {!membersOnly && (\n <TextField\n label=\"Max budget in team ($)\"\n type=\"number\"\n value={memberBudget}\n onChange={e => setMemberBudget(e.target.value)}\n disabled={memberBusy}\n size=\"small\"\n sx={{ width: 150 }}\n />\n )}\n <Button\n onClick={handleAddMember}\n disabled={memberBusy || !memberRef.trim()}\n variant=\"outlined\"\n sx={{ mt: 0.5 }}\n >\n Add\n </Button>\n </Box>\n </Box>\n )}\n\n </Box>\n\n {!membersOnly && showKnowledgeBases && (\n <Box>\n <Divider sx={{ my: 1 }} />\n <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>\n Knowledge Bases\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n Attaching a knowledge base exposes its documents to every key in\n this team.\n </Typography>\n {kbError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setKbError(null)}>\n {kbError}\n </Alert>\n )}\n <Autocomplete\n multiple\n options={kbOptions}\n value={kbIds}\n getOptionLabel={kbLabel}\n onChange={(_, v) => setKbIds(v)}\n disabled={kbBusy}\n renderInput={params => (\n <TextField {...params} label=\"Attached knowledge bases\" />\n )}\n />\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>\n <Button\n onClick={handleSaveKnowledgeBases}\n disabled={kbBusy}\n variant=\"outlined\"\n >\n {kbBusy ? 'Saving\u2026' : 'Save knowledge bases'}\n </Button>\n </Box>\n </Box>\n )}\n\n {!membersOnly && showMcpServers && (\n <Box>\n <Divider sx={{ my: 1 }} />\n <Typography variant=\"subtitle2\" sx={{ mb: 1 }}>\n MCP Servers\n </Typography>\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mb: 1 }}>\n Attaching an MCP server lets every key in this team invoke that\n server's tools through the model \u2014 including any side effects\n those tools have.\n </Typography>\n {mcpError && (\n <Alert severity=\"error\" sx={{ mb: 1 }} onClose={() => setMcpError(null)}>\n {mcpError}\n </Alert>\n )}\n <Autocomplete\n multiple\n options={mcpOptions}\n value={mcpIds}\n getOptionLabel={mcpLabel}\n onChange={(_, v) => setMcpIds(v)}\n disabled={mcpBusy}\n renderInput={params => (\n <TextField {...params} label=\"Attached MCP servers\" />\n )}\n />\n <Box sx={{ display: 'flex', justifyContent: 'flex-end', mt: 1 }}>\n <Button\n onClick={handleSaveMcpServers}\n disabled={mcpBusy}\n variant=\"outlined\"\n >\n {mcpBusy ? 'Saving\u2026' : 'Save MCP servers'}\n </Button>\n </Box>\n </Box>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={submitting}>\n {membersOnly ? 'Done' : 'Cancel'}\n </Button>\n {!membersOnly && (\n <Button onClick={handleSubmit} disabled={submitting} variant=\"contained\">\n {submitting ? 'Saving...' : submitLabel}\n </Button>\n )}\n </DialogActions>\n </Dialog>\n );\n};\n", "import { UserInfo, TeamInfo, VirtualKey } from './types';\nimport { Tone } from './components/ui';\nimport { budgetStatusForPct } from '@acarmisc/backstage-plugin-litellm-common';\n\n/** One concrete budget limit the signed-in user is subject to. */\nexport interface BudgetLimit {\n kind: 'key' | 'user' | 'team';\n /** Display name: key_alias / \"Personal budget\" / team_alias. */\n label: string;\n /** Secondary identifier: masked key, team_id, etc. */\n sublabel?: string;\n /** Spend cap in USD (> 0 when a cap exists). */\n budget: number;\n /** Spend so far in the current window. */\n spend: number;\n /** Reset window, e.g. \"30d\". Missing means the budget never resets. */\n budgetDuration?: string;\n /** User-facing warning threshold (soft limit). */\n softLimit?: number;\n /** Share of the cap spent, 0..100+ (unclamped). */\n pct: number;\n /**\n * True when the backend redacted the dollar amounts (team budget hiding).\n * `budget`/`spend` are then 0 and only `pct` carries the signal \u2014 render\n * the meter without `$` figures.\n */\n hidden?: boolean;\n}\n\n/** The budgets that apply to the current user, grouped by enforcement level. */\nexport interface BudgetSummary {\n /** Budgeted keys, capped at `maxKeys`, closest to the cap first. */\n keys: BudgetLimit[];\n /** Budgeted keys hidden by the cap. */\n hiddenBudgetedKeys: number;\n /** Every key owned by the user (budgeted or not). */\n totalKeyCount: number;\n /** Personal budget, when one is set (undefined otherwise). */\n user?: BudgetLimit;\n /** Team budgets shared by the user's teams. */\n teams: BudgetLimit[];\n}\n\n/** Share of the cap spent, unclamped so 120% stays visible as such. */\nfunction limitPct(spend: number, budget: number): number {\n if (budget <= 0) return 0;\n return (spend / budget) * 100;\n}\n\n/**\n * Collapses the current user's data into the budget limits that LiteLLM\n * actually enforces for them: key budgets (top `maxKeys`, closest to the cap\n * first), then the personal budget (when set), then each team budget. Team\n * budgets are enforced for every key bound to that team; a key *without* a\n * team falls back to the owner's personal budget.\n */\nexport function buildBudgetSummary(\n user: UserInfo | null,\n teams: TeamInfo[],\n keys: VirtualKey[],\n maxKeys = 3,\n): BudgetSummary {\n const budgeted = keys\n .filter(k => (k.max_budget ?? 0) > 0)\n .map(k => {\n const spend = k.spend ?? 0;\n return {\n kind: 'key' as const,\n label: k.key_alias || k.key || 'Untitled key',\n sublabel: k.key,\n budget: k.max_budget!,\n spend,\n budgetDuration: k.budget_duration,\n pct: limitPct(spend, k.max_budget!),\n };\n })\n .sort((a, b) => b.pct - a.pct);\n\n const userBudget =\n user && (user.max_budget ?? user.hard_limit ?? 0) > 0\n ? (() => {\n const budget = user.max_budget ?? user.hard_limit ?? 0;\n const spend = user.current_spend ?? user.spend ?? 0;\n return {\n kind: 'user' as const,\n label: 'Personal budget',\n sublabel: user.user_email || user.user_id,\n budget,\n spend,\n budgetDuration: user.budget_duration,\n softLimit: user.soft_limit,\n pct: limitPct(spend, budget),\n };\n })()\n : undefined;\n\n const teamLimits: BudgetLimit[] = teams\n .filter(t => (t.max_budget ?? 0) > 0 || t.budget_hidden === true)\n .map(t => {\n if (t.budget_hidden === true) {\n return {\n kind: 'team' as const,\n label: t.team_alias || 'Untitled team',\n sublabel: t.team_id,\n budget: 0,\n spend: 0,\n budgetDuration: t.budget_duration,\n pct: Math.min(100, Math.max(0, t.budget_pct ?? 0)),\n hidden: true as const,\n };\n }\n const spend = t.spend ?? 0;\n return {\n kind: 'team' as const,\n label: t.team_alias || 'Untitled team',\n sublabel: t.team_id,\n budget: t.max_budget!,\n spend,\n budgetDuration: t.budget_duration,\n pct: limitPct(spend, t.max_budget!),\n };\n })\n .sort((a, b) => b.pct - a.pct);\n\n return {\n keys: budgeted.slice(0, maxKeys),\n hiddenBudgetedKeys: Math.max(0, budgeted.length - maxKeys),\n totalKeyCount: keys.length,\n user: userBudget,\n teams: teamLimits,\n };\n}\n\n/**\n * Every concrete limit across all levels, keys first then personal then\n * teams. The per-level slices are already sorted by proximity to the cap, so\n * each level's limits stay ordered; this is the flat list for a \"show all\n * limits\" view. Keys beyond a display `maxKeys` are not included \u2014 build the\n * summary with a large `maxKeys` when the full list is needed.\n */\nexport function allBudgetLimits(summary: BudgetSummary): BudgetLimit[] {\n return [\n ...summary.keys,\n ...(summary.user ? [summary.user] : []),\n ...summary.teams,\n ];\n}\n\n/** One gauge in the condensed homepage card \u2014 a single enforcement level. */\nexport interface BudgetGauge {\n kind: 'key' | 'user' | 'team';\n /**\n * The limit of this level nearest its cap, or undefined when the user has\n * no cap at this level (render an empty gauge).\n */\n limit?: BudgetLimit;\n /** How many limits apply at this level (1 for a personal budget). */\n count: number;\n}\n\nconst GAUGE_KINDS: Array<BudgetGauge['kind']> = ['key', 'user', 'team'];\n\n/**\n * Collapses a `BudgetSummary` to exactly one gauge per enforcement level \u2014\n * key, user, team \u2014 carrying the limit nearest its cap and how many limits\n * that level holds. Every level is always returned, with `limit` undefined\n * when the user has no cap there, so the caller can render a stable row.\n *\n * Pass a summary built with a large `maxKeys` (e.g. `keys.length`) so the\n * nearest key is present even when it falls outside the display cap; a key\n * count hidden by that cap is still reflected in `count`.\n */\nexport function buildBudgetGauges(summary: BudgetSummary): BudgetGauge[] {\n const byLevel: Record<BudgetGauge['kind'], BudgetLimit[]> = {\n key: summary.keys,\n user: summary.user ? [summary.user] : [],\n team: summary.teams,\n };\n return GAUGE_KINDS.map(kind => {\n const limits = byLevel[kind];\n const count =\n kind === 'key' ? limits.length + summary.hiddenBudgetedKeys : limits.length;\n return {\n kind,\n count,\n limit: limits.length\n ? limits.reduce((a, b) => (b.pct > a.pct ? b : a))\n : undefined,\n };\n });\n}\n\n/**\n * One-line summary of a `BudgetSummary`, for a collapsed/compact header:\n * how many concrete limits the user is subject to, and the one closest to\n * its cap \u2014 kept as the whole `BudgetLimit` so the caller can name its\n * level (key / personal / team). `closest` is null when there are no limits.\n */\nexport function budgetHeadline(summary: BudgetSummary): {\n count: number;\n closest: BudgetLimit | null;\n} {\n const all: BudgetLimit[] = [\n ...summary.keys,\n ...(summary.user ? [summary.user] : []),\n ...summary.teams,\n ];\n const count =\n summary.keys.length +\n summary.hiddenBudgetedKeys +\n (summary.user ? 1 : 0) +\n summary.teams.length;\n const closest = all.length\n ? all.reduce((a, b) => (b.pct > a.pct ? b : a))\n : null;\n return { count, closest };\n}\n\n/** \"30d\" \u2192 \"every 30 days\"; \"1d\" \u2192 \"daily\". Returns null when duration is unset. */\nexport function fmtBudgetDuration(duration?: string): string | null {\n if (!duration) return null;\n const m = /^(\\d+)(s|m|h|d)$/.exec(duration);\n if (!m) return duration;\n const n = Number(m[1]);\n const unit = m[2];\n if (unit === 'd') return n === 1 ? 'daily' : `every ${n} days`;\n if (unit === 'h') return n === 1 ? 'hourly' : `every ${n} hours`;\n if (unit === 'm') return n === 1 ? 'every minute' : `every ${n} minutes`;\n return n === 1 ? 'every second' : `every ${n} seconds`;\n}\n\n/** status pill tone + meter tone for a budget at `pct`. */\nexport function budgetTone(pct: number): Tone {\n const status = budgetStatusForPct(pct);\n if (status === 'over') return 'danger';\n if (status === 'near') return 'warning';\n return 'accent';\n}\n\n/** Budget status for the signed-in user's overall spend vs their cap. */\nexport interface UserBudgetKpi {\n /** Total spend in the active budget window (lifetime or reset period). */\n spend: number;\n /** The budget cap, or null if unlimited. */\n max: number | null;\n /** max - spend, clamped at >= 0 for display. Null if unlimited. */\n remaining: number | null;\n /** spend / max * 100, or null if unlimited. Unclamped (can be > 100). */\n pct: number | null;\n /** 'capped' when a budget exists, 'unlimited' otherwise. */\n kind: 'capped' | 'unlimited';\n /**\n * Caption for the KPI. When capped: \"resets {formatted reset_at}\" if reset_at\n * exists and budget_duration is set, else \"lifetime cap\". Null if unlimited.\n */\n resetLabel: string | null;\n}\n\n/**\n * Compute the user's budget status: spend vs their personal cap.\n * Returns { spend, max, remaining, pct, kind, resetLabel } where remaining\n * is clamped at >= 0 for display purposes but pct and kind reflect the real status.\n */\nexport function userBudgetKpi(userInfo: UserInfo | null): UserBudgetKpi {\n if (!userInfo) {\n return {\n spend: 0,\n max: null,\n remaining: null,\n pct: null,\n kind: 'unlimited',\n resetLabel: null,\n };\n }\n\n const spend = userInfo.spend ?? 0;\n const max = userInfo.max_budget ?? null;\n\n if (max === null || max <= 0) {\n return {\n spend,\n max: null,\n remaining: null,\n pct: null,\n kind: 'unlimited',\n resetLabel: null,\n };\n }\n\n const remaining = Math.max(0, max - spend);\n const pct = (spend / max) * 100;\n\n // Format reset label\n let resetLabel: string;\n if (userInfo.budget_duration && userInfo.budget_reset_at) {\n try {\n const resetDate = new Date(userInfo.budget_reset_at);\n // Format as \"MMM D, YYYY HH:MM\" (e.g., \"Jan 1, 2026 00:00\")\n const fmt = new Intl.DateTimeFormat('en-US', {\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n timeZone: 'UTC',\n });\n const formatted = fmt.format(resetDate);\n resetLabel = `resets ${formatted}`;\n } catch {\n resetLabel = 'lifetime cap';\n }\n } else {\n resetLabel = 'lifetime cap';\n }\n\n return {\n spend,\n max,\n remaining,\n pct,\n kind: 'capped',\n resetLabel,\n };\n}", "import { FC, ReactNode, useEffect, useMemo, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Grid from '@mui/material/Grid';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport Skeleton from '@mui/material/Skeleton';\nimport {\n AreaChart,\n Area,\n BarChart,\n Bar,\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n ReferenceLine,\n Cell,\n} from 'recharts';\nimport {\n DateRange,\n UsageMetrics,\n ModelInfo,\n UserInfo,\n UsageModelBreakdown,\n UsageKeyBreakdown,\n} from '../types';\nimport { fmtUsd, fmtInt, modelsWithUsage } from '../format';\nimport { userBudgetKpi } from '../budget';\nimport {\n ChartCard,\n ChartTooltip,\n EmptyState,\n Meter,\n MetricStrip,\n SectionCard,\n SegmentedControl,\n Tone,\n SeriesLegend,\n TagChip,\n chartColor,\n dataTableSx,\n fmtCompact,\n fmtDateShort,\n fmtUsdCompact,\n useChartTheme,\n SERIES,\n} from './ui';\n\ninterface UsageStatsProps {\n usage: UsageMetrics | null;\n usageError?: Error;\n onRetryUsage?: () => void;\n models: ModelInfo[];\n dateRange: DateRange;\n currentPreset: DatePreset;\n onDateRangeChange: (range: DateRange, preset?: DatePreset) => void;\n loading: boolean;\n userInfo?: UserInfo;\n}\n\ntype DatePreset = 'today' | '24h' | '7d' | '30d';\ntype TabKey = 'costs' | 'models' | 'keys';\n\nconst TOP_N_MODELS = 6;\nconst PERIOD_LS_KEY = 'litellm_usage_period';\n\nconst PRESET_LABELS: Record<DatePreset, string> = {\n today: 'Today',\n '24h': 'Last 24 hours',\n '7d': 'Last 7 days',\n '30d': 'Last 30 days',\n};\n\nconst fmtPct = (n: number) => `${(n * 100).toFixed(1)}%`;\n\n/** Green above 99%, amber down to 90%, red below. */\nfunction rateTone(rate: number): Tone {\n if (rate >= 0.99) return 'success';\n if (rate >= 0.9) return 'warning';\n return 'danger';\n}\n\nconst ChartSkeleton: FC<{ height?: number }> = ({ height = 240 }) => (\n <Skeleton variant=\"rounded\" height={height} />\n);\n\n/** Shows a loading skeleton, an empty-state message, or the chart itself. */\nconst ChartOrFallback: FC<{\n loading: boolean;\n empty: boolean;\n height?: number;\n children: ReactNode;\n}> = ({ loading, empty, height = 240, children }) => {\n if (loading) return <ChartSkeleton height={height} />;\n if (empty) return <EmptyState message=\"No data for this period\" height={height} />;\n return <>{children}</>;\n};\n\n/** Inline success-rate bar used in both breakdown tables. */\nconst SuccessRateCell: FC<{ rate: number; requests: number }> = ({ rate, requests }) => {\n if (requests === 0) return <Typography variant=\"body2\" color=\"text.secondary\">\u2014</Typography>;\n const tone = rateTone(rate);\n return (\n <Box display=\"flex\" alignItems=\"center\" gap={1}>\n {/* Fixed, not flexible: the success-rate column is the last one, so a\n flexible meter stretches across all the table's slack space. */}\n <Box width={72} flexShrink={0}>\n <Meter value={rate * 100} tone={tone} height={4} />\n </Box>\n <Typography\n variant=\"caption\"\n sx={{ fontVariantNumeric: 'tabular-nums', minWidth: 44 }}\n >\n {fmtPct(rate)}\n </Typography>\n </Box>\n );\n};\n\nexport const UsageStats: FC<UsageStatsProps> = ({\n usage,\n usageError,\n onRetryUsage,\n models,\n dateRange,\n currentPreset,\n onDateRangeChange,\n loading,\n userInfo,\n}) => {\n const chart = useChartTheme();\n const [selectedModel, setSelectedModel] = useState<string>('all');\n const [tab, setTab] = useState<TabKey>('costs');\n\n // Filter to only models that have usage in the current period\n const modelsInPeriod = useMemo(\n () => modelsWithUsage(usage, models),\n [usage, models],\n );\n\n // If the currently selected model is no longer in the list, reset to 'all'\n useEffect(() => {\n if (selectedModel !== 'all' && !modelsInPeriod.includes(selectedModel)) {\n setSelectedModel('all');\n }\n }, [modelsInPeriod, selectedModel]);\n\n const handlePresetChange = (preset: DatePreset) => {\n const end = new Date();\n const start = new Date();\n if (preset === 'today') start.setHours(0, 0, 0, 0);\n else if (preset === '24h') start.setHours(start.getHours() - 24);\n else if (preset === '7d') start.setDate(start.getDate() - 7);\n else if (preset === '30d') start.setDate(start.getDate() - 30);\n try { localStorage.setItem(PERIOD_LS_KEY, preset); } catch { /* ignore */ }\n onDateRangeChange({ start, end }, preset);\n };\n\n // \u2500\u2500 daily_usage \u2192 base series \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const dailyData = useMemo(\n () =>\n (usage?.daily_usage ?? []).map(d => ({\n date: d.date,\n spend: d.spend,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n totalTokens: d.total_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n })),\n [usage],\n );\n\n // \u2500\u2500 Cumulative spend per day \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const cumulativeData = useMemo(() => {\n let cum = 0;\n return dailyData.map(d => { cum += d.spend; return { date: d.date, cumulative: cum }; });\n }, [dailyData]);\n\n // \u2500\u2500 Success rate trend (days with requests only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const successRateData = useMemo(\n () =>\n dailyData\n .filter(d => d.apiRequests > 0)\n .map(d => ({\n date: d.date,\n successRate: parseFloat(((d.successfulRequests / d.apiRequests) * 100).toFixed(1)),\n })),\n [dailyData],\n );\n\n // \u2500\u2500 Stacked spend by model per day \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const { modelSpendByDate, topModels: topSpendModels } = useMemo(() => {\n const rows = usage?.daily_by_model ?? [];\n const modelTotals: Record<string, number> = {};\n for (const r of rows) modelTotals[r.model] = (modelTotals[r.model] ?? 0) + r.spend;\n\n const top = Object.entries(modelTotals)\n .sort(([, a], [, b]) => b - a)\n .slice(0, TOP_N_MODELS)\n .map(([m]) => m);\n\n const dateMap: Record<string, Record<string, number>> = {};\n for (const r of rows) {\n if (!dateMap[r.date]) dateMap[r.date] = {};\n const bucket = top.includes(r.model) ? r.model : 'Other';\n dateMap[r.date][bucket] = (dateMap[r.date][bucket] ?? 0) + r.spend;\n }\n\n const sorted = Object.entries(dateMap)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([date, m]) => ({ date, ...m }));\n\n const hasOther = sorted.some(r => (r as any).Other > 0);\n return { modelSpendByDate: sorted, topModels: hasOther ? [...top, 'Other'] : top };\n }, [usage]);\n\n // \u2500\u2500 Model breakdown rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const modelRows = useMemo(() => {\n const entries = Object.entries<UsageModelBreakdown>(usage?.usage_by_model ?? {}).map(([model, d]) => ({\n model,\n spend: d.total_spend,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n totalTokens: d.total_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n successRate: d.api_requests > 0 ? d.successful_requests / d.api_requests : 0,\n }));\n return selectedModel === 'all' ? entries : entries.filter(e => e.model === selectedModel);\n }, [usage, selectedModel]);\n\n // top-models horizontal bar (sorted by spend)\n const topModelSpendBars = useMemo(\n () => [...modelRows].sort((a, b) => b.spend - a.spend).slice(0, 10),\n [modelRows],\n );\n\n // \u2500\u2500 Key breakdown rows \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n const keyRows = useMemo(\n () =>\n Object.entries<UsageKeyBreakdown>(usage?.usage_by_key ?? {}).map(([keyHash, d]) => ({\n keyHash,\n keyAlias: d.key_alias ?? keyHash.slice(0, 8),\n teamId: d.team_id ?? null,\n models: d.models,\n spend: d.total_spend,\n totalTokens: d.total_tokens,\n promptTokens: d.prompt_tokens,\n completionTokens: d.completion_tokens,\n apiRequests: d.api_requests,\n successfulRequests: d.successful_requests,\n failedRequests: d.failed_requests,\n successRate: d.api_requests > 0 ? d.successful_requests / d.api_requests : 0,\n })),\n [usage],\n );\n\n const topKeySpendBars = useMemo(\n () => [...keyRows].sort((a, b) => b.spend - a.spend).slice(0, 10),\n [keyRows],\n );\n\n const totalRequests = usage?.api_requests ?? 0;\n const overallSuccessRate = totalRequests > 0 ? (usage?.successful_requests ?? 0) / totalRequests : 0;\n const budgetKpi = userBudgetKpi(userInfo ?? null);\n\n // Keep the budget reference line inside the plot even when spend is far below it.\n const cumulativeDomain: any = budgetKpi.max && budgetKpi.max > 0\n ? [0, (dataMax: number) => Math.max(dataMax, budgetKpi.max!) * 1.05]\n : [0, 'auto'];\n\n const successTone: Tone = totalRequests === 0 ? 'neutral' : rateTone(overallSuccessRate);\n\n const metrics = [\n {\n label: 'Total spend',\n value: fmtUsd(usage?.total_spend ?? 0),\n hint: undefined,\n tone: 'accent' as const,\n },\n ...(budgetKpi.kind === 'capped' && budgetKpi.max !== null && budgetKpi.remaining !== null\n ? [\n {\n label: 'Budget left',\n value: budgetKpi.remaining > 0 ? fmtUsd(budgetKpi.remaining) : 'Over cap',\n hint: `${fmtUsd(budgetKpi.spend)} of ${fmtUsd(budgetKpi.max)} \u00B7 ${budgetKpi.resetLabel ?? ''}`,\n tone: (budgetKpi.pct !== null && budgetKpi.pct >= 100 ? 'danger' : 'accent') as Tone,\n },\n ]\n : []),\n {\n label: 'Requests',\n value: fmtInt(totalRequests),\n hint: `${fmtInt(usage?.failed_requests ?? 0)} failed`,\n tone: 'info' as const,\n },\n {\n label: 'Success rate',\n value: totalRequests > 0 ? fmtPct(overallSuccessRate) : '\u2014',\n hint: totalRequests > 0 ? `${fmtInt(usage?.successful_requests ?? 0)} succeeded` : undefined,\n tone: successTone,\n },\n {\n label: 'Tokens',\n value: fmtCompact(usage?.total_tokens ?? 0),\n hint: `${fmtCompact(usage?.prompt_tokens ?? 0)} in \u00B7 ${fmtCompact(usage?.completion_tokens ?? 0)} out`,\n tone: 'success' as const,\n },\n ];\n\n const renderKeyRows = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={7} sx={{ py: 3 }}>\n <Skeleton variant=\"rounded\" height={80} />\n </TableCell>\n </TableRow>\n );\n }\n if (keyRows.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={7}><EmptyState message=\"No key activity in this period\" /></TableCell>\n </TableRow>\n );\n }\n return [...keyRows]\n .sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests)\n .map(r => (\n <TableRow key={r.keyHash}>\n <TableCell>\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>{r.keyAlias}</Typography>\n {r.teamId ? (\n <Typography variant=\"caption\" color=\"text.secondary\">team: {r.teamId}</Typography>\n ) : null}\n </TableCell>\n <TableCell>\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {r.models.slice(0, 3).map(m => (\n <TagChip key={m} label={m} title={m} />\n ))}\n {r.models.length > 3 && <TagChip label={`+${r.models.length - 3}`} mono={false} />}\n </Box>\n </TableCell>\n <TableCell align=\"right\">{fmtUsd(r.spend)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.apiRequests)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.totalTokens)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.failedRequests)}</TableCell>\n <TableCell>\n <SuccessRateCell rate={r.successRate} requests={r.apiRequests} />\n </TableCell>\n </TableRow>\n ));\n };\n\n const renderModelRows = () => {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={8} sx={{ py: 3 }}>\n <Skeleton variant=\"rounded\" height={80} />\n </TableCell>\n </TableRow>\n );\n }\n if (modelRows.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={8}><EmptyState message=\"No model activity in this period\" /></TableCell>\n </TableRow>\n );\n }\n return [...modelRows]\n .sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens)\n .map(r => (\n <TableRow key={r.model}>\n <TableCell>\n <Box display=\"flex\" alignItems=\"center\" gap={1}>\n <Box sx={{ width: 8, height: 8, borderRadius: '50%', bgcolor: chartColor(r.model), flexShrink: 0 }} />\n <Typography variant=\"body2\" sx={{ fontWeight: 600 }}>{r.model}</Typography>\n </Box>\n </TableCell>\n <TableCell align=\"right\">{fmtUsd(r.spend)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.apiRequests)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.successfulRequests)}</TableCell>\n <TableCell align=\"right\">{fmtInt(r.failedRequests)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.promptTokens)}</TableCell>\n <TableCell align=\"right\">{fmtCompact(r.completionTokens)}</TableCell>\n <TableCell>\n <SuccessRateCell rate={r.successRate} requests={r.apiRequests} />\n </TableCell>\n </TableRow>\n ));\n };\n\n const periodSelect = (\n <TextField\n select\n size=\"small\"\n label=\"Period\"\n value={currentPreset}\n onChange={e => handlePresetChange(e.target.value as DatePreset)}\n sx={{ minWidth: 160 }}\n >\n {(Object.keys(PRESET_LABELS) as DatePreset[]).map(p => (\n <MenuItem key={p} value={p}>{PRESET_LABELS[p]}</MenuItem>\n ))}\n </TextField>\n );\n\n if (usageError) {\n return (\n <SectionCard\n title=\"Usage Analytics\"\n subtitle={`${PRESET_LABELS[currentPreset]} \u00B7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`}\n actions={periodSelect}\n >\n <Alert severity=\"error\">\n Failed to load usage data: {(usageError as any).message || 'Unknown error'}\n {onRetryUsage && (\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={onRetryUsage}>Retry</Button>\n </Box>\n )}\n </Alert>\n </SectionCard>\n );\n }\n\n return (\n <SectionCard\n title=\"Usage Analytics\"\n subtitle={`${PRESET_LABELS[currentPreset]} \u00B7 ${dateRange.start.toLocaleDateString()} \u2013 ${dateRange.end.toLocaleDateString()}`}\n actions={periodSelect}\n >\n <MetricStrip metrics={metrics} />\n\n <Box\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 2,\n flexWrap: 'wrap',\n mt: 2.5,\n mb: 2,\n }}\n >\n <SegmentedControl<TabKey>\n value={tab}\n onChange={setTab}\n options={[\n { value: 'costs', label: 'Costs' },\n { value: 'models', label: 'Model Activity' },\n { value: 'keys', label: 'Key Activity' },\n ]}\n />\n {tab === 'models' && (\n <TextField\n select\n size=\"small\"\n label=\"Model\"\n value={selectedModel}\n onChange={e => setSelectedModel(e.target.value)}\n sx={{ minWidth: 220 }}\n >\n <MenuItem value=\"all\">All models</MenuItem>\n {models\n .filter(m => modelsInPeriod.includes(m.model_name))\n .map(m => (\n <MenuItem key={m.model_name} value={m.model_name}>{m.model_name}</MenuItem>\n ))}\n </TextField>\n )}\n </Box>\n\n {/* \u2550\u2550 COSTS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'costs' && (\n <Grid container spacing={2}>\n {/* Daily spend by model \u2014 the headline chart, given full width so the\n stack and its colour key stay legible with up to seven series. */}\n <Grid item xs={12}>\n <ChartCard title=\"Daily spend by model\" height={260}>\n <ChartOrFallback loading={loading} empty={modelSpendByDate.length === 0} height={260}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={modelSpendByDate} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtUsdCompact} width={56} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={fmtUsd} hideZero />}\n />\n {topSpendModels.map(m => (\n <Area\n key={m}\n type=\"monotone\"\n dataKey={m}\n stackId=\"spend\"\n stroke={chartColor(m)}\n strokeWidth={1.5}\n fill={chartColor(m)}\n fillOpacity={0.28}\n />\n ))}\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n {!loading && topSpendModels.length > 0 && (\n <SeriesLegend series={topSpendModels.map(m => ({ name: m, color: chartColor(m) }))} />\n )}\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily token usage\">\n <ChartOrFallback loading={loading} empty={dailyData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtCompact} width={48} {...chart.axis} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} />} />\n <Legend {...chart.legend} />\n <Area type=\"monotone\" dataKey=\"promptTokens\" name=\"Input\" stackId=\"tok\" stroke={SERIES.input} strokeWidth={1.5} fill={SERIES.input} fillOpacity={0.25} />\n <Area type=\"monotone\" dataKey=\"completionTokens\" name=\"Output\" stackId=\"tok\" stroke={SERIES.output} strokeWidth={1.5} fill={SERIES.output} fillOpacity={0.25} />\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily requests\">\n <ChartOrFallback loading={loading} empty={dailyData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }} barCategoryGap=\"30%\">\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtCompact} width={48} {...chart.axis} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} />} />\n <Legend {...chart.legend} />\n <Bar dataKey=\"successfulRequests\" name=\"Successful\" fill={SERIES.success} stackId=\"r\" />\n <Bar dataKey=\"failedRequests\" name=\"Failed\" fill={SERIES.failure} stackId=\"r\" radius={[3, 3, 0, 0]} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Daily success rate\">\n <ChartOrFallback loading={loading} empty={successRateData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <LineChart data={successRateData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis domain={[0, 100]} tickFormatter={v => `${v}%`} width={44} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={(v: number) => `${v}%`} />}\n />\n <ReferenceLine y={100} stroke={SERIES.success} strokeDasharray=\"4 4\" strokeOpacity={0.5} />\n <Line\n type=\"monotone\"\n dataKey=\"successRate\"\n name=\"Success rate\"\n stroke={SERIES.input}\n strokeWidth={2}\n dot={{ r: 2.5, strokeWidth: 0, fill: SERIES.input }}\n activeDot={{ r: 4 }}\n />\n </LineChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard\n title=\"Spend in period\"\n >\n <ChartOrFallback loading={loading} empty={cumulativeData.length === 0}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={cumulativeData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis\n tickFormatter={fmtUsdCompact}\n width={56}\n domain={cumulativeDomain}\n {...chart.axis}\n />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={fmtUsd} />}\n />\n {budgetKpi.max && budgetKpi.max > 0 && (\n <ReferenceLine\n y={budgetKpi.max}\n stroke={SERIES.budget}\n strokeDasharray=\"5 4\"\n label={{ value: `Budget ${fmtUsd(budgetKpi.max)}`, position: 'insideTopRight', fontSize: 10, fill: SERIES.budget }}\n />\n )}\n <Area\n type=\"monotone\"\n dataKey=\"cumulative\"\n name=\"Cumulative spend\"\n stroke={SERIES.spend}\n strokeWidth={2}\n fill={SERIES.spend}\n fillOpacity={0.18}\n />\n </AreaChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n </Grid>\n )}\n\n {/* \u2550\u2550 MODELS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'models' && (\n <Grid container spacing={2}>\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Spend by model\" height={Math.max(200, topModelSpendBars.length * 34)}>\n <ChartOrFallback\n loading={loading}\n empty={topModelSpendBars.length === 0}\n height={Math.max(200, topModelSpendBars.length * 34)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topModelSpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtUsdCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"model\" width={170} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtUsd} labelFormatter={l => l} />} />\n <Bar dataKey=\"spend\" name=\"Spend\" radius={[0, 3, 3, 0]} barSize={14}>\n {topModelSpendBars.map(r => (\n <Cell key={r.model} fill={chartColor(r.model)} />\n ))}\n </Bar>\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12} md={6}>\n <ChartCard title=\"Tokens by model\" height={Math.max(200, topModelSpendBars.length * 34)}>\n <ChartOrFallback\n loading={loading}\n empty={modelRows.length === 0}\n height={Math.max(200, topModelSpendBars.length * 34)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topModelSpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"model\" width={170} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtInt} labelFormatter={l => l} />} />\n <Legend {...chart.legend} />\n <Bar dataKey=\"promptTokens\" name=\"Input\" fill={SERIES.input} stackId=\"t\" barSize={14} />\n <Bar dataKey=\"completionTokens\" name=\"Output\" fill={SERIES.output} stackId=\"t\" barSize={14} radius={[0, 3, 3, 0]} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n\n <Grid item xs={12}>\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 2 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>Model</TableCell>\n <TableCell align=\"right\">Spend</TableCell>\n <TableCell align=\"right\">Requests</TableCell>\n <TableCell align=\"right\">Success</TableCell>\n <TableCell align=\"right\">Failed</TableCell>\n <TableCell align=\"right\">Input</TableCell>\n <TableCell align=\"right\">Output</TableCell>\n <TableCell sx={{ width: 160 }}>Success rate</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderModelRows()}\n </TableBody>\n </Table>\n </TableContainer>\n </Grid>\n </Grid>\n )}\n\n {/* \u2550\u2550 KEYS TAB \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */}\n {tab === 'keys' && (\n <Grid container spacing={2}>\n {(loading || topKeySpendBars.length > 0) && (\n <Grid item xs={12}>\n <ChartCard title=\"Spend by key\" height={Math.max(160, topKeySpendBars.length * 32)}>\n <ChartOrFallback\n loading={loading}\n empty={topKeySpendBars.length === 0}\n height={Math.max(160, topKeySpendBars.length * 32)}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={topKeySpendBars} layout=\"vertical\" margin={{ top: 0, right: 12, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} vertical horizontal={false} />\n <XAxis type=\"number\" tickFormatter={fmtUsdCompact} {...chart.axis} />\n <YAxis type=\"category\" dataKey=\"keyAlias\" width={160} {...chart.axis} tick={{ fontSize: 10.5, fill: chart.axis.tick.fill }} />\n <Tooltip cursor={chart.cursor} content={<ChartTooltip valueFormatter={fmtUsd} labelFormatter={l => l} />} />\n <Bar dataKey=\"spend\" name=\"Spend\" fill={SERIES.input} radius={[0, 3, 3, 0]} barSize={14} />\n </BarChart>\n </ResponsiveContainer>\n </ChartOrFallback>\n </ChartCard>\n </Grid>\n )}\n\n <Grid item xs={12}>\n <TableContainer component={Paper} variant=\"outlined\" sx={{ borderRadius: 2 }}>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>Key</TableCell>\n <TableCell>Models</TableCell>\n <TableCell align=\"right\">Spend</TableCell>\n <TableCell align=\"right\">Requests</TableCell>\n <TableCell align=\"right\">Tokens</TableCell>\n <TableCell align=\"right\">Failed</TableCell>\n <TableCell sx={{ width: 160 }}>Success rate</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderKeyRows()}\n </TableBody>\n </Table>\n </TableContainer>\n </Grid>\n </Grid>\n )}\n </SectionCard>\n );\n};\n", "/**\n * Widget state machine for loading, error, and ready states.\n *\n * Discriminated union that represents the overall state of a widget:\n * - 'loading': profile or usage data is being fetched\n * - 'unprovisioned': user has no LiteLLM account (provisioning error)\n * - 'error': a data fetch failed (non-provisioning error)\n * - 'ready': data is available; usageUnavailable indicates failed usage fetch\n */\n\nimport { ApiError } from './api';\n\nexport const USAGE_UNAVAILABLE_MSG = 'Usage unavailable';\nexport const UNPROVISIONED_MSG = 'LiteLLM account not set up. Ask your admin.';\n\nconst UNPROVISIONED_BACKEND_MESSAGE = 'User not found in LiteLLM';\n\n/**\n * Detects whether an error represents a provisioning error.\n *\n * The backend answers 404 with body `{ error: 'User not found in LiteLLM' }`\n * when the user hasn't been provisioned. `ApiError` uses that `error` text as\n * its message, and `useLiteLLMProfile` surfaces failures as a plain message\n * string, so all three shapes are recognised: an ApiError (status + body), an\n * Error, or the bare message string.\n */\nexport function isUnprovisionedError(error: unknown): boolean {\n if (typeof error === 'string') {\n return error === UNPROVISIONED_BACKEND_MESSAGE;\n }\n if (error instanceof ApiError) {\n const body = error.body as { error?: unknown } | null | undefined;\n return (\n error.status === 404 &&\n !!body &&\n typeof body === 'object' &&\n body.error === UNPROVISIONED_BACKEND_MESSAGE\n );\n }\n if (error instanceof Error) {\n return error.message === UNPROVISIONED_BACKEND_MESSAGE;\n }\n return false;\n}\n\nexport type WidgetViewState =\n | { kind: 'loading' }\n | { kind: 'unprovisioned' }\n | { kind: 'error'; message: string }\n | { kind: 'ready'; usageUnavailable: boolean };\n\nexport interface WidgetStateParams {\n /** True if profile data is currently loading */\n loading: boolean;\n /** Error from profile fetch (getUserInfo). null if no error. */\n error: unknown;\n /** User info object; null if not loaded or unprovisioned */\n userInfo: unknown;\n /** Error from usage fetch. null if no error. */\n usageError: unknown;\n /** Number of keys; optional. Used to determine if the user has any keys. */\n hasKeys?: boolean;\n}\n\n/**\n * Determines the overall widget view state based on loading and error conditions.\n *\n * Priority:\n * 1. If loading, return 'loading'\n * 2. If profile error is unprovisioned, return 'unprovisioned'\n * 3. If profile error (any other), return 'error'\n * 4. Otherwise, return 'ready' with usageUnavailable flag based on usageError\n */\nexport function widgetViewState({\n loading,\n error,\n userInfo: _userInfo,\n usageError,\n hasKeys: _hasKeys,\n}: WidgetStateParams): WidgetViewState {\n if (loading) {\n return { kind: 'loading' };\n }\n\n if (error) {\n if (isUnprovisionedError(error)) {\n return { kind: 'unprovisioned' };\n }\n return { kind: 'error', message: USAGE_UNAVAILABLE_MSG };\n }\n\n return {\n kind: 'ready',\n usageUnavailable: usageError !== null && usageError !== undefined,\n };\n}\n", "/**\n * Shared budget-limit presentation used by both budget cards: the\n * `LiteLLMBudgetWidget` (full/compact meter list) and the condensed\n * `LiteLLMBudgetGauges` (expanded \"all limits\" view). Keeping the card in one\n * place means a limit reads identically wherever it is shown.\n */\nimport { FC, ReactNode } from 'react';\nimport Box from '@mui/material/Box';\nimport Paper from '@mui/material/Paper';\nimport Typography from '@mui/material/Typography';\nimport { alpha, useTheme } from '@mui/material/styles';\nimport type { Theme } from '@mui/material/styles';\nimport { Link } from '@backstage/core-components';\nimport { BudgetLimit, fmtBudgetDuration, budgetTone } from '../budget';\nimport { fmtUsd } from '../format';\nimport { Meter, Tone } from './ui';\n\n/** Semantic colour for a tone, from the host theme. */\nexport function levelToneColor(tone: Tone | undefined, theme: Theme): string {\n switch (tone) {\n case 'success': return theme.palette.success.main;\n case 'warning': return theme.palette.warning.main;\n case 'danger': return theme.palette.error.main;\n case 'info': return theme.palette.info.main;\n default: return theme.palette.primary.main;\n }\n}\n\n/** Spend-vs-cap meter card for a single limit. */\nexport const LimitCard: FC<{ limit: BudgetLimit }> = ({ limit }) => {\n const tone = budgetTone(limit.pct);\n const pct = Math.round(limit.pct);\n const closeTo = limit.softLimit !== undefined && limit.spend >= limit.softLimit;\n return (\n <Paper variant=\"outlined\" sx={{ px: 1.5, py: 1.25, borderRadius: 1.5 }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', gap: 1.5 }}>\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Typography\n variant=\"body2\"\n sx={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n title={limit.sublabel ? `${limit.label} \u00B7 ${limit.sublabel}` : limit.label}\n >\n {limit.label}\n </Typography>\n {limit.sublabel && (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n fontSize: 10.5,\n fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace',\n display: 'block',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {limit.sublabel}\n </Typography>\n )}\n </Box>\n {limit.hidden ? (\n <Typography variant=\"body2\" sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>\n {pct}% used\n </Typography>\n ) : (\n <Typography variant=\"body2\" sx={{ fontWeight: 600, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>\n {fmtUsd(limit.spend)}\n <Box component=\"span\" color=\"text.secondary\" sx={{ fontWeight: 400 }}>\n {' / '}\n {fmtUsd(limit.budget)}\n </Box>\n </Typography>\n )}\n </Box>\n <Box sx={{ mt: 1 }}>\n <Meter value={limit.pct} tone={tone} height={6} />\n </Box>\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n gap: 1,\n mt: 0.75,\n }}\n >\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {limit.hidden ? (\n <>Hidden by admin</>\n ) : (\n <>{pct}% of budget{closeTo && ` \u00B7 soft-limit warning`}</>\n )}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {fmtBudgetDuration(limit.budgetDuration)\n ? `resets ${fmtBudgetDuration(limit.budgetDuration)}`\n : 'never resets'}\n </Typography>\n </Box>\n </Paper>\n );\n};\n\n/** A LimitCard prefixed with a small KEY / USER / TEAM tag. */\nexport const TaggedLimit: FC<{ limit: BudgetLimit }> = ({ limit }) => {\n const theme = useTheme();\n const tone = budgetTone(limit.pct);\n return (\n <Box>\n <Typography\n sx={{\n fontSize: 11,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: tone === 'accent' ? theme.palette.text.secondary : levelToneColor(tone, theme),\n mb: 0.5,\n }}\n >\n {limit.kind}\n </Typography>\n <LimitCard limit={limit} />\n </Box>\n );\n};\n\n/** A key-budget note under a limit list \u2014 plain text when no href is given. */\nexport const MoreKeysNote: FC<{ count: number; href?: string; label?: string }> = ({\n count,\n href,\n label,\n}) => {\n const text = label ?? `+${count} more budgeted key${count > 1 ? 's' : ''} further from the cap`;\n if (!href) {\n return (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {text}\n </Typography>\n );\n }\n return (\n <Link to={href} variant=\"caption\">\n {text} \u2192\n </Link>\n );\n};\n\n/**\n * Flat list of concrete limits across every level, as tagged meter cards.\n * Used by the condensed gauges card's expanded view; the full widget renders\n * its own grouped-by-level rail instead.\n */\nexport const BudgetLimitList: FC<{\n limits: BudgetLimit[];\n /** Keys beyond the supplied limits \u2014 rendered as a trailing note. */\n hiddenKeyCount?: number;\n keysHref?: string;\n}> = ({ limits, hiddenKeyCount = 0, keysHref }) => (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25 }}>\n {limits.map(limit => (\n <TaggedLimit key={`${limit.kind}:${limit.sublabel ?? limit.label}`} limit={limit} />\n ))}\n {hiddenKeyCount > 0 && <MoreKeysNote count={hiddenKeyCount} href={keysHref} />}\n </Box>\n);\n\n/** Inset panel used to hold a nested list of limits inside a card. */\nexport const LimitListPanel: FC<{ children: ReactNode }> = ({ children }) => (\n <Box\n sx={theme => ({\n px: 1.5,\n py: 1.5,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.03 : 0.02),\n })}\n >\n {children}\n </Box>\n);\n", "/**\n * Build a link to the keys tab on the LiteLLM page.\n * @param baseUrl - The base URL of the LiteLLM module (result from useRouteRef)\n * @returns The full URL to the keys tab, or undefined if baseUrl is not available\n */\nexport function buildKeysLink(baseUrl: string | undefined): string | undefined {\n if (baseUrl === undefined) {\n return undefined;\n }\n return `${baseUrl}?tab=keys`;\n}\n", "/**\n * LiteLLM budget-policy widget. Renders the enforcement hierarchy as a\n * numbered flow \u2014 key \u2192 personal \u2192 team \u2192 global \u2014 and, against each level\n * the signed-in user actually has a limit on, a live meter showing how close\n * they are to the cap. Intended for at-a-glance use on a homepage card next\n * to `LiteLLMHomeWidget`, but works anywhere.\n *\n * The policy text mirrors the LiteLLM proxy behaviour:\n * - every request is checked against stacked limits, in order;\n * - a key bound to a team is capped by the team budgets, not the owner's\n * personal budget;\n * - a limit with a `budget_duration` resets its spend when the window\n * closes; without one it never resets.\n *\n * Two knobs shrink it for use as a secondary column:\n * - `compact` drops the numbered rail and the policy footnote, showing\n * only the limits the user actually has as a tight tagged meter list;\n * - `collapsible` folds the body under a one-line summary header.\n * `action` renders a host-supplied node (e.g. a button) pinned to the card\n * bottom, always visible.\n *\n * When user data is passed via props (userInfo, teams, keys), they are used\n * directly without refetching. Otherwise, the hook fetches them.\n */\nimport { FC, ReactNode, useId, useMemo, useState } from 'react';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport { ExpandMore } from '@mui/icons-material';\nimport { alpha } from '@mui/material/styles';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { StatusPill, Tone } from './ui';\nimport { widgetViewState, UNPROVISIONED_MSG } from '../widgetState';\nimport {\n levelToneColor,\n LimitCard,\n MoreKeysNote,\n TaggedLimit,\n} from './BudgetLimitList';\nimport {\n buildBudgetSummary,\n budgetHeadline,\n BudgetLimit,\n BudgetSummary,\n budgetTone,\n} from '../budget';\nimport { rootRouteRef } from '../routes';\nimport { buildKeysLink } from '../routeHelpers';\n\nexport interface LiteLLMBudgetWidgetProps {\n /** Optional title override. Defaults to 'Budget Policy'. */\n title?: string;\n /** Max key budgets to show, closest to the cap first. Defaults to 3. */\n maxKeys?: number;\n /**\n * Drop the numbered key\u2192personal\u2192team\u2192global rail and the policy\n * footnote; show only the limits the user actually has. Defaults to false.\n */\n compact?: boolean;\n /** Fold the body under a clickable one-line summary header. Defaults to false. */\n collapsible?: boolean;\n /** Initial expanded state when `collapsible`. Defaults to true. */\n defaultExpanded?: boolean;\n /**\n * Node rendered at the card bottom, below a divider and outside the\n * collapsible region so it stays visible when collapsed \u2014 e.g. a\n * \"create key\" button.\n */\n action?: ReactNode;\n /**\n * Optional preloaded data to use instead of fetching via the hook.\n * When provided, the component uses these values directly without refetching.\n */\n userInfo?: UserInfo | null;\n teams?: TeamInfo[];\n keys?: VirtualKey[];\n}\n\ninterface LevelFrameProps {\n rank: number;\n name: string;\n tagline: string;\n note?: string;\n tone?: Tone;\n isLast?: boolean;\n children: ReactNode;\n}\n\nconst LevelFrame: FC<LevelFrameProps> = ({\n rank,\n name,\n tagline,\n note,\n tone,\n isLast,\n children,\n}) => (\n <Box sx={{ display: 'flex', gap: 1.5 }}>\n {/* Left rail: rank badge + connector to the next level. */}\n <Box sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: 26, flexShrink: 0 }}>\n <Box\n sx={theme => ({\n width: 26,\n height: 26,\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(levelToneColor(tone, theme), 0.14),\n color: levelToneColor(tone, theme),\n fontSize: 12,\n fontWeight: 700,\n flexShrink: 0,\n })}\n >\n {rank}\n </Box>\n <Box\n sx={theme => ({\n flex: 1,\n width: 2,\n minHeight: 14,\n bgcolor: isLast ? 'transparent' : alpha(theme.palette.text.primary, 0.12),\n })}\n />\n </Box>\n\n <Box sx={{ flex: 1, minWidth: 0, pb: isLast ? 0 : 2 }}>\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 1, flexWrap: 'wrap', mb: 0.75 }}>\n <Typography\n sx={theme => ({\n fontSize: 12.5,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n color: levelToneColor(tone, theme),\n })}\n >\n {name}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontSize: 11.5 }}>\n {tagline}\n </Typography>\n {note && <StatusPill label={note} tone=\"neutral\" dot={false} sx={{ ml: 'auto' }} />}\n </Box>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>{children}</Box>\n </Box>\n </Box>\n);\n\nconst EmptyLimitCard: FC<{ children: ReactNode }> = ({ children }) => (\n <Paper\n variant=\"outlined\"\n sx={theme => ({\n px: 1.5,\n py: 1.25,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.03 : 0.015),\n })}\n >\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontSize: 13 }}>\n {children}\n </Typography>\n </Paper>\n);\n\n/** How each enforcement level reads in the collapsed summary line. */\nconst CLOSEST_LEVEL_LABEL: Record<BudgetLimit['kind'], string> = {\n key: 'key',\n user: 'personal',\n team: 'team',\n};\n\n\n/**\n * The one thing that's easy to get wrong about LiteLLM budgets: the order\n * caps are checked in. Short by design.\n */\nconst HierarchyNote: FC<{ withReset?: boolean }> = ({ withReset }) => (\n <Box\n sx={theme => ({\n px: 1.5,\n py: 1.25,\n borderRadius: 1.5,\n border: '1px dashed',\n borderColor: alpha(theme.palette.text.primary, 0.18),\n })}\n >\n <Typography variant=\"caption\" color=\"text.secondary\" display=\"block\">\n <b>Order:</b> key \u2192 personal \u2192 team \u2192 global. The first cap you reach\n blocks the request; a key that belongs to a team uses the team's cap,\n not your personal one.\n {withReset &&\n ' A cap with a reset window drops to $0 when the window closes; without one it never resets.'}\n </Typography>\n </Box>\n);\n\n/** Full body: the numbered key\u2192personal\u2192team\u2192global rail plus the policy footnote. */\nconst FullBody: FC<{ summary: BudgetSummary; keysLink?: string }> = ({ summary, keysLink }) => {\n const hasBudgetedKeys = summary.keys.length + summary.hiddenBudgetedKeys > 0;\n return (\n <>\n <LevelFrame\n rank={1}\n name=\"Key\"\n tagline=\"per-key cap \u00B7 highest priority\"\n note={hasBudgetedKeys ? undefined : 'no key budgets set'}\n >\n {!hasBudgetedKeys && (\n <EmptyLimitCard>No key has a budget, so no key-level cap applies.</EmptyLimitCard>\n )}\n {summary.keys.map(k => (\n <LimitCard key={k.sublabel ?? k.label} limit={k} />\n ))}\n {summary.hiddenBudgetedKeys > 0 && keysLink && (\n <MoreKeysNote count={summary.hiddenBudgetedKeys} href={keysLink} />\n )}\n </LevelFrame>\n\n <LevelFrame\n rank={2}\n name=\"User\"\n tagline=\"cap on everything you spend with your own keys\"\n note=\"skipped for team-bound keys\"\n >\n {summary.user ? (\n <LimitCard limit={summary.user} />\n ) : (\n <EmptyLimitCard>No personal budget is set on your account.</EmptyLimitCard>\n )}\n </LevelFrame>\n\n <LevelFrame rank={3} name=\"Team\" tagline=\"shared cap for all keys in a team (if any)\">\n {summary.teams.length > 0\n ? summary.teams.map(t => (\n <LimitCard key={t.sublabel ?? t.label} limit={t} />\n ))\n : (\n <EmptyLimitCard>No team you belong to has a budget.</EmptyLimitCard>\n )}\n </LevelFrame>\n\n <LevelFrame rank={4} name=\"Global\" tagline=\"proxy-wide cap set by your admin\" isLast>\n <EmptyLimitCard>\n Configured by your admin in the proxy config \u2014 it isn't visible from this page. When\n set, it limits spend across every request on the proxy.\n </EmptyLimitCard>\n </LevelFrame>\n\n <Box sx={{ mt: 2 }}>\n <HierarchyNote withReset />\n </Box>\n </>\n );\n};\n\n/** Compact body: only the limits the user actually has, as a tagged meter list. */\nconst CompactBody: FC<{ summary: BudgetSummary; keysLink?: string }> = ({ summary, keysLink }) => {\n const { count } = budgetHeadline(summary);\n if (count === 0) {\n return (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ fontSize: 13 }}>\n No budget limits apply to you right now.\n </Typography>\n );\n }\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25 }}>\n <HierarchyNote />\n {summary.keys.map(k => (\n <TaggedLimit key={k.sublabel ?? k.label} limit={k} />\n ))}\n {summary.hiddenBudgetedKeys > 0 && keysLink && (\n <MoreKeysNote count={summary.hiddenBudgetedKeys} href={keysLink} />\n )}\n {summary.user && <TaggedLimit limit={summary.user} />}\n {summary.teams.map(t => (\n <TaggedLimit key={t.sublabel ?? t.label} limit={t} />\n ))}\n </Box>\n );\n};\n\nexport const LiteLLMBudgetWidget: FC<LiteLLMBudgetWidgetProps> = ({\n title = 'Budget Policy',\n maxKeys = 3,\n compact = false,\n collapsible = false,\n defaultExpanded = true,\n action,\n userInfo: propUserInfo,\n teams: propTeams,\n keys: propKeys,\n}) => {\n const { userInfo: hookUserInfo, teams: hookTeams, keys: hookKeys, loading, error } = useLiteLLMProfile();\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const keysLink = buildKeysLink(moduleRouteRef?.());\n const [expanded, setExpanded] = useState(defaultExpanded);\n const collapsibleContentId = useId();\n\n // Use provided props if available, otherwise use hook data\n const user = propUserInfo !== undefined ? propUserInfo : hookUserInfo;\n const teams = propTeams !== undefined ? propTeams : hookTeams;\n const keys = propKeys !== undefined ? propKeys : hookKeys;\n\n const viewState = useMemo(\n () => widgetViewState({\n loading,\n error,\n userInfo: user,\n usageError: null, // budget widget doesn't fetch usage\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [loading, error, user, keys],\n );\n\n const summary = useMemo(\n () => buildBudgetSummary(user, teams, keys, maxKeys),\n [user, teams, keys, maxKeys],\n );\n const headline = useMemo(() => budgetHeadline(summary), [summary]);\n\n const limitsWord = `${headline.count} limit${headline.count === 1 ? '' : 's'}`;\n const closestWord =\n headline.closest === null\n ? ''\n : ` \u00B7 closest: ${CLOSEST_LEVEL_LABEL[headline.closest.kind]} ${Math.round(\n headline.closest.pct,\n )}%`;\n const summaryText =\n headline.count === 0 ? 'no limits apply' : `${limitsWord}${closestWord}`;\n\n const body = (\n <>\n {viewState.kind === 'loading' && (\n <Box sx={{ minHeight: 140 }}>\n {[0, 1, 2, 3].map(i => (\n <Box key={i} sx={{ display: 'flex', gap: 1, mb: 1 }}>\n <Skeleton variant=\"rectangular\" width={24} height={24} sx={{ flexShrink: 0, mt: 0.5 }} />\n <Box sx={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={18} sx={{ mb: 0.5 }} />\n <Skeleton variant=\"rectangular\" width=\"100%\" height={8} sx={{ mb: 0.5 }} />\n <Skeleton variant=\"text\" width=\"40%\" height={12} />\n </Box>\n </Box>\n ))}\n </Box>\n )}\n\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {viewState.message}\n </Typography>\n )}\n\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {viewState.kind === 'ready' &&\n (compact ? <CompactBody summary={summary} keysLink={keysLink} /> : <FullBody summary={summary} keysLink={keysLink} />)}\n </>\n );\n\n return (\n <Paper sx={{ p: 2 }}>\n {collapsible ? (\n <Box\n onClick={() => setExpanded(e => !e)}\n sx={{\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n cursor: 'pointer',\n userSelect: 'none',\n mb: expanded ? 1.5 : 0,\n }}\n >\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Typography variant=\"h6\" lineHeight={1.2}>{title}</Typography>\n {viewState.kind === 'ready' && (\n <Box sx={{ mt: 0.5 }}>\n <StatusPill\n label={summaryText}\n tone={budgetTone(headline.closest?.pct ?? 0)}\n />\n </Box>\n )}\n </Box>\n <IconButton\n size=\"small\"\n aria-label={expanded ? 'Collapse budget policy' : 'Expand budget policy'}\n aria-expanded={expanded}\n aria-controls={collapsibleContentId}\n onClick={e => {\n e.stopPropagation();\n setExpanded(x => !x);\n }}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: expanded ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <ExpandMore />\n </IconButton>\n </Box>\n ) : (\n <Box sx={{ mb: 1.5 }}>\n <Typography variant=\"h6\" lineHeight={1.2}>{title}</Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n How LiteLLM caps spend \u2014 and where you stand right now\n </Typography>\n </Box>\n )}\n\n {collapsible ? (\n <Collapse in={expanded} unmountOnExit>\n <Box id={collapsibleContentId}>\n {body}\n </Box>\n </Collapse>\n ) : (\n body\n )}\n\n {action && (\n <Box\n sx={theme => ({\n mt: 2,\n pt: 2,\n borderTop: `1px solid ${theme.palette.divider}`,\n })}\n >\n {action}\n </Box>\n )}\n </Paper>\n );\n};\n", "import { FC, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Divider from '@mui/material/Divider';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableContainer from '@mui/material/TableContainer';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport Button from '@mui/material/Button';\nimport CircularProgress from '@mui/material/CircularProgress';\nimport { alpha } from '@mui/material/styles';\nimport MuiTooltip from '@mui/material/Tooltip';\nimport { ExpandMore, Group, Add, LockOutlined, GroupAddOutlined } from '@mui/icons-material';\nimport {\n AreaChart,\n Area,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n} from 'recharts';\nimport { TeamInfo, UsageMetrics } from '../types';\nimport {\n ChartTooltip,\n EmptyState,\n Meter,\n SectionCard,\n Stat,\n StatusPill,\n TagChip,\n Tone,\n dataTableSx,\n fmtDateShort,\n fmtUsdCompact,\n useChartTheme,\n SERIES,\n} from './ui';\n\nfunction budgetTone(isOver: boolean, isNear: boolean): Tone {\n if (isOver) return 'danger';\n if (isNear) return 'warning';\n return 'accent';\n}\n\nconst fmtUsd2 = (n: number) => `$${(n ?? 0).toFixed(2)}`;\n\nfunction visibleBudgetPct(spend: number, budget: number): number {\n if (budget <= 0) return 0;\n return Math.min((spend / budget) * 100, 100);\n}\n\nfunction budgetStatValue(hidden: boolean, budget: number): string {\n if (hidden) return 'Hidden';\n if (budget > 0) return fmtUsd2(budget);\n return 'Unlimited';\n}\n\ninterface TeamCardProps {\n team: TeamInfo;\n usage: UsageMetrics | null;\n usageLoading: boolean;\n canManage?: boolean;\n onEditTeam?: (team: TeamInfo) => void;\n /** Members-only management (team-role path); hidden when `canManage`. */\n canManageMembers?: boolean;\n onManageMembers?: (team: TeamInfo) => void;\n onExpand?: (team: TeamInfo) => void;\n}\n\nconst TeamCard: FC<TeamCardProps> = ({ team, usage, usageLoading, canManage, onEditTeam, canManageMembers, onManageMembers, onExpand }) => {\n const [expanded, setExpanded] = useState(false);\n const chart = useChartTheme();\n\n const handleExpandChange = (newExpanded: boolean) => {\n setExpanded(newExpanded);\n if (newExpanded && onExpand) {\n onExpand(team);\n }\n };\n\n // When the backend redacts dollar amounts (budget hiding), only the\n // consumption level survives: pct + status + reset window. Spend charts\n // and `$` figures must stay hidden \u2014 usage spend is zeroed server-side\n // for the same reason.\n const hidden = team.budget_hidden === true;\n const budget = hidden ? 0 : team.max_budget ?? 0;\n const spend = hidden ? 0 : team.spend ?? 0;\n const budgetPct = hidden\n ? Math.min(100, Math.max(0, team.budget_pct ?? 0))\n : visibleBudgetPct(spend, budget);\n const isOver = hidden\n ? team.budget_status === 'over'\n : budget > 0 && spend >= budget;\n const isNear = hidden\n ? team.budget_status === 'near'\n : budget > 0 && spend >= budget * 0.8 && !isOver;\n\n const dailyData = usage?.daily_usage?.map(d => ({ date: d.date, spend: d.spend })) ?? [];\n\n const renderDailySpendSection = () => {\n // Spend is redacted server-side when the budget is hidden \u2014 a flat $0\n // chart would mislead, so the section is omitted entirely.\n if (hidden) return null;\n if (usageLoading) {\n return (\n <Box display=\"flex\" justifyContent=\"center\" py={3}>\n <CircularProgress size={22} />\n </Box>\n );\n }\n if (dailyData.length === 0) return null;\n return (\n <Box mb={2.5}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 11, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', mb: 1 }}\n >\n Daily spend\n </Typography>\n <Box height={150}>\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 8, left: 0, bottom: 0 }}>\n <CartesianGrid {...chart.grid} />\n <XAxis dataKey=\"date\" tickFormatter={fmtDateShort} {...chart.axis} />\n <YAxis tickFormatter={fmtUsdCompact} width={52} {...chart.axis} />\n <Tooltip\n cursor={chart.cursor}\n content={<ChartTooltip valueFormatter={v => `$${v.toFixed(4)}`} />}\n />\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n strokeWidth={2}\n fill={SERIES.spend}\n fillOpacity={0.18}\n />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n </Box>\n );\n };\n\n const sectionLabel = (label: string) => (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ display: 'block', fontSize: 11, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase', mb: 1 }}\n >\n {label}\n </Typography>\n );\n\n return (\n <Paper variant=\"outlined\" sx={{ borderRadius: 2, p: 2.5 }}>\n <Box display=\"flex\" alignItems=\"center\" gap={1.5}>\n <Box\n sx={theme => ({\n width: 36,\n height: 36,\n borderRadius: 1.5,\n flexShrink: 0,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: alpha(theme.palette.primary.main, 0.1),\n color: theme.palette.primary.main,\n })}\n >\n <Group fontSize=\"small\" />\n </Box>\n <Box flexGrow={1} minWidth={0}>\n <Typography variant=\"subtitle1\" sx={{ fontWeight: 600, lineHeight: 1.3 }}>\n {team.team_alias || 'Untitled team'}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {team.team_id}\n </Typography>\n </Box>\n {isOver && <StatusPill label=\"Over budget\" tone=\"danger\" />}\n {isNear && <StatusPill label=\"Near limit\" tone=\"warning\" />}\n {canManage && onEditTeam && (\n <Button\n size=\"small\"\n variant=\"text\"\n onClick={() => onEditTeam(team)}\n sx={{ textTransform: 'none' }}\n >\n Edit\n </Button>\n )}\n {canManageMembers && onManageMembers && !canManage && (\n <MuiTooltip title=\"Add or remove members of this team\">\n <Button\n size=\"small\"\n variant=\"text\"\n startIcon={<GroupAddOutlined />}\n onClick={() => onManageMembers(team)}\n sx={{ textTransform: 'none' }}\n >\n Manage members\n </Button>\n </MuiTooltip>\n )}\n <IconButton\n size=\"small\"\n onClick={() => handleExpandChange(!expanded)}\n aria-label={expanded ? 'Hide team details' : 'Show team details'}\n aria-expanded={expanded}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: expanded ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <ExpandMore />\n </IconButton>\n </Box>\n\n {/* Fixed-track grid, capped in width, so the six stats line up across\n every team card instead of stretching to fill the row. */}\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: { xs: 'repeat(3, minmax(0, 1fr))', sm: 'repeat(6, minmax(0, 1fr))' },\n gap: 2,\n mt: 2.5,\n maxWidth: 640,\n }}\n >\n <Stat label=\"Members\" value={team.members_with_roles?.length ?? '\u2014'} />\n <Stat label=\"Models\" value={team.models?.length ? team.models.length : 'All'} />\n <Stat label=\"Budget\" value={budgetStatValue(hidden, budget)} />\n <Stat label=\"Spend\" value={hidden ? '\u2014' : fmtUsd2(spend)} />\n <Stat label=\"TPM\" value={team.tpm_limit && team.tpm_limit > 0 ? team.tpm_limit.toLocaleString() : '\u2014'} />\n <Stat label=\"RPM\" value={team.rpm_limit && team.rpm_limit > 0 ? team.rpm_limit.toLocaleString() : '\u2014'} />\n </Box>\n\n {hidden && (\n <Box mt={2} maxWidth={640}>\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"baseline\" mb={0.75}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {budgetPct.toFixed(0)}% used\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\">\n Hidden by admin\n </Typography>\n </Box>\n <Meter value={budgetPct} tone={budgetTone(isOver, isNear)} height={5} />\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mt: 0.75 }}>\n Team budget is hidden \u2014 showing usage level only\n {team.budget_duration ? ` \u00B7 resets every ${team.budget_duration}` : ''}.\n </Typography>\n </Box>\n )}\n\n {!hidden && budget > 0 && (\n <Box mt={2} maxWidth={640}>\n <Box display=\"flex\" justifyContent=\"space-between\" alignItems=\"baseline\" mb={0.75}>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtUsd2(spend)} of {fmtUsd2(budget)}\n </Typography>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {budgetPct.toFixed(0)}%\n </Typography>\n </Box>\n <Meter value={budgetPct} tone={budgetTone(isOver, isNear)} height={5} />\n </Box>\n )}\n\n <Collapse in={expanded} unmountOnExit>\n <Divider sx={{ my: 2.5 }} />\n\n <Box mb={2.5}>\n {sectionLabel('Models')}\n {team.models?.length ? (\n <Box display=\"flex\" gap={0.5} flexWrap=\"wrap\">\n {team.models.map(m => (\n <TagChip key={m} label={m} title={m} />\n ))}\n </Box>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">All models allowed</Typography>\n )}\n </Box>\n\n {renderDailySpendSection()}\n\n <Box>\n {sectionLabel('Members')}\n {team.members_with_roles?.length ? (\n <TableContainer\n component={Paper}\n variant=\"outlined\"\n sx={{ borderRadius: 1.5 }}\n >\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell>User</TableCell>\n <TableCell align=\"right\">Role</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {team.members_with_roles.map(m => (\n <TableRow key={m.user_id}>\n <TableCell>\n {m.user_email ? (\n <>\n <Typography variant=\"body2\">{m.user_email}</Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 11 }}\n >\n {m.user_id}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"body2\"\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace' }}\n >\n {m.user_id}\n </Typography>\n )}\n </TableCell>\n <TableCell align=\"right\">\n <StatusPill\n label={m.role}\n tone={m.role === 'admin' ? 'accent' : 'neutral'}\n dot={false}\n />\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n ) : (\n <Typography variant=\"body2\" color=\"text.secondary\">No members assigned.</Typography>\n )}\n </Box>\n </Collapse>\n </Paper>\n );\n};\n\ninterface TeamUsageProps {\n teams: TeamInfo[];\n loading: boolean;\n getTeamUsage: (teamId: string) => UsageMetrics | null;\n getTeamUsageLoading: (teamId: string) => boolean;\n canManage?: boolean;\n onEditTeam?: (team: TeamInfo) => void;\n /** When true (with `onCreateTeam`), a \"Create Team\" action renders in the section header. */\n canCreate?: boolean;\n onCreateTeam?: () => void;\n /** Called when a team card is expanded to trigger data loading. */\n onTeamExpand?: (team: TeamInfo) => void;\n /** Per-team: whether the caller may manage this team's members only. */\n canManageMembers?: (team: TeamInfo) => boolean;\n onManageMembers?: (team: TeamInfo) => void;\n /** Teams are synced from an identity provider: show a badge, no write controls. */\n readOnly?: boolean;\n}\n\nexport const TeamUsage: FC<TeamUsageProps> = ({\n teams,\n loading,\n getTeamUsage,\n getTeamUsageLoading,\n canManage,\n onEditTeam,\n canCreate,\n onCreateTeam,\n onTeamExpand,\n canManageMembers,\n onManageMembers,\n readOnly,\n}) => {\n const readOnlyBadge = (\n <MuiTooltip title=\"Teams and memberships are managed in your identity provider. Changes made here would be overwritten, so editing is disabled.\">\n <Box\n component=\"span\"\n sx={{ display: 'inline-flex', alignItems: 'center', gap: 0.5, color: 'text.secondary', fontSize: 12.5 }}\n >\n <LockOutlined sx={{ fontSize: 15 }} />\n Synced from identity provider\n </Box>\n </MuiTooltip>\n );\n const createButton =\n canCreate && onCreateTeam ? (\n <Button\n variant=\"contained\"\n color=\"primary\"\n disableElevation\n startIcon={<Add />}\n onClick={onCreateTeam}\n >\n Create Team\n </Button>\n ) : undefined;\n const createAction = readOnly ? readOnlyBadge : createButton;\n\n if (loading) {\n return (\n <SectionCard title=\"Teams\" actions={createAction}>\n <Skeleton variant=\"rounded\" height={120} sx={{ mb: 2 }} />\n <Skeleton variant=\"rounded\" height={120} />\n </SectionCard>\n );\n }\n\n if (!teams.length) {\n return (\n <SectionCard title=\"Teams\" actions={createAction}>\n <EmptyState\n message=\"You're not a member of any LiteLLM team yet.\"\n hint=\"Your account is provisioned, so you can still generate personal keys and use models. Ask an admin to add you to a team if you need a shared budget.\"\n />\n </SectionCard>\n );\n }\n\n return (\n <SectionCard\n title=\"Teams\"\n subtitle={`${teams.length} team${teams.length === 1 ? '' : 's'}`}\n actions={createAction}\n >\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n {teams.map(team => (\n <TeamCard\n key={team.team_id}\n team={team}\n usage={getTeamUsage(team.team_id)}\n usageLoading={getTeamUsageLoading(team.team_id)}\n canManage={canManage}\n onEditTeam={onEditTeam}\n canManageMembers={canManageMembers?.(team)}\n onManageMembers={onManageMembers}\n onExpand={onTeamExpand}\n />\n ))}\n </Box>\n </SectionCard>\n );\n};\n", "import { FC, useCallback, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TableSortLabel from '@mui/material/TableSortLabel';\nimport Typography from '@mui/material/Typography';\nimport MenuItem from '@mui/material/MenuItem';\nimport Select from '@mui/material/Select';\nimport FormControl from '@mui/material/FormControl';\nimport InputLabel from '@mui/material/InputLabel';\nimport TextField from '@mui/material/TextField';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport { Search } from '@mui/icons-material';\nimport ContentCopyIcon from '@mui/icons-material/ContentCopy';\nimport Tooltip from '@mui/material/Tooltip';\nimport Snackbar from '@mui/material/Snackbar';\nimport Alert from '@mui/material/Alert';\nimport { ModelInfo, TeamInfo } from '../types';\nimport { SectionCard, EmptyState, TagChip, dataTableSx, quietIconButtonSx } from './ui';\nimport { alpha, useTheme } from '@mui/material/styles';\n\ninterface ModelsTableProps {\n allModels: ModelInfo[];\n teams: TeamInfo[];\n loading: boolean;\n}\n\nconst ALL_PROXY_MODELS = 'all-proxy-models';\n\nfunction isModelAllowedByTeam(model: ModelInfo, teamModels?: string[]): boolean {\n if (!teamModels || teamModels.length === 0 || teamModels.includes(ALL_PROXY_MODELS)) return true;\n return teamModels.includes(model.model_name) ||\n !!model.access_groups?.some(group => teamModels.includes(group));\n}\n\nfunction fmtCostPerToken(cost?: number): string {\n if (cost === undefined || cost === null) return '\u2014';\n if (cost === 0) return '$0';\n if (cost < 0.000001) return `$${(cost * 1_000_000).toFixed(2)}/M`;\n if (cost < 0.001) return `$${(cost * 1000).toFixed(3)}/K`;\n return `$${cost.toFixed(4)}`;\n}\n\nfunction fmtTokens(n?: number): string {\n if (n === undefined || n === null) return '\u2014';\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(0)}K`;\n return String(n);\n}\n\nexport const ModelsTable: FC<ModelsTableProps> = ({ allModels, teams, loading }) => {\n const theme = useTheme();\n const [selectedTeamId, setSelectedTeamId] = useState<string>('');\n const [filterText, setFilterText] = useState<string>('');\n const [copiedSnackbar, setCopiedSnackbar] = useState(false);\n const [sortKey, setSortKey] = useState<'model_name' | 'mode' | 'input_cost_per_token' | 'output_cost_per_token' | 'max_input_tokens' | 'max_output_tokens'>('model_name');\n const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');\n\n const selectedTeam = useMemo(\n () => teams.find(t => t.team_id === selectedTeamId) ?? null,\n [teams, selectedTeamId],\n );\n\n const teamModels = useMemo(() => {\n if (!selectedTeam) return [];\n return allModels.filter(model => isModelAllowedByTeam(model, selectedTeam.models));\n }, [allModels, selectedTeam]);\n\n const filteredModels = useMemo(() => {\n const q = filterText.trim().toLowerCase();\n let models = teamModels;\n if (q) {\n models = teamModels.filter(model =>\n model.model_name.toLowerCase().includes(q) ||\n (model.access_groups || []).some(group => group.toLowerCase().includes(q)),\n );\n }\n return [...models].sort((a, b) => {\n let aVal: string | number | undefined;\n let bVal: string | number | undefined;\n switch (sortKey) {\n case 'model_name':\n aVal = a.model_name;\n bVal = b.model_name;\n break;\n case 'mode':\n aVal = a.mode;\n bVal = b.mode;\n break;\n case 'input_cost_per_token':\n aVal = a.input_cost_per_token ?? 0;\n bVal = b.input_cost_per_token ?? 0;\n break;\n case 'output_cost_per_token':\n aVal = a.output_cost_per_token ?? 0;\n bVal = b.output_cost_per_token ?? 0;\n break;\n case 'max_input_tokens':\n aVal = a.max_input_tokens ?? 0;\n bVal = b.max_input_tokens ?? 0;\n break;\n case 'max_output_tokens':\n aVal = a.max_output_tokens ?? 0;\n bVal = b.max_output_tokens ?? 0;\n break;\n default:\n return 0;\n }\n if (aVal === undefined || aVal === null) aVal = '';\n if (bVal === undefined || bVal === null) bVal = '';\n if (typeof aVal === 'string' && typeof bVal === 'string') {\n return sortDirection === 'asc' ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);\n }\n return sortDirection === 'asc' ? (aVal as number) - (bVal as number) : (bVal as number) - (aVal as number);\n });\n }, [teamModels, filterText, sortKey, sortDirection]);\n\n const handleCopyModelId = useCallback((modelId: string) => {\n navigator.clipboard.writeText(modelId).then(() => setCopiedSnackbar(true));\n }, []);\n\n const handleSort = useCallback((key: typeof sortKey) => {\n if (sortKey === key) {\n setSortDirection(prev => prev === 'asc' ? 'desc' : 'asc');\n } else {\n setSortKey(key);\n setSortDirection('asc');\n }\n }, [sortKey]);\n\n const modeColor = (mode: string): string => {\n switch (mode) {\n case 'chat': return theme.palette.info.main;\n case 'embedding': return theme.palette.success.main;\n case 'completion': return theme.palette.primary.main;\n case 'image': return theme.palette.warning.main;\n default: return theme.palette.info.main;\n }\n };\n\n return (\n <SectionCard\n title=\"Available Models\"\n subtitle={\n selectedTeam\n ? `${filteredModels.length}${filterText.trim() ? ` of ${teamModels.length}` : ''} model${filteredModels.length === 1 ? '' : 's'}`\n : 'Select a team to view its models'\n }\n >\n <Box sx={{ px: 2.5, pb: 2.5, pt: 1, display: 'flex', gap: 2, flexWrap: 'wrap' }}>\n <FormControl size=\"small\" sx={{ minWidth: 240, mb: 2 }}>\n <InputLabel id=\"team-select-label\">Team</InputLabel>\n <Select\n labelId=\"team-select-label\"\n value={selectedTeamId}\n label=\"Team\"\n onChange={e => setSelectedTeamId(e.target.value)}\n >\n {teams.map(t => (\n <MenuItem key={t.team_id} value={t.team_id}>\n {t.team_alias ?? t.team_id}\n </MenuItem>\n ))}\n </Select>\n </FormControl>\n <TextField\n label=\"Filter Models\"\n size=\"small\"\n value={filterText}\n onChange={e => setFilterText(e.target.value)}\n disabled={!selectedTeamId}\n sx={{ minWidth: 240, mb: 2 }}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <Search fontSize=\"small\" />\n </InputAdornment>\n ),\n }}\n />\n </Box>\n\n {loading && (\n <EmptyState message=\"Loading models\u2026\" />\n )}\n\n {!loading && !selectedTeamId && (\n <EmptyState\n message=\"Select a team to see available models\"\n hint=\"Each team may have a different set of models assigned\"\n />\n )}\n\n {!loading && selectedTeamId && teamModels.length === 0 && (\n <EmptyState\n message=\"No models available for this team\"\n hint={allModels.length === 0 ? 'No models are configured in the system' : 'None of the team\\'s assigned models were found in the catalog'}\n />\n )}\n\n {!loading && selectedTeamId && teamModels.length > 0 && filteredModels.length === 0 && (\n <EmptyState\n message=\"No models match your search\"\n hint=\"Try a different search term\"\n />\n )}\n\n {!loading && filteredModels.length > 0 && (\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sortDirection={sortKey === 'model_name' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'model_name'} direction={sortKey === 'model_name' ? sortDirection : 'asc'} onClick={() => handleSort('model_name')}>Model ID</TableSortLabel>\n </TableCell>\n <TableCell sortDirection={sortKey === 'mode' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'mode'} direction={sortKey === 'mode' ? sortDirection : 'asc'} onClick={() => handleSort('mode')}>Mode</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'input_cost_per_token' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'input_cost_per_token'} direction={sortKey === 'input_cost_per_token' ? sortDirection : 'asc'} onClick={() => handleSort('input_cost_per_token')}>Input Cost</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'output_cost_per_token' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'output_cost_per_token'} direction={sortKey === 'output_cost_per_token' ? sortDirection : 'asc'} onClick={() => handleSort('output_cost_per_token')}>Output Cost</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'max_input_tokens' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'max_input_tokens'} direction={sortKey === 'max_input_tokens' ? sortDirection : 'asc'} onClick={() => handleSort('max_input_tokens')}>Max Input</TableSortLabel>\n </TableCell>\n <TableCell align=\"right\" sortDirection={sortKey === 'max_output_tokens' ? sortDirection : false}>\n <TableSortLabel active={sortKey === 'max_output_tokens'} direction={sortKey === 'max_output_tokens' ? sortDirection : 'asc'} onClick={() => handleSort('max_output_tokens')}>Max Output</TableSortLabel>\n </TableCell>\n <TableCell>Capabilities</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {filteredModels.map(m => (\n <TableRow key={m.model_name} hover>\n <TableCell>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>\n <Tooltip title={m.model_name} placement=\"top\">\n <span\n role=\"button\"\n tabIndex={0}\n aria-label=\"Copy model ID\"\n onClick={() => handleCopyModelId(m.model_name)}\n onKeyDown={e => e.key === 'Enter' && handleCopyModelId(m.model_name)}\n style={{ cursor: 'pointer', display: 'inline-flex' }}\n >\n <TagChip label={m.model_name} title=\"Copy model ID\" />\n </span>\n </Tooltip>\n <Tooltip title=\"Copy model ID\">\n <Box\n component=\"span\"\n role=\"button\"\n tabIndex={0}\n onClick={() => handleCopyModelId(m.model_name)}\n onKeyDown={e => e.key === 'Enter' && handleCopyModelId(m.model_name)}\n sx={quietIconButtonSx('accent')}\n style={{ cursor: 'pointer', display: 'inline-flex' }}\n >\n <ContentCopyIcon sx={{ fontSize: 14 }} />\n </Box>\n </Tooltip>\n </Box>\n </TableCell>\n <TableCell>\n <Box\n component=\"span\"\n sx={{\n display: 'inline-block',\n px: 0.75,\n py: 0.25,\n borderRadius: 1,\n fontSize: 11,\n fontWeight: 600,\n textTransform: 'capitalize',\n bgcolor: alpha(modeColor(m.mode), 0.1),\n color: modeColor(m.mode),\n }}\n >\n {m.mode}\n </Box>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtCostPerToken(m.input_cost_per_token)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtCostPerToken(m.output_cost_per_token)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtTokens(m.max_input_tokens)}\n </Typography>\n </TableCell>\n <TableCell align=\"right\">\n <Typography variant=\"body2\" sx={{ fontVariantNumeric: 'tabular-nums' }}>\n {fmtTokens(m.max_output_tokens)}\n </Typography>\n </TableCell>\n <TableCell>\n <Box sx={{ display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>\n {m.supports_function_calling && (\n <TagChip label=\"Fn\" title=\"Function calling\" />\n )}\n {m.supports_vision && (\n <TagChip label=\"\uD83D\uDC41\" title=\"Vision\" />\n )}\n </Box>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n </TableContainer>\n )}\n\n <Snackbar\n open={copiedSnackbar}\n autoHideDuration={2000}\n onClose={() => setCopiedSnackbar(false)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}\n >\n <Alert severity=\"success\" variant=\"filled\" sx={{ fontSize: 13 }}>\n Model ID copied to clipboard\n </Alert>\n </Snackbar>\n </SectionCard>\n );\n};\n", "import { FC, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport Table from '@mui/material/Table';\nimport TableBody from '@mui/material/TableBody';\nimport TableCell from '@mui/material/TableCell';\nimport TableContainer from '@mui/material/TableContainer';\nimport TableHead from '@mui/material/TableHead';\nimport TableRow from '@mui/material/TableRow';\nimport TablePagination from '@mui/material/TablePagination';\nimport TextField from '@mui/material/TextField';\nimport MenuItem from '@mui/material/MenuItem';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport IconButton from '@mui/material/IconButton';\nimport Alert from '@mui/material/Alert';\nimport { alpha } from '@mui/material/styles';\nimport { KeyboardArrowDown } from '@mui/icons-material';\nimport { useAsync } from 'react-use';\nimport { LiteLlmApiInterface } from '../api';\nimport { AuditLogEntry, AuditLogsParams } from '../types';\nimport { EmptyState, SectionCard, StatusPill, Tone, dataTableSx } from './ui';\n\ninterface AuditLogProps {\n api: LiteLlmApiInterface;\n}\n\nconst ACTION_TONES: Record<string, Tone> = {\n created: 'success',\n deleted: 'danger',\n updated: 'warning',\n blocked: 'danger',\n unblocked: 'success',\n};\n\nfunction actionTone(action?: string): Tone {\n if (!action) return 'neutral';\n for (const [key, tone] of Object.entries(ACTION_TONES)) {\n if (action.toLowerCase().includes(key)) return tone;\n }\n return 'info';\n}\n\n/** `LiteLLM_VerificationToken` \u2192 `Key`; falls back to the raw table name. */\nconst TABLE_LABELS: Record<string, string> = {\n LiteLLM_VerificationToken: 'Key',\n LiteLLM_TeamTable: 'Team',\n LiteLLM_TeamMembership: 'Team member',\n LiteLLM_ObjectPermissionTable: 'Team access (KB / MCP)',\n LiteLLM_UserTable: 'User',\n};\n\nfunction prettyTableName(name?: string | null): string {\n if (!name) return '\u2014';\n return TABLE_LABELS[name] ?? name;\n}\n\nfunction formatDateTime(iso: string): string {\n try {\n return new Date(iso).toLocaleString();\n } catch {\n return iso;\n }\n}\n\nconst DetailRow: FC<{ entry: AuditLogEntry }> = ({ entry }) => {\n const [open, setOpen] = useState(false);\n const hasDetail = entry.before_value || entry.updated_values;\n\n return (\n <>\n <TableRow>\n <TableCell sx={{ width: 40, pr: 0 }}>\n {hasDetail && (\n <IconButton\n size=\"small\"\n onClick={() => setOpen(o => !o)}\n aria-label={open ? 'Hide changes' : 'Show changes'}\n aria-expanded={open}\n sx={theme => ({\n color: theme.palette.text.secondary,\n transform: open ? 'rotate(180deg)' : 'none',\n transition: theme.transitions.create('transform'),\n })}\n >\n <KeyboardArrowDown fontSize=\"small\" />\n </IconButton>\n )}\n </TableCell>\n <TableCell sx={{ whiteSpace: 'nowrap' }}>\n <Typography variant=\"body2\" color=\"text.secondary\">{formatDateTime(entry.updated_at)}</Typography>\n </TableCell>\n <TableCell>\n {entry.action && <StatusPill label={entry.action} tone={actionTone(entry.action)} />}\n </TableCell>\n <TableCell>\n <Typography variant=\"body2\">{prettyTableName(entry.table_name)}</Typography>\n </TableCell>\n <TableCell>\n <Typography\n variant=\"body2\"\n component=\"code\"\n color=\"text.secondary\"\n title={entry.object_id ?? undefined}\n sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', fontSize: 12 }}\n >\n {entry.object_id ? entry.object_id.slice(0, 20) + (entry.object_id.length > 20 ? '\u2026' : '') : '\u2014'}\n </Typography>\n </TableCell>\n <TableCell>{entry.changed_by ?? '\u2014'}</TableCell>\n </TableRow>\n {/* The `&&` selectors below double specificity so they beat the\n table-level `tbody td` rules in dataTableSx \u2014 otherwise the collapsed\n row keeps its cell padding and border, leaving an empty stripe\n between entries. */}\n {hasDetail && (\n <TableRow sx={{ '&&:hover': { bgcolor: 'transparent' } }}>\n <TableCell colSpan={6} sx={{ '&&': { py: 0, border: 0 } }}>\n <Collapse in={open} unmountOnExit>\n <Box\n display=\"flex\"\n gap={2}\n flexWrap=\"wrap\"\n sx={theme => ({\n p: 2,\n mb: 1.5,\n borderRadius: 1.5,\n bgcolor: alpha(theme.palette.text.primary, theme.palette.mode === 'dark' ? 0.05 : 0.03),\n })}\n >\n {entry.before_value && (\n <Box flex={1} minWidth={200}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n display=\"block\"\n mb={0.75}\n sx={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n Before\n </Typography>\n <Typography component=\"pre\" variant=\"caption\" sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all', m: 0 }}>\n {JSON.stringify(entry.before_value, null, 2)}\n </Typography>\n </Box>\n )}\n {entry.updated_values && (\n <Box flex={1} minWidth={200}>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n display=\"block\"\n mb={0.75}\n sx={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.07em', textTransform: 'uppercase' }}\n >\n After\n </Typography>\n <Typography component=\"pre\" variant=\"caption\" sx={{ fontFamily: 'ui-monospace, SFMono-Regular, Menlo, monospace', whiteSpace: 'pre-wrap', wordBreak: 'break-all', m: 0 }}>\n {JSON.stringify(entry.updated_values, null, 2)}\n </Typography>\n </Box>\n )}\n </Box>\n </Collapse>\n </TableCell>\n </TableRow>\n )}\n </>\n );\n};\n\nfunction renderAuditLogBody(loading: boolean, entries: AuditLogEntry[]) {\n if (loading) {\n return (\n <TableRow>\n <TableCell colSpan={6} sx={{ py: 2 }}>\n <Skeleton variant=\"rounded\" height={160} />\n </TableCell>\n </TableRow>\n );\n }\n if (entries.length === 0) {\n return (\n <TableRow>\n <TableCell colSpan={6}>\n <EmptyState\n message=\"No audit events found\"\n hint=\"Try widening the filters or a different time window.\"\n />\n </TableCell>\n </TableRow>\n );\n }\n return entries.map(entry => <DetailRow key={entry.id} entry={entry} />);\n}\n\nexport const AuditLog: FC<AuditLogProps> = ({ api }) => {\n const [page, setPage] = useState(0);\n const [pageSize, setPageSize] = useState(25);\n const [filters, setFilters] = useState<Pick<AuditLogsParams, 'action' | 'table_name' | 'changed_by'>>({});\n\n const fetchParams: AuditLogsParams = useMemo(\n () => ({ page: page + 1, page_size: pageSize, ...filters }),\n [page, pageSize, filters],\n );\n\n const { value, loading, error } = useAsync(\n () => api.getAuditLogs(fetchParams),\n [api, fetchParams],\n );\n\n const entries: AuditLogEntry[] = value?.audit_logs ?? [];\n const total = value?.total ?? 0;\n\n return (\n <SectionCard\n title=\"Audit Log\"\n subtitle={loading ? 'Loading\u2026' : `${total.toLocaleString()} event${total === 1 ? '' : 's'}`}\n flush\n actions={\n <>\n <TextField\n size=\"small\"\n label=\"Action\"\n select\n value={filters.action ?? ''}\n onChange={e => { setFilters(f => ({ ...f, action: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 150 }}\n >\n <MenuItem value=\"\">All actions</MenuItem>\n <MenuItem value=\"created\">Created</MenuItem>\n <MenuItem value=\"updated\">Updated</MenuItem>\n <MenuItem value=\"deleted\">Deleted</MenuItem>\n <MenuItem value=\"blocked\">Blocked</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n label=\"Table\"\n select\n value={filters.table_name ?? ''}\n onChange={e => { setFilters(f => ({ ...f, table_name: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 150 }}\n >\n <MenuItem value=\"\">All tables</MenuItem>\n <MenuItem value=\"LiteLLM_VerificationToken\">Key</MenuItem>\n <MenuItem value=\"LiteLLM_TeamTable\">Team</MenuItem>\n <MenuItem value=\"LiteLLM_TeamMembership\">Team member</MenuItem>\n <MenuItem value=\"LiteLLM_ObjectPermissionTable\">Team access (KB / MCP)</MenuItem>\n <MenuItem value=\"LiteLLM_UserTable\">User</MenuItem>\n </TextField>\n <TextField\n size=\"small\"\n label=\"Changed by\"\n value={filters.changed_by ?? ''}\n onChange={e => { setFilters(f => ({ ...f, changed_by: e.target.value || undefined })); setPage(0); }}\n sx={{ minWidth: 180 }}\n />\n </>\n }\n >\n {error && (\n <Box px={2.5} pb={2}>\n <Alert severity=\"error\">{error.message}</Alert>\n </Box>\n )}\n\n <TableContainer>\n <Table size=\"small\" sx={dataTableSx}>\n <TableHead>\n <TableRow>\n <TableCell sx={{ width: 40 }} />\n <TableCell>Time</TableCell>\n <TableCell>Action</TableCell>\n <TableCell>Table</TableCell>\n <TableCell>Object ID</TableCell>\n <TableCell>Changed By</TableCell>\n </TableRow>\n </TableHead>\n <TableBody>\n {renderAuditLogBody(loading, entries)}\n </TableBody>\n </Table>\n </TableContainer>\n\n <TablePagination\n component=\"div\"\n count={total}\n page={page}\n onPageChange={(_, p) => setPage(p)}\n rowsPerPage={pageSize}\n onRowsPerPageChange={e => { setPageSize(Number(e.target.value)); setPage(0); }}\n rowsPerPageOptions={[10, 25, 50]}\n sx={theme => ({ borderTop: `1px solid ${theme.palette.divider}` })}\n />\n </SectionCard>\n );\n};\n", "/**\n * Convert a Date to a local calendar day string in YYYY-MM-DD format.\n * Uses local calendar components (getFullYear, getMonth, getDate),\n * not UTC, to avoid timezone shifts at month/year boundaries.\n */\nexport function toLocalDay(d: Date): string {\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return `${year}-${month}-${day}`;\n}\n\n/**\n * Month-to-date range as YYYY-MM-DD strings: the 1st of the current month through today.\n * Uses local calendar, not UTC, to respect the user's timezone.\n */\nexport function monthToDateRange(now: Date = new Date()): { startDate: string; endDate: string } {\n const start = new Date(now.getFullYear(), now.getMonth(), 1);\n return {\n startDate: toLocalDay(start),\n endDate: toLocalDay(now),\n };\n}\n\nexport type DatePreset = 'today' | '24h' | '7d' | '30d';\n\n/**\n * Build a date range from a preset name. Returns an object with\n * Date objects and pre-formatted YYYY-MM-DD strings for API calls.\n */\nexport function localDateRange(\n preset: DatePreset,\n now: Date = new Date(),\n): { start: Date; end: Date; startDate: string; endDate: string } {\n const end = new Date(now);\n const start = new Date(now);\n\n if (preset === 'today') {\n start.setHours(0, 0, 0, 0);\n } else if (preset === '24h') {\n start.setHours(start.getHours() - 24);\n } else if (preset === '7d') {\n start.setDate(start.getDate() - 7);\n } else if (preset === '30d') {\n start.setDate(start.getDate() - 30);\n }\n\n return {\n start,\n end,\n startDate: toLocalDay(start),\n endDate: toLocalDay(end),\n };\n}\n", "/**\n * Feedback message generation for toast notifications.\n * Maps action outcomes to appropriate toast messages and severity levels.\n */\n\nexport type AlertSeverity = 'success' | 'warning' | 'error' | 'info';\n\nexport interface AlertMessage {\n message: string;\n severity: AlertSeverity;\n}\n\ntype ActionKind =\n | 'generateSuccess'\n | 'generateError'\n | 'updateSuccess'\n | 'updateError'\n | 'blockSuccess'\n | 'blockError'\n | 'unblockSuccess'\n | 'unblockError'\n | 'resetSpendSuccess'\n | 'resetSpendError'\n | 'deleteSuccess'\n | 'deleteError'\n | 'deleteAlreadyDeleted'\n | 'pruneSuccess'\n | 'prunePartial'\n | 'pruneError'\n | 'teamSaveSuccess'\n | 'teamSaveError'\n | 'knowledgeBaseSuccess'\n | 'mcpServerSuccess';\n\n/**\n * Generate a toast alert message for an action outcome.\n * For inline dialog errors (e.g., key form validation), return null\n * to let the dialog handle it internally.\n */\nexport function toastFor(kind: ActionKind, errorMsg?: string): AlertMessage | null {\n switch (kind) {\n case 'generateSuccess':\n return { message: 'Key generated successfully', severity: 'success' };\n case 'generateError':\n return { message: `Failed to generate key: ${errorMsg}`, severity: 'error' };\n\n case 'updateSuccess':\n return { message: 'Key updated successfully', severity: 'success' };\n case 'updateError':\n return { message: `Failed to update key: ${errorMsg}`, severity: 'error' };\n\n case 'blockSuccess':\n return { message: 'Key blocked \u2014 requests will be rejected until unblocked', severity: 'warning' };\n case 'blockError':\n return { message: `Failed to block key: ${errorMsg}`, severity: 'error' };\n\n case 'unblockSuccess':\n return { message: 'Key unblocked', severity: 'success' };\n case 'unblockError':\n return { message: `Failed to unblock key: ${errorMsg}`, severity: 'error' };\n\n case 'resetSpendSuccess':\n return { message: 'Spend counter reset to $0', severity: 'success' };\n case 'resetSpendError':\n return { message: `Failed to reset spend: ${errorMsg}`, severity: 'error' };\n\n case 'deleteSuccess':\n return { message: 'Key revoked successfully', severity: 'success' };\n case 'deleteError':\n return { message: `Failed to revoke key: ${errorMsg}`, severity: 'error' };\n case 'deleteAlreadyDeleted':\n return { message: 'Key was already deleted', severity: 'warning' };\n\n case 'pruneSuccess':\n return { message: 'Pruned expired keys', severity: 'success' };\n case 'prunePartial':\n return { message: 'Pruned expired keys (some failed to delete)', severity: 'warning' };\n case 'pruneError':\n return { message: `Failed to prune expired keys: ${errorMsg}`, severity: 'error' };\n\n case 'teamSaveSuccess':\n return { message: 'Team saved', severity: 'success' };\n case 'teamSaveError':\n return { message: `Failed to save team: ${errorMsg}`, severity: 'error' };\n\n case 'knowledgeBaseSuccess':\n return { message: 'Knowledge bases updated', severity: 'success' };\n\n case 'mcpServerSuccess':\n return { message: 'MCP servers updated', severity: 'success' };\n\n default:\n return null;\n }\n}\n", "import { TeamInfo } from './types';\n\n/**\n * Checks whether a user can manage members of a team (add/remove members).\n * A user is a member manager if:\n * - The feature is not in readOnly mode (teams synced from identity provider)\n * - There are configured memberManagerRoles\n * - The user is a member of the team with a role in memberManagerRoles\n */\nexport function isTeamMemberManager(\n team: TeamInfo | undefined,\n userId: string | undefined,\n memberManagerRoles: string[] | undefined,\n readOnly: boolean | undefined,\n): boolean {\n if (!team || !userId || !memberManagerRoles || memberManagerRoles.length === 0 || readOnly) {\n return false;\n }\n return team.members_with_roles?.some(m => m.user_id === userId && memberManagerRoles.includes(m.role)) ?? false;\n}\n", "/**\n * Copy for unprovisioned users.\n */\n\nexport function getUnprovisionedTitle(): string {\n return 'Your LiteLLM account isn\\'t set up yet';\n}\n\nexport function getUnprovisionedMessage(supportContact?: string): string {\n const contact = supportContact?.trim();\n if (contact) {\n return `Contact ${contact}`;\n }\n return 'Contact your administrator';\n}\n\nexport function getAdminDetailsTitle(): string {\n return 'Details for administrators';\n}\n\nexport function getAdminDetailsMessage(): string {\n return 'Set litellm.provisioning.enabled: true in app-config.yaml to enable auto-provisioning, or ask your administrator to create the account manually.';\n}\n", "import { FC, useCallback, useEffect, useMemo, useState } from 'react';\nimport Box from '@mui/material/Box';\nimport Alert from '@mui/material/Alert';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport Tabs from '@mui/material/Tabs';\nimport Tab from '@mui/material/Tab';\nimport Grid from '@mui/material/Grid';\nimport Accordion from '@mui/material/Accordion';\nimport AccordionSummary from '@mui/material/AccordionSummary';\nimport AccordionDetails from '@mui/material/AccordionDetails';\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport { useSearchParams } from 'react-router-dom';\nimport { useAsync, useAsyncRetry } from 'react-use';\nimport { useApi, alertApiRef } from '@backstage/core-plugin-api';\nimport { Content, Progress } from '@backstage/core-components';\nimport { usePermission } from '@backstage/plugin-permission-react';\nimport { DashboardHeader } from './DashboardHeader';\nimport { KeysTable } from './KeysTable';\nimport { KeyFormDialog } from './KeyFormDialog';\nimport { ManageTeamDialog } from './ManageTeamDialog';\nimport { UsageStats } from './UsageStats';\nimport { LiteLLMBudgetWidget } from './LiteLLMBudgetWidget';\nimport { TeamUsage } from './TeamUsage';\nimport { ModelsTable } from './ModelsTable';\nimport { AuditLog } from './AuditLog';\nimport { liteLlmApiRef } from '../api';\nimport { toLocalDay } from '../dates';\nimport {\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n} from '@acarmisc/backstage-plugin-litellm-common';\nimport { DateRange, GenerateKeyRequest, GenerateKeyResponse, UpdateKeyRequest, UsageMetrics, CreateTeamRequest, UpdateTeamRequest, TeamInfo, VirtualKey } from '../types';\nimport { toastFor } from '../feedback';\nimport { isTeamMemberManager } from '../teamMemberManager';\nimport {\n getUnprovisionedTitle,\n getUnprovisionedMessage,\n getAdminDetailsTitle,\n getAdminDetailsMessage,\n} from '../unprovisionedCopy';\n\nconst PERIOD_LS_KEY = 'litellm_usage_period';\ntype DatePreset = 'today' | '24h' | '7d' | '30d';\n\ntype PageTab = 'overview' | 'keys' | 'teams' | 'models' | 'audit';\nconst PAGE_TABS: readonly PageTab[] = ['overview', 'keys', 'teams', 'models', 'audit'];\nconst isPageTab = (v: string | null): v is PageTab =>\n !!v && (PAGE_TABS as readonly string[]).includes(v);\n\nfunction initDateRange(): DateRange {\n let preset = '7d';\n try { preset = localStorage.getItem(PERIOD_LS_KEY) ?? '7d'; } catch { /* ignore */ }\n const end = new Date();\n const start = new Date();\n if (preset === 'today') start.setHours(0, 0, 0, 0);\n else if (preset === '24h') start.setHours(start.getHours() - 24);\n else if (preset === '30d') start.setDate(start.getDate() - 30);\n else start.setDate(start.getDate() - 7);\n return { start, end };\n}\n\nexport const LiteLLMPage: FC = () => {\n const api = useApi(liteLlmApiRef);\n const alertApi = useApi(alertApiRef);\n\n const [dateRange, setDateRange] = useState<DateRange>(initDateRange);\n const [currentPreset, setCurrentPreset] = useState<DatePreset>(() => {\n try { return (localStorage.getItem(PERIOD_LS_KEY) as DatePreset) ?? '7d'; } catch { return '7d'; }\n });\n const [searchParams, setSearchParams] = useSearchParams();\n const [activeTab, setActiveTab] = useState<PageTab>(() => {\n const t = searchParams.get('tab');\n return isPageTab(t) ? t : 'overview';\n });\n const [filter, setFilter] = useState<'expired' | 'expiring' | undefined>(() => {\n const f = searchParams.get('filter');\n return f === 'expired' || f === 'expiring' ? f : undefined;\n });\n\n // `?generate=1` (e.g. from a homepage budget card's \"Generate New Key\"\n // CTA) opens the generate-key dialog on arrival. The param is cleared once honoured so a\n // manual close doesn't immediately reopen it on the next render.\n const [generateDialogOpen, setGenerateDialogOpen] = useState(\n () => searchParams.get('generate') === '1',\n );\n useEffect(() => {\n if (searchParams.get('generate') !== '1') return;\n setGenerateDialogOpen(true);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.delete('generate');\n return next;\n },\n { replace: true },\n );\n }, [searchParams, setSearchParams]);\n\n // Keep `?tab=` in sync so links (e.g. the budget widget's \"more keys\"\n // note pointing at `/litellm?tab=keys`) land on the right tab and the URL\n // stays shareable.\n const selectTab = useCallback(\n (tab: PageTab) => {\n setActiveTab(tab);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.set('tab', tab);\n return next;\n },\n { replace: true },\n );\n },\n [setSearchParams],\n );\n\n // Navigate to keys tab with a filter applied\n const navigateToFilter = useCallback(\n (f: 'expired' | 'expiring') => {\n setActiveTab('keys');\n setFilter(f);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.set('tab', 'keys');\n next.set('filter', f);\n return next;\n },\n { replace: true },\n );\n },\n [setSearchParams],\n );\n\n // Clear filter when explicitly requested\n const clearFilter = useCallback(() => {\n setFilter(undefined);\n setSearchParams(\n prev => {\n const next = new URLSearchParams(prev);\n next.delete('filter');\n return next;\n },\n { replace: true },\n );\n }, [setSearchParams]);\n\n const [manageTeam, setManageTeam] = useState<{ mode: 'create' | 'edit' | 'members'; team?: TeamInfo } | null>(null);\n /** Which key is open in the shared key form dialog; null = create mode. */\n const [keyToEdit, setKeyToEdit] = useState<VirtualKey | null>(null);\n const keyFormOpen = generateDialogOpen || !!keyToEdit;\n\n // Team usage cache: teamId -> UsageMetrics\n const [teamUsageCache, setTeamUsageCache] = useState<Record<string, UsageMetrics | null>>({});\n const [teamUsageLoading, setTeamUsageLoading] = useState<Record<string, boolean>>({});\n\n const { value: userInfo, loading: userLoading, error: userError } = useAsync(\n () => api.getUserInfo(),\n [api],\n );\n\n const { value: keys, loading: keysLoading, error: keysError, retry: refreshKeys } = useAsyncRetry(\n () => api.listKeys(),\n [api],\n );\n\n const { value: allModels, loading: modelsLoading, error: modelsError, retry: refreshModels } = useAsyncRetry(\n () => api.listModels(),\n [api],\n );\n\n const { value: allTeams, loading: teamsLoading, error: teamsError, retry: refreshTeams } = useAsyncRetry(\n () => api.getTeams(),\n [api],\n );\n\n const { value: liteLlmConfig } = useAsync(() => api.getConfig(), [api]);\n\n // Teams the caller administers by group ownership (not membership). Only\n // fetched when team management is enabled; failures degrade to an empty list.\n const { value: managedTeams } = useAsync(\n async () =>\n liteLlmConfig?.teamManagement?.enabled\n ? api.getManagedTeams().catch(() => [])\n : [],\n [api, liteLlmConfig],\n );\n\n const { allowed: canCreateTeam } = usePermission({ permission: litellmTeamCreatePermission });\n const { allowed: canManageTeam } = usePermission({ permission: litellmTeamManagePermission });\n const { allowed: canManageMembers } = usePermission({ permission: litellmTeamMembersManagePermission });\n const { allowed: canManageKnowledgeBases } = usePermission({ permission: litellmTeamKnowledgebaseManagePermission });\n const { allowed: canManageMcpServers } = usePermission({ permission: litellmTeamMcpManagePermission });\n const teamMgmtEnabled = liteLlmConfig?.teamManagement?.enabled ?? false;\n const objectPermsEnabled = liteLlmConfig?.teamManagement?.objectPermissionsEnabled ?? false;\n\n const { value: vectorStores } = useAsync(\n async () =>\n objectPermsEnabled ? api.getVectorStores().catch(() => []) : [],\n [api, objectPermsEnabled],\n );\n const { value: mcpServers } = useAsync(\n async () =>\n objectPermsEnabled ? api.getMcpServers().catch(() => []) : [],\n [api, objectPermsEnabled],\n );\n\n // Filter to teams the current user belongs to\n const teams = useMemo(() => {\n if (!allTeams?.length) return [];\n if (!userInfo) return allTeams;\n const userId = userInfo.user_id;\n const memberOf = userInfo.teams;\n if (memberOf?.length) {\n return allTeams.filter(t => memberOf.includes(t.team_id));\n }\n // No team list on the profile: fall back to membership on the team records.\n // Never fall back to *all* teams \u2014 that would list teams the user isn't in.\n return allTeams.filter(t =>\n t.members_with_roles?.some(m => m.user_id === userId),\n );\n }, [allTeams, userInfo]);\n\n const { value: usage, loading: usageLoading, error: usageError, retry: refreshUsage } = useAsyncRetry(async () => {\n const startDate = toLocalDay(dateRange.start);\n const endDate = toLocalDay(dateRange.end);\n return api.getUsage(startDate, endDate);\n }, [api, dateRange]);\n\n // Invalidate team usage cache when date range changes so stale data isn't shown\n const handleDateRangeChange = useCallback((range: DateRange, preset?: DatePreset) => {\n setDateRange(range);\n if (preset) {\n setCurrentPreset(preset);\n }\n setTeamUsageCache({});\n setTeamUsageLoading({});\n }, [setDateRange, setCurrentPreset]);\n\n // Fetch team usage on demand when a team card is expanded\n const loadTeamUsage = useCallback(async (teamId: string) => {\n if (teamUsageCache[teamId] !== undefined || teamUsageLoading[teamId]) return;\n setTeamUsageLoading(prev => ({ ...prev, [teamId]: true }));\n try {\n const startDate = toLocalDay(dateRange.start);\n const endDate = toLocalDay(dateRange.end);\n const data = await api.getTeamUsage(teamId, startDate, endDate);\n setTeamUsageCache(prev => ({ ...prev, [teamId]: data }));\n } catch {\n setTeamUsageCache(prev => ({ ...prev, [teamId]: null }));\n } finally {\n setTeamUsageLoading(prev => ({ ...prev, [teamId]: false }));\n }\n }, [api, dateRange, teamUsageCache, teamUsageLoading]);\n\n // Models offered for key generation: when the user has a model restriction, the\n // UNION of their own allowed models and their teams' models (a team-bound key is\n // limited to its team's models, which the server enforces and the key form then\n // narrows to the selected team); with no restriction, every model. The server\n // (POST /keys/generate) is the source of truth for what is actually accepted.\n const allowedModels = useMemo(() => {\n if (!allModels?.length) return [];\n const userModels = userInfo?.models;\n const teamModels = teams?.flatMap(t => t.models ?? []);\n const hasUserRestriction = userModels && userModels.length > 0;\n const hasTeamRestriction = teamModels && teamModels.length > 0;\n if (!hasUserRestriction && !hasTeamRestriction) return allModels;\n const allowed = new Set([\n ...(hasUserRestriction ? userModels! : allModels.map(m => m.model_name)),\n ...(hasTeamRestriction ? teamModels! : []),\n ]);\n return allModels.filter(m => allowed.has(m.model_name));\n }, [allModels, userInfo, teams]);\n\n const getConfig = useCallback(() => api.getConfig(), [api]);\n\n const handleGenerateKey = useCallback(\n async (request: GenerateKeyRequest): Promise<GenerateKeyResponse> => {\n try {\n const response = await api.generateKey(request);\n const alert = toastFor('generateSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n return response;\n } catch (e: any) {\n // The dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleUpdateKey = useCallback(\n async (keyId: string, request: UpdateKeyRequest) => {\n try {\n await api.updateKey(keyId, request);\n const alert = toastFor('updateSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n // The dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleBlockKey = useCallback(\n async (keyId: string) => {\n try {\n await api.blockKey(keyId);\n const alert = toastFor('blockSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('blockError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleUnblockKey = useCallback(\n async (keyId: string) => {\n try {\n await api.unblockKey(keyId);\n const alert = toastFor('unblockSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('unblockError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleResetKeySpend = useCallback(\n async (keyId: string) => {\n try {\n await api.resetKeySpend(keyId);\n const alert = toastFor('resetSpendSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n // The key dialog renders this error inline; don't toast it as well.\n throw e;\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handleDeleteKey = useCallback(\n async (keyId: string) => {\n try {\n await api.deleteKey(keyId);\n const alert = toastFor('deleteSuccess');\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n if (e.body?.success && (e.body?.message?.includes('already deleted') || e.body?.message?.includes('never existed'))) {\n const alert = toastFor('deleteAlreadyDeleted');\n if (alert) alertApi.post(alert);\n refreshKeys();\n return;\n }\n const alert = toastFor('deleteError', e.message);\n if (alert) alertApi.post(alert);\n }\n },\n [api, refreshKeys, alertApi],\n );\n\n const handlePruneExpiredKeys = useCallback(\n async () => {\n try {\n const result = await api.pruneExpiredKeys();\n const kind = result.failed > 0 ? 'prunePartial' : 'pruneSuccess';\n const alert = toastFor(kind);\n if (alert) alertApi.post(alert);\n refreshKeys();\n } catch (e: any) {\n const alert = toastFor('pruneError', e.message);\n if (alert) alertApi.post(alert);\n }\n return { pruned: 0, failed: 0 };\n },\n [api, refreshKeys, alertApi],\n ) as () => Promise<{ pruned: number; failed: number }>;\n\n const isInitialLoading = userLoading && !userInfo;\n\n if (isInitialLoading) {\n return <Progress />;\n }\n\n // User exists in Backstage but has no LiteLLM account\n if (userError || !userInfo) {\n const hint = (userError as any)?.body?.hint;\n return (\n <Box sx={{ p: 3, display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box\n sx={{\n maxWidth: 600,\n mx: 'auto',\n py: 6,\n textAlign: 'center',\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 2,\n }}\n >\n <Typography variant=\"h5\" sx={{ fontWeight: 600 }}>\n {getUnprovisionedTitle()}\n </Typography>\n <Typography color=\"text.secondary\">\n {hint || getUnprovisionedMessage(liteLlmConfig?.supportContact)}\n </Typography>\n <Accordion sx={{ width: '100%', maxWidth: 500, mt: 2 }}>\n <AccordionSummary expandIcon={<ExpandMoreIcon />}>\n <Typography variant=\"body2\" sx={{ fontWeight: 500 }}>\n {getAdminDetailsTitle()}\n </Typography>\n </AccordionSummary>\n <AccordionDetails>\n <Typography variant=\"caption\" color=\"text.secondary\">\n {getAdminDetailsMessage()}\n </Typography>\n </AccordionDetails>\n </Accordion>\n </Box>\n </Box>\n );\n }\n\n const pageTabs = (\n <Tabs\n value={activeTab}\n onChange={(_, v) => selectTab(v as PageTab)}\n variant=\"scrollable\"\n scrollButtons=\"auto\"\n // Substring class matching so these survive a host MUI classname prefix\n // (Backstage renders `v5-MuiTabs-indicator`, not `MuiTabs-indicator`).\n sx={{\n minHeight: 44,\n '& [class*=\"MuiTabs-indicator\"]': { height: 2, borderRadius: '2px 2px 0 0' },\n '& [class*=\"MuiTab-root\"]': { minHeight: 44, textTransform: 'none', fontSize: 14 },\n }}\n >\n <Tab label=\"Overview\" value=\"overview\" />\n <Tab label=\"Keys\" value=\"keys\" />\n <Tab label=\"Teams\" value=\"teams\" />\n <Tab label=\"Models\" value=\"models\" />\n {userInfo.can_view_audit && <Tab label=\"Audit Log\" value=\"audit\" />}\n </Tabs>\n );\n\n return (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n <Box sx={{ px: 3, pt: 3 }}>\n <DashboardHeader\n userInfo={userInfo}\n teams={teams ?? []}\n keys={keys ?? []}\n loading={userLoading || teamsLoading}\n keysError={keysError}\n onGenerateKeyClick={() => setGenerateDialogOpen(true)}\n onNavigateToFilter={navigateToFilter}\n tabs={pageTabs}\n />\n </Box>\n\n <Content>\n {activeTab === 'overview' && (() => {\n // Show onboarding when keys have loaded without error and list is empty\n if (!keysLoading && !keysError && keys?.length === 0) {\n return (\n <Box sx={{ maxWidth: 600, mx: 'auto', py: 4 }}>\n <Box\n sx={{\n textAlign: 'center',\n py: 6,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 3,\n }}\n >\n <Typography variant=\"h5\" sx={{ fontWeight: 600 }}>\n Create your first API key\n </Typography>\n <Box\n component=\"ol\"\n sx={{\n textAlign: 'left',\n pl: 3,\n display: 'flex',\n flexDirection: 'column',\n gap: 1,\n '& li': { color: 'text.secondary' },\n }}\n >\n <li>Generate a key</li>\n <li>Copy the endpoint</li>\n <li>Make a call</li>\n </Box>\n <Button\n variant=\"contained\"\n color=\"primary\"\n onClick={() => setGenerateDialogOpen(true)}\n >\n Generate API Key\n </Button>\n </Box>\n </Box>\n );\n }\n\n return (\n <Grid container spacing={2} alignItems=\"flex-start\">\n <Grid item xs={12} lg={8}>\n <UsageStats\n usage={usage ?? null}\n usageError={usageError}\n onRetryUsage={refreshUsage}\n models={allModels ?? []}\n dateRange={dateRange}\n currentPreset={currentPreset}\n onDateRangeChange={handleDateRangeChange}\n loading={usageLoading}\n userInfo={userInfo}\n />\n </Grid>\n <Grid item xs={12} lg={4}>\n <LiteLLMBudgetWidget compact collapsible userInfo={userInfo ?? null} teams={teams} keys={keys ?? []} />\n </Grid>\n </Grid>\n );\n })()}\n\n {activeTab === 'keys' && (() => {\n if (keysError) {\n return (\n <Alert severity=\"error\">\n Failed to load keys: {(keysError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshKeys}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n return (\n <KeysTable\n keys={keys ?? []}\n loading={keysLoading || modelsLoading}\n onGenerateKeyClick={() => setGenerateDialogOpen(true)}\n onEditKey={setKeyToEdit}\n onBlockKey={handleBlockKey}\n onUnblockKey={handleUnblockKey}\n onDeleteKey={handleDeleteKey}\n onPruneExpiredKeys={handlePruneExpiredKeys}\n filter={filter}\n onClearFilter={clearFilter}\n />\n );\n })()}\n\n {activeTab === 'teams' && (() => {\n if (teamsError) {\n return (\n <Alert severity=\"error\">\n Failed to load teams: {(teamsError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshTeams}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n // Union of teams the user is a member of and teams their group owns,\n // de-duplicated by team_id (membership entries win on conflict).\n const teamsById = new Map<string, TeamInfo>();\n for (const t of managedTeams ?? []) teamsById.set(t.team_id, t);\n for (const t of teams ?? []) teamsById.set(t.team_id, t);\n const visibleTeams = Array.from(teamsById.values());\n const readOnly = liteLlmConfig?.teamManagement?.readOnly ?? false;\n const memberManagerRoles = liteLlmConfig?.teamManagement?.memberManagerRoles ?? [];\n\n return (\n <TeamUsage\n teams={visibleTeams}\n loading={teamsLoading}\n getTeamUsage={teamId => teamUsageCache[teamId] ?? null}\n getTeamUsageLoading={teamId => teamUsageLoading[teamId] ?? false}\n canManage={teamMgmtEnabled && canManageTeam && !readOnly}\n onEditTeam={t => setManageTeam({ mode: 'edit', team: t })}\n canCreate={teamMgmtEnabled && canCreateTeam && !readOnly}\n onCreateTeam={() => setManageTeam({ mode: 'create' })}\n canManageMembers={t =>\n teamMgmtEnabled &&\n canManageMembers &&\n isTeamMemberManager(t, userInfo?.user_id, memberManagerRoles, readOnly)\n }\n onManageMembers={t => setManageTeam({ mode: 'members', team: t })}\n readOnly={readOnly}\n onTeamExpand={team => loadTeamUsage(team.team_id)}\n />\n );\n })()}\n\n {activeTab === 'models' && (() => {\n if (modelsError) {\n return (\n <Alert severity=\"error\">\n Failed to load models: {(modelsError as any).message || 'Unknown error'}\n <Box sx={{ mt: 1 }}>\n <Button size=\"small\" onClick={refreshModels}>Retry</Button>\n </Box>\n </Alert>\n );\n }\n return (\n <ModelsTable\n allModels={allModels ?? []}\n teams={teams ?? []}\n loading={modelsLoading}\n />\n );\n })()}\n\n {activeTab === 'audit' && userInfo.can_view_audit && <AuditLog api={api} />}\n </Content>\n\n <KeyFormDialog\n open={keyFormOpen}\n onClose={() => {\n setGenerateDialogOpen(false);\n setKeyToEdit(null);\n }}\n mode={keyToEdit ? 'edit' : 'create'}\n keyToEdit={keyToEdit}\n keys={keys ?? []}\n models={allowedModels}\n modelsError={modelsError}\n onRetryModels={refreshModels}\n teams={teams ?? []}\n username={userInfo.user_id}\n keyGenerationSettings={liteLlmConfig?.keyGeneration}\n onCreateKey={handleGenerateKey}\n onUpdateKey={handleUpdateKey}\n onResetKeySpend={handleResetKeySpend}\n onGetConfig={getConfig}\n />\n\n <ManageTeamDialog\n open={!!manageTeam}\n onClose={() => setManageTeam(null)}\n mode={manageTeam?.mode === 'members' ? 'edit' : (manageTeam?.mode ?? 'create')}\n team={manageTeam?.team}\n allModels={allModels ?? []}\n config={liteLlmConfig}\n membersOnly={manageTeam?.mode === 'members'}\n currentUserId={userInfo?.user_id}\n memberManagerRoles={liteLlmConfig?.teamManagement?.memberManagerRoles}\n onSubmit={async (payload, initialMembers) => {\n try {\n if (manageTeam?.mode === 'edit' && manageTeam.team) {\n const loadedAt = manageTeam.team.metadata?.updated_at_iso;\n await api.updateTeam(manageTeam.team.team_id, {\n ...(payload as UpdateTeamRequest),\n // Reject the edit if someone else changed the team since it was loaded.\n ...(typeof loadedAt === 'string' ? { expectedUpdatedAtIso: loadedAt } : {}),\n });\n } else {\n const created = await api.createTeam(payload as CreateTeamRequest);\n // Members picked in the create dialog; one failure must not\n // hide the team that was created.\n const failed: string[] = [];\n for (const m of initialMembers ?? []) {\n try {\n await api.addTeamMember(created.team_id, m);\n } catch (e: any) {\n failed.push(`${m.userEntityRef} (${e.message})`);\n }\n }\n if (failed.length) {\n alertApi.post({\n message: `Team created, but some members could not be added: ${failed.join(', ')}`,\n severity: 'warning',\n });\n refreshTeams();\n return;\n }\n }\n const alert = toastFor('teamSaveSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n canManageMembers={teamMgmtEnabled && canManageMembers && !liteLlmConfig?.teamManagement?.readOnly}\n onAddMember={async (userEntityRef, maxBudgetInTeam) => {\n if (!manageTeam?.team) return;\n const updated = await api.addTeamMember(manageTeam.team.team_id, {\n userEntityRef,\n ...(maxBudgetInTeam ? { maxBudgetInTeam } : {}),\n });\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n refreshTeams();\n }}\n onRemoveMember={async userEntityRef => {\n if (!manageTeam?.team) return;\n const updated = await api.removeTeamMember(\n manageTeam.team.team_id,\n userEntityRef,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n refreshTeams();\n }}\n canManageKnowledgeBases={\n teamMgmtEnabled && objectPermsEnabled && canManageKnowledgeBases\n }\n vectorStores={vectorStores ?? []}\n onSaveKnowledgeBases={async vectorStoreIds => {\n if (!manageTeam?.team) return;\n try {\n const updated = await api.setTeamKnowledgeBases(\n manageTeam.team.team_id,\n vectorStoreIds,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n const alert = toastFor('knowledgeBaseSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n canManageMcpServers={\n teamMgmtEnabled && objectPermsEnabled && canManageMcpServers\n }\n mcpServers={mcpServers ?? []}\n onSaveMcpServers={async mcpServerIds => {\n if (!manageTeam?.team) return;\n try {\n const updated = await api.setTeamMcpServers(\n manageTeam.team.team_id,\n mcpServerIds,\n );\n setManageTeam(s => (s && s.team ? { ...s, team: updated } : s));\n const alert = toastFor('mcpServerSuccess');\n if (alert) alertApi.post(alert);\n refreshTeams();\n } catch (e: any) {\n const alert = toastFor('teamSaveError', e.message);\n if (alert) alertApi.post(alert);\n }\n }}\n />\n\n </Box>\n );\n};\n", "export { litellmPlugin, litellmPlugin as default } from './plugin';\nexport { LiteLLMPage } from './components/LiteLLMPage';\nexport { DashboardHeader } from './components/DashboardHeader';\nexport { KeysTable } from './components/KeysTable';\nexport { UsageStats } from './components/UsageStats';\nexport { TeamUsage } from './components/TeamUsage';\nexport { LiteLLMHomeWidget } from './components/LiteLLMHomeWidget';\nexport type { LiteLLMHomeWidgetProps } from './components/LiteLLMHomeWidget';\nexport { LiteLLMBudgetWidget } from './components/LiteLLMBudgetWidget';\nexport type { LiteLLMBudgetWidgetProps } from './components/LiteLLMBudgetWidget';\nexport { LiteLLMBudgetGauges } from './components/LiteLLMBudgetGauges';\nexport type {\n LiteLLMBudgetGaugesProps,\n BudgetCta,\n BudgetCtaKind,\n BudgetCtaSpec,\n} from './components/LiteLLMBudgetGauges';\nexport { KeyFormDialog } from './components/KeyFormDialog';\nexport type { KeyFormDialogMode, KeyFormDialogProps } from './components/KeyFormDialog';\nexport { GenerateKeyButton } from './components/GenerateKeyButton';\nexport type { GenerateKeyButtonProps } from './components/GenerateKeyButton';\nexport { ManageTeamDialog } from './components/ManageTeamDialog';\nexport { LiteLlmApi, liteLlmApiRef } from './api';\nexport {\n litellmTeamCreatePermission,\n litellmTeamManagePermission,\n litellmTeamMembersManagePermission,\n litellmTeamKnowledgebaseManagePermission,\n litellmTeamMcpManagePermission,\n} from '@acarmisc/backstage-plugin-litellm-common';\nexport type { LiteLlmApiInterface } from './api';\nexport * from './types';\n", "import { TrendingUp as TrendingUpIcon } from '@mui/icons-material';\nimport {\n createFrontendPlugin,\n ApiBlueprint,\n PageBlueprint,\n fetchApiRef,\n discoveryApiRef,\n} from '@backstage/frontend-plugin-api';\nimport { liteLlmApiRef, LiteLlmApi } from './api';\nimport { rootRouteRef } from './routes';\n\nconst liteLlmApi = ApiBlueprint.make({\n params: defineParams =>\n defineParams({\n api: liteLlmApiRef,\n deps: { fetchApi: fetchApiRef, discoveryApi: discoveryApiRef },\n factory: ({ fetchApi, discoveryApi }) => new LiteLlmApi(fetchApi, discoveryApi),\n }),\n});\n\nconst liteLlmPage = PageBlueprint.make({\n params: {\n path: '/litellm',\n title: 'LiteLLM',\n icon: <TrendingUpIcon />,\n routeRef: rootRouteRef,\n loader: async () => {\n const { LiteLLMPage } = await import('./components/LiteLLMPage');\n return <LiteLLMPage />;\n },\n },\n});\n\nexport const litellmPlugin = createFrontendPlugin({\n pluginId: 'litellm',\n routes: {\n root: rootRouteRef,\n },\n extensions: [liteLlmApi, liteLlmPage],\n});\n", "import { ElementType, FC, useEffect, useMemo, useState } from 'react';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport FormControl from '@mui/material/FormControl';\nimport Select from '@mui/material/Select';\nimport MenuItem from '@mui/material/MenuItem';\nimport Skeleton from '@mui/material/Skeleton';\nimport { AreaChart, Area, XAxis, Tooltip, ResponsiveContainer } from 'recharts';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { liteLlmApiRef } from '../api';\nimport { rootRouteRef } from '../routes';\nimport { UsageMetrics } from '../types';\nimport { fmtUsd } from '../format';\nimport { toLocalDay } from '../dates';\nimport { SERIES, ChartTooltip } from './ui';\nimport { widgetViewState, USAGE_UNAVAILABLE_MSG, UNPROVISIONED_MSG } from '../widgetState';\nimport { rangeCaption, sparklineAriaLabel, usageSummary } from '../homeWidgetHelpers';\n\nexport interface LiteLLMHomeWidgetProps {\n /** Default period when the widget mounts. Defaults to '7d'. */\n defaultPeriod?: 'today' | '7d' | '30d';\n /** Optional title override. Defaults to 'LiteLLM Usage'. */\n title?: string;\n /**\n * Render without the widget's own card chrome and title, for hosts (such as\n * the home page grid) that already provide a titled card. Defaults to false.\n */\n bare?: boolean;\n}\n\ntype DatePreset = 'today' | '7d' | '30d';\n\n\nfunction presetToDateRange(preset: DatePreset): { start: Date; end: Date } {\n const end = new Date();\n const start = new Date();\n if (preset === 'today') {\n start.setHours(0, 0, 0, 0);\n } else if (preset === '7d') {\n start.setDate(start.getDate() - 7);\n } else {\n start.setDate(start.getDate() - 30);\n }\n return { start, end };\n}\n\n\nexport const LiteLLMHomeWidget: FC<LiteLLMHomeWidgetProps> = ({\n defaultPeriod = '7d',\n title = 'LiteLLM Usage',\n bare = false,\n}) => {\n const api = useApi(liteLlmApiRef);\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const { userInfo, keys, loading: profileLoading, error: profileError } = useLiteLLMProfile();\n const [period, setPeriod] = useState<DatePreset>(defaultPeriod);\n const [usageLoading, setUsageLoading] = useState(true);\n const [usageError, setUsageError] = useState<unknown>(null);\n const [usage, setUsage] = useState<UsageMetrics | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n setUsageLoading(true);\n setUsageError(null);\n\n const { start, end } = presetToDateRange(period);\n const startDate = toLocalDay(start);\n const endDate = toLocalDay(end);\n\n api.getUsage(startDate, endDate)\n .then((usageResult) => {\n if (cancelled) return;\n setUsage(usageResult);\n setUsageLoading(false);\n })\n .catch((err) => {\n if (!cancelled) {\n setUsageError(err);\n setUsage(null);\n setUsageLoading(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n }, [api, period]);\n\n const viewState = useMemo(\n () => widgetViewState({\n loading: profileLoading || usageLoading,\n error: profileError,\n userInfo,\n usageError,\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [profileLoading, usageLoading, profileError, userInfo, usageError, keys],\n );\n\n const Wrapper: ElementType = bare ? Box : Paper;\n const partialFailure = !usageLoading && usageError && usage;\n\n const dailyData = (usage?.daily_usage ?? []).map(d => ({\n date: d.date,\n spend: d.spend,\n }));\n\n const hasSparkline = dailyData.length > 0;\n\n const { start, end } = presetToDateRange(period);\n const startDate = toLocalDay(start);\n const endDate = toLocalDay(end);\n const dateRangeCaption = rangeCaption(startDate, endDate);\n const sparklineAriaLabelText = sparklineAriaLabel(dailyData);\n\n return (\n <Wrapper sx={bare ? { height: '100%' } : { p: 2, height: '100%' }}>\n {/* Card header */}\n <Box display=\"flex\" justifyContent={bare ? 'flex-end' : 'space-between'} alignItems=\"center\" mb={1.5}>\n {!bare && <Typography variant=\"h6\">{title}</Typography>}\n <FormControl size=\"small\" sx={{ minWidth: 90 }}>\n <Select\n value={period}\n onChange={e => setPeriod(e.target.value as DatePreset)}\n displayEmpty\n inputProps={{ 'aria-label': 'Usage period' }}\n >\n <MenuItem value=\"today\">Today</MenuItem>\n <MenuItem value=\"7d\">7d</MenuItem>\n <MenuItem value=\"30d\">30d</MenuItem>\n </Select>\n </FormControl>\n </Box>\n\n {/* Loading state */}\n {viewState.kind === 'loading' && (\n <Box sx={{ minHeight: 120 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={20} sx={{ mb: 1 }} />\n <Skeleton variant=\"rectangular\" width=\"100%\" height={100} />\n </Box>\n )}\n\n {/* Error state */}\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {viewState.message}\n </Typography>\n )}\n\n {/* Unprovisioned state */}\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 1 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {/* Content */}\n {viewState.kind === 'ready' && partialFailure && (\n <Box sx={{ mt: 1, mb: 1, p: 1, backgroundColor: 'action.hover', borderRadius: 1 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {USAGE_UNAVAILABLE_MSG}\n </Typography>\n </Box>\n )}\n\n {viewState.kind === 'ready' && (\n <>\n {/* Summary line */}\n <Typography\n variant=\"body2\"\n sx={{\n fontWeight: 500,\n mb: hasSparkline ? 1.5 : 1,\n color: viewState.usageUnavailable ? 'text.secondary' : 'text.primary',\n }}\n >\n {viewState.usageUnavailable ? USAGE_UNAVAILABLE_MSG : usageSummary(usage)}\n </Typography>\n\n {/* Sparkline with caption */}\n {hasSparkline && !viewState.usageUnavailable && (\n <>\n <Box\n height={80}\n role=\"img\"\n aria-label={sparklineAriaLabelText}\n sx={{ mb: 0.5 }}\n >\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={dailyData} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <XAxis dataKey=\"date\" hide />\n <Tooltip content={<ChartTooltip valueFormatter={fmtUsd} />} />\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n fill={SERIES.spend}\n fillOpacity={0.3}\n dot={false}\n isAnimationActive={false}\n />\n </AreaChart>\n </ResponsiveContainer>\n </Box>\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ display: 'block', mb: 1 }}>\n daily spend ({dateRangeCaption})\n </Typography>\n </>\n )}\n\n {/* Footer link */}\n {moduleRouteRef?.() && (\n <Typography variant=\"caption\" sx={{ mt: 1, display: 'block' }}>\n <Link to={moduleRouteRef()} color=\"primary\">\n Open LiteLLM \u2192\n </Link>\n </Typography>\n )}\n </>\n )}\n </Wrapper>\n );\n};\n", "import { fmtUsd } from './format';\nimport { fmtCompact, fmtDateShort } from './components/ui/tokens';\nimport { toLocalDay } from './dates';\nimport type { UsageMetrics } from './types';\n\n/**\n * Build a human-readable date range caption from two YYYY-MM-DD strings.\n * Example: '2026-09-01', '2026-09-29' \u2192 'Sep 1 \u2013 Sep 29'\n */\nexport function rangeCaption(startDay: string, endDay: string): string {\n return `${fmtDateShort(startDay)} \u2013 ${fmtDateShort(endDay)}`;\n}\n\n/**\n * Build a month-to-date range caption from a Date.\n * Example: new Date('2026-09-29') \u2192 'Sep 1 \u2013 29'\n * Handles same-day (returns date twice) and month/year edge cases.\n */\nexport function mtdCaption(now: Date = new Date()): string {\n const year = now.getFullYear();\n const month = now.getMonth();\n const day = now.getDate();\n const startDay = `${year}-${String(month + 1).padStart(2, '0')}-01`;\n const endDay = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;\n return rangeCaption(startDay, endDay);\n}\n\n/**\n * Build an aria-label summary for a sparkline chart showing daily spend data.\n * Includes total spend, peak value, and the date it occurred.\n * Example: 'Daily spend over 7 days, total $129.90, peak $41.20 on Sep 27'\n */\nexport function sparklineAriaLabel(points: Array<{ date: string; spend: number }>): string {\n if (!points || points.length === 0) {\n return 'No daily spend data';\n }\n\n const total = points.reduce((sum, p) => sum + p.spend, 0);\n const maxPoint = points.reduce(\n (max, p) => (p.spend > max.spend ? p : max),\n points[0],\n );\n\n const dayCount = points.length;\n const peakDate = fmtDateShort(maxPoint.date);\n\n return `Daily spend over ${dayCount} day${dayCount === 1 ? '' : 's'}, total ${fmtUsd(total)}, peak ${fmtUsd(maxPoint.spend)} on ${peakDate}`;\n}\n\n/**\n * Spend recorded on the local calendar day `now` (defaults to today) in a\n * daily-spend series. Days the API omits count as zero \u2014 no spend recorded\n * yet \u2014 so a chart that simply hasn't seen a request today still answers\n * `$0.00` instead of `undefined`.\n *\n * `now` is overridable so the same helper yields yesterday's figure\n * (`spendOnDay(points, yesterday)`) for a day-over-day hint.\n */\nexport function spendOnDay(\n points: Array<{ date: string; spend: number }>,\n now: Date = new Date(),\n): number {\n const day = toLocalDay(now);\n return points.find(p => p.date === day)?.spend ?? 0;\n}\n\n/**\n * Format usage metrics as a single summary line: '$X spent \u00B7 YM in \u00B7 ZM out'\n * Handles zero usage and undefined values gracefully.\n */\nexport function usageSummary(usage: UsageMetrics | null | undefined): string {\n if (!usage) {\n return '$0.00 spent \u00B7 0 in \u00B7 0 out';\n }\n\n const spent = fmtUsd(usage.total_spend ?? 0);\n const tokenIn = fmtCompact(usage.prompt_tokens ?? 0);\n const tokenOut = fmtCompact(usage.completion_tokens ?? 0);\n\n return `${spent} spent \u00B7 ${tokenIn} in \u00B7 ${tokenOut} out`;\n}\n\n/**\n * Build ARIA attributes for a meter component showing a percentage value.\n * When value > 100%, sets aria-valuetext to include \"over cap\" warning.\n * Returns an object with role, aria-valuenow, aria-valuemin, aria-valuemax,\n * aria-label, and optionally aria-valuetext.\n */\nexport function meterAria(\n pct: number,\n label?: string,\n): {\n role: string;\n 'aria-valuenow': number;\n 'aria-valuemin': number;\n 'aria-valuemax': number;\n 'aria-label'?: string;\n 'aria-valuetext'?: string;\n} {\n const attrs: ReturnType<typeof meterAria> = {\n role: 'meter',\n 'aria-valuenow': Math.max(0, Math.min(100, pct)),\n 'aria-valuemin': 0,\n 'aria-valuemax': 100,\n };\n\n if (label) {\n attrs['aria-label'] = label;\n }\n\n if (pct > 100) {\n attrs['aria-valuetext'] = `${Math.round(pct)}% \u2014 over cap`;\n }\n\n return attrs;\n}\n", "/**\n * Condensed budget card for a homepage column: spend KPIs on one line,\n * one inline row per enforcement level (key \u2192 personal \u2192 team), and a\n * month-to-date daily spend strip, in a fixed card that never reflows.\n *\n * The card is deliberately *row*-shaped rather than four side-by-side\n * columns: a four-column grid lets one long key alias widen its track (a\n * `1fr` track is only as narrow as its widest unbreakable content) and lets\n * each column wrap its own number of caption lines, so the text under the\n * rings drifts out of alignment. Rows share three fixed tracks \u2014 ring,\n * flexible name, right-aligned amount \u2014 so every figure is in the same\n * place and tabular numerals line up, and a long name ellipsizes inside\n * `minmax(0, 1fr)` instead of stretching anything.\n *\n * Each row shows the limit nearest its cap at that level: the ring carries\n * the percentage, the middle track the level tag, limit name and a short\n * note (over cap, a `+N more` link, or the key id / email), and the right\n * track the spend-vs-cap dollars over the reset window \u2014 one caption per\n * fact, so the reset window is never printed twice in a row. Where the full `LiteLLMBudgetWidget` lists every limit as a\n * meter card, this trades detail for density. Gauges are always rendered in\n * the same order, with an empty ring when the user has no cap at that\n * level, so the card keeps a stable shape as data loads and across users.\n *\n * Above the rows sit two inline KPIs \u2014 **today spent** (with a\n * day-over-day hint) and month-to-date spend \u2014 both derived from the same\n * month-to-date usage call, so the indicator costs no extra request. The\n * usage period is frozen to month-to-date (no period selector): the chart\n * always covers the 1st of the current month through today.\n *\n * The bottom action bar is composable: pass any subset of `ctas` \u2014 generate\n * a new key, open the LiteLLM module, or expand the full per-limit list in\n * place \u2014 in the order you want. `action` remains an escape hatch for a\n * fully custom node; when either is present it renders below a divider. The\n * `new-key` CTA renders the shared `GenerateKeyButton`, identical to the\n * one on the plugin page.\n */\nimport { ElementType, FC, ReactNode, useCallback, useEffect, useId, useMemo, useState } from 'react';\nimport { useRouteRef } from '@backstage/frontend-plugin-api';\nimport Paper from '@mui/material/Paper';\nimport Box from '@mui/material/Box';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport Skeleton from '@mui/material/Skeleton';\nimport Collapse from '@mui/material/Collapse';\nimport { useTheme } from '@mui/material/styles';\nimport useMediaQuery from '@mui/material/useMediaQuery';\nimport { ExpandMore } from '@mui/icons-material';\nimport { AreaChart, Area, ResponsiveContainer, Tooltip, ReferenceLine, XAxis } from 'recharts';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport { useLiteLLMProfile } from '../hooks/useLiteLLMProfile';\nimport { liteLlmApiRef } from '../api';\nimport { UserInfo, TeamInfo, VirtualKey } from '../types';\nimport { fmtUsd } from '../format';\nimport { monthToDateRange, toLocalDay } from '../dates';\nimport { resolveCtas, type BudgetCtaKind, type BudgetCtaSpec, type BudgetCta } from '../ctas';\nimport { widgetViewState, USAGE_UNAVAILABLE_MSG, UNPROVISIONED_MSG } from '../widgetState';\nimport { Gauge, StatusPill, ChartTooltip, SERIES, toneColor, type Tone } from './ui';\nimport { GenerateKeyButton } from './GenerateKeyButton';\nimport { BudgetLimitList, LimitListPanel } from './BudgetLimitList';\nimport {\n allBudgetLimits,\n buildBudgetGauges,\n buildBudgetSummary,\n budgetHeadline,\n BudgetGauge,\n BudgetLimit,\n budgetTone,\n fmtBudgetDuration,\n} from '../budget';\nimport { rootRouteRef } from '../routes';\nimport { mtdCaption, sparklineAriaLabel, spendOnDay } from '../homeWidgetHelpers';\n\nexport type { BudgetCtaKind, BudgetCtaSpec, BudgetCta } from '../ctas';\n\nexport interface LiteLLMBudgetGaugesProps {\n /** Optional title override. Defaults to 'Budget'. */\n title?: string;\n /**\n * Render without the card's own chrome and title, for hosts (such as the\n * home page grid) that already provide a titled card. Defaults to false.\n */\n bare?: boolean;\n /** Ring diameter in px. Defaults to 56. */\n size?: number;\n /** Where the \"+N more\" key link points. Defaults to the Keys tab. */\n keysHref?: string;\n /** Where the module CTA points. Defaults to the LiteLLM page. */\n moduleHref?: string;\n /**\n * Called when the \"Generate New Key\" CTA is used. When omitted, the CTA\n * deep-links to the module with `?generate=1`, which opens the\n * generate-key dialog.\n */\n onCreateKey?: () => void;\n /**\n * Action-bar buttons to render, in order. Defaults to\n * `['module', 'all-limits']`; 'new-key' is added automatically for users with no keys. Pass `[]` to hide the bar; the\n * `all-limits` entry is dropped automatically when the user has no limits.\n */\n ctas?: BudgetCta[];\n /** Max key limits listed in the expanded view. Defaults to 8. */\n maxExpandedKeys?: number;\n /** Controlled expanded state for the all-limits view. */\n expanded?: boolean;\n /** Initial expanded state when uncontrolled. Defaults to false. */\n defaultExpanded?: boolean;\n /** Notified whenever the expanded state changes. */\n onExpandedChange?: (expanded: boolean) => void;\n /** Fully custom node pinned below the CTAs, below a divider. */\n action?: ReactNode;\n /**\n * Optional preloaded data to use instead of fetching via the hook.\n * When provided, the component uses these values directly without refetching.\n */\n userInfo?: UserInfo | null;\n teams?: TeamInfo[];\n keys?: VirtualKey[];\n}\n\n/** One-word level names, and the note shown when the level has no cap. */\nconst LEVEL: Record<BudgetGauge['kind'], { name: string; none: string }> = {\n key: { name: 'Key', none: 'No cap (unlimited)' },\n user: { name: 'User', none: 'No personal budget' },\n team: { name: 'Team', none: 'No team budget' },\n};\n\nconst CTA_LABELS: Record<BudgetCtaKind, string> = {\n 'new-key': 'Generate New Key',\n module: 'Open LiteLLM',\n 'all-limits': 'All limits',\n};\n\n/** Compact USD for the tight budget caption \u2014 drops trailing cents. */\nfunction fmtUsdShort(n: number): string {\n const v = n ?? 0;\n if (v >= 100 && Number.isInteger(v)) return `$${v}`;\n return fmtUsd(v);\n}\n\n/** Budget caption: \"$213.39 / $240\", or a note when dollars are redacted. */\nfunction spendCaption(limit: BudgetLimit): string {\n if (limit.hidden) return 'hidden by admin';\n return `${fmtUsdShort(limit.spend)} / ${fmtUsdShort(limit.budget)}`;\n}\n\n/** Reset-window line under the amount: \"resets every 30 days\" / \"never resets\". */\nfunction resetLabel(limit: BudgetLimit): string {\n const window = fmtBudgetDuration(limit.budgetDuration);\n return window ? `resets ${window}` : 'never resets';\n}\n\n/** Uppercase micro-label used for levels, KPIs and the chart caption. */\nconst Tag: FC<{ children: ReactNode; tone?: Tone; title?: string }> = ({ children, tone, title }) => (\n <Typography\n title={title}\n sx={theme => ({\n fontSize: 10.5,\n fontWeight: 700,\n letterSpacing: '0.08em',\n textTransform: 'uppercase',\n lineHeight: 1.3,\n color: tone ? toneColor(theme, tone) : theme.palette.text.secondary,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n })}\n >\n {children}\n </Typography>\n);\n\n/**\n * One inline KPI: uppercase label over a tabular value with a quiet hint\n * underneath. Fixed three-line shape, so two of them sit side by side\n * without their baselines drifting apart.\n */\nconst InlineStat: FC<{\n label: string;\n value: string;\n hint?: string;\n tone?: Tone;\n title?: string;\n}> = ({ label, value, hint, tone = 'accent', title }) => (\n <Box sx={{ minWidth: 0, flex: 1 }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 0.625, minWidth: 0 }}>\n <Box\n sx={theme => ({\n width: 6,\n height: 6,\n borderRadius: '50%',\n bgcolor: toneColor(theme, tone),\n flexShrink: 0,\n })}\n />\n <Tag>{label}</Tag>\n </Box>\n <Typography\n title={title}\n sx={{\n fontSize: 19,\n fontWeight: 700,\n lineHeight: 1.15,\n mt: 0.25,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {value}\n </Typography>\n {/* Fixed height so rows of stats stay aligned even with an empty hint. */}\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n mt: 0.25,\n fontSize: 10.5,\n minHeight: 14,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {hint ?? ''}\n </Typography>\n </Box>\n);\n\n/**\n * One enforcement level as a single row: ring on the left, level tag +\n * limit name + a short note (over cap, \"+N more\", key id) in the flexible\n * middle, spend-vs-cap dollars over the reset window right-aligned in a\n * fixed track.\n */\nconst LevelRow: FC<{ gauge: BudgetGauge; size: number; keysHref?: string }> = ({\n gauge,\n size,\n keysHref,\n}) => {\n const { name, none } = LEVEL[gauge.kind];\n const limit = gauge.limit;\n const tone = limit ? budgetTone(limit.pct) : 'neutral';\n const extra = gauge.kind === 'key' ? Math.max(0, gauge.count - 1) : 0;\n const overCap = Boolean(limit && limit.pct > 100);\n\n /**\n * Third line of the middle track. The over-cap flag earns the slot first\n * (the reset window below already lives in the right track, so repeating it\n * here would print the same caption twice), then the \"+N more\" link, then\n * the identifying detail \u2014 key id, email, team slug.\n */\n const subNote = (): ReactNode => {\n if (overCap) return 'Over cap';\n if (extra > 0 && keysHref) {\n return (\n <Typography\n component={Link}\n to={keysHref}\n variant=\"caption\"\n sx={{\n fontSize: 10.5,\n color: 'primary.main',\n textDecoration: 'none',\n '&:hover': { textDecoration: 'underline' },\n }}\n >\n +{extra} more\n </Typography>\n );\n }\n return limit?.sublabel ?? null;\n };\n\n const gaugeAriaLabel = limit\n ? `${name} budget used: ${Math.round(limit.pct)}%`\n : `${name} \u2014 no cap`;\n\n return (\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: 'auto minmax(0, 1fr) auto',\n alignItems: 'center',\n gap: 1.25,\n py: 0.75,\n minWidth: 0,\n }}\n >\n <Gauge\n value={limit?.pct ?? 0}\n tone={tone}\n size={size}\n label={limit ? `${Math.round(limit.pct)}%` : '\u2014'}\n ariaLabel={gaugeAriaLabel}\n />\n\n <Box sx={{ minWidth: 0 }}>\n {/* The default accent tone would colour every healthy row; only a\n warning or an over-cap limit earns a coloured level tag. */}\n <Tag tone={tone === 'warning' || tone === 'danger' ? tone : undefined}>{name}</Tag>\n {limit ? (\n <>\n <Typography\n variant=\"caption\"\n title={limit.sublabel ? `${limit.label} \u00B7 ${limit.sublabel}` : limit.label}\n sx={{\n display: 'block',\n fontSize: 11.5,\n fontWeight: 600,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {limit.label}\n </Typography>\n <Typography\n variant=\"caption\"\n color={overCap ? 'error' : 'text.secondary'}\n sx={{\n display: 'block',\n fontSize: 10.5,\n fontWeight: overCap ? 700 : undefined,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {subNote()}\n </Typography>\n </>\n ) : (\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n fontSize: 10.5,\n lineHeight: 1.35,\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {none}\n </Typography>\n )}\n </Box>\n\n <Box sx={{ minWidth: 0, textAlign: 'right' }}>\n <Typography\n title={limit ? `${fmtUsd(limit.spend)} of ${fmtUsd(limit.budget)}` : undefined}\n sx={{\n display: 'block',\n fontSize: 12.5,\n fontWeight: 600,\n lineHeight: 1.35,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n color: limit ? undefined : 'text.secondary',\n }}\n >\n {amountCaption(limit)}\n </Typography>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{\n display: 'block',\n fontSize: 10.5,\n lineHeight: 1.35,\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n }}\n >\n {amountNote(limit)}\n </Typography>\n </Box>\n </Box>\n );\n};\n\n/** Right-track amount: \"$213 / $240\", or just the percentage when hidden. */\nfunction amountCaption(limit?: BudgetLimit): string {\n if (!limit) return '';\n return limit.hidden ? `${Math.round(limit.pct)}%` : spendCaption(limit);\n}\n\n/** Second right-track line: the reset window, or why dollars are missing. */\nfunction amountNote(limit?: BudgetLimit): string {\n if (!limit) return '';\n return limit.hidden ? 'hidden by admin' : resetLabel(limit);\n}\n\ninterface DailySpend {\n date: string;\n spend: number;\n}\n\n/**\n * Full-width strip below the rows: a sparkline of daily spend (MTD) with\n * the month's total on the same caption line as the range, so the number,\n * the window and the chart read as one unit.\n */\nconst SpendStrip: FC<{\n data: DailySpend[];\n mtdSpend: number;\n loading: boolean;\n height: number;\n usageUnavailable?: boolean;\n maxBudget?: number;\n}> = ({ data, mtdSpend, loading, height, usageUnavailable = false, maxBudget }) => {\n const renderPlot = () => {\n if (loading) {\n return <Skeleton variant=\"rectangular\" width=\"100%\" height=\"100%\" />;\n }\n if (data.length === 0) {\n return (\n <Box\n display=\"flex\"\n justifyContent=\"center\"\n alignItems=\"center\"\n height=\"100%\"\n sx={theme => ({ color: theme.palette.text.secondary, fontSize: 18 })}\n >\n \u2014\n </Box>\n );\n }\n return (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <AreaChart data={data} margin={{ top: 4, right: 0, bottom: 0, left: 0 }}>\n <XAxis dataKey=\"date\" hide />\n <Tooltip content={<ChartTooltip valueFormatter={fmtUsd} />} />\n {maxBudget !== undefined && (\n <ReferenceLine\n y={maxBudget}\n stroke={SERIES.budget}\n strokeDasharray=\"4 4\"\n strokeWidth={1}\n />\n )}\n <Area\n type=\"monotone\"\n dataKey=\"spend\"\n name=\"Spend\"\n stroke={SERIES.spend}\n strokeWidth={1.5}\n fill={SERIES.spend}\n fillOpacity={0.25}\n dot={false}\n isAnimationActive={false}\n />\n </AreaChart>\n </ResponsiveContainer>\n );\n };\n\n const caption = (() => {\n if (loading) return '\u2026';\n if (usageUnavailable) return USAGE_UNAVAILABLE_MSG;\n if (data.length === 0) return 'No spend this month';\n return mtdCaption();\n })();\n\n return (\n <Box role=\"img\" aria-label={sparklineAriaLabel(data)} sx={{ minWidth: 0 }}>\n <Box sx={{ height, width: '100%' }}>{renderPlot()}</Box>\n <Box\n sx={{\n display: 'flex',\n alignItems: 'baseline',\n justifyContent: 'space-between',\n gap: 1,\n mt: 0.5,\n minWidth: 0,\n }}\n >\n <Box sx={{ display: 'flex', alignItems: 'baseline', gap: 0.75, minWidth: 0 }}>\n <Tag>Spent (mtd)</Tag>\n <Typography\n variant=\"caption\"\n color=\"text.secondary\"\n sx={{ fontSize: 10.5, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}\n >\n {caption}\n </Typography>\n </Box>\n <Typography\n title={loading || usageUnavailable ? undefined : `${fmtUsd(mtdSpend)} spent month to date`}\n sx={{\n fontSize: 12.5,\n fontWeight: 700,\n fontVariantNumeric: 'tabular-nums',\n whiteSpace: 'nowrap',\n }}\n >\n {loading || usageUnavailable ? '\u2014' : fmtUsd(mtdSpend)}\n </Typography>\n </Box>\n </Box>\n );\n};\n\n/** KPI value while loading / unavailable: '\u2026' \u2192 '\u2014' \u2192 the figure. */\nfunction statValue(loading: boolean, unavailable: boolean, value: string): string {\n if (loading) return '\u2026';\n if (unavailable) return '\u2014';\n return value;\n}\n\n/** KPI hint under `statValue`: nothing while loading, the reason when unavailable. */\nfunction statHint(loading: boolean, unavailable: boolean, hint?: string): string | undefined {\n if (loading) return undefined;\n if (unavailable) return USAGE_UNAVAILABLE_MSG;\n return hint;\n}\n\nexport const LiteLLMBudgetGauges: FC<LiteLLMBudgetGaugesProps> = ({\n title = 'Budget',\n bare = false,\n size = 56,\n keysHref,\n moduleHref: propModuleHref,\n onCreateKey,\n ctas,\n maxExpandedKeys = 8,\n expanded,\n defaultExpanded = false,\n onExpandedChange,\n action,\n userInfo: propUserInfo,\n teams: propTeams,\n keys: propKeys,\n}) => {\n const api = useApi(liteLlmApiRef);\n const theme = useTheme();\n const isSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));\n const gaugeSize = isSmallScreen ? Math.min(48, size) : size;\n const expandedRegionId = useId();\n const moduleRouteRef = useRouteRef(rootRouteRef);\n const moduleHref = propModuleHref ?? moduleRouteRef?.();\n const { userInfo: hookUserInfo, teams: hookTeams, keys: hookKeys, loading: profileLoading, error: profileError } = useLiteLLMProfile();\n const [usageLoading, setUsageLoading] = useState(true);\n const [usageError, setUsageError] = useState<string | null>(null);\n const [dailySpend, setDailySpend] = useState<DailySpend[]>([]);\n const [mtdSpend, setMtdSpend] = useState(0);\n\n // Use provided props if available, otherwise use hook data\n const user = propUserInfo !== undefined ? propUserInfo : hookUserInfo;\n const teams = propTeams !== undefined ? propTeams : hookTeams;\n const keys = propKeys !== undefined ? propKeys : hookKeys;\n\n // Combine loading states: if props are provided, only usage matters; otherwise both profile and usage\n const loading = propUserInfo === undefined ? profileLoading : usageLoading;\n const error = propUserInfo === undefined ? profileError : usageError;\n\n const isControlled = expanded !== undefined;\n const [uncontrolledExpanded, setUncontrolledExpanded] = useState(defaultExpanded);\n const isExpanded = isControlled ? expanded! : uncontrolledExpanded;\n\n const toggleExpanded = useCallback(() => {\n const next = !isExpanded;\n if (!isControlled) setUncontrolledExpanded(next);\n onExpandedChange?.(next);\n }, [isControlled, isExpanded, onExpandedChange]);\n\n const keysTabHref = keysHref ?? (moduleHref ? `${moduleHref}?tab=keys` : undefined);\n\n useEffect(() => {\n let cancelled = false;\n setUsageLoading(true);\n setUsageError(null);\n // The usage chart is frozen to month-to-date \u2014 no period selector.\n const { startDate, endDate } = monthToDateRange();\n api.getUsage(startDate, endDate)\n .then((usageResult) => {\n if (cancelled) return;\n // Usage degrades independently: a failed usage fetch leaves the\n // gauges untouched and the chart strip renders its empty state.\n const daily = usageResult.daily_usage ?? [];\n setDailySpend(\n daily.map(d => ({\n date: d.date,\n spend: d.spend ?? 0,\n })),\n );\n setMtdSpend(usageResult.total_spend ?? 0);\n setUsageLoading(false);\n })\n .catch((err) => {\n if (!cancelled) {\n setUsageError(err?.message ?? 'Failed to load usage data');\n setDailySpend([]);\n setMtdSpend(0);\n setUsageLoading(false);\n }\n });\n return () => {\n cancelled = true;\n };\n }, [api]);\n\n // Keep every budgeted key so the nearest-per-level gauge is accurate even\n // beyond the full widget's display cap.\n const summary = useMemo(\n () => buildBudgetSummary(user, teams, keys, keys.length),\n [user, teams, keys],\n );\n const gauges = useMemo(() => buildBudgetGauges(summary), [summary]);\n const headline = useMemo(() => budgetHeadline(summary), [summary]);\n\n // Expanded view: every concrete limit, but cap the key entries so a user\n // with dozens of keys doesn't get an endless list.\n const expandedSummary = useMemo(\n () => buildBudgetSummary(user, teams, keys, maxExpandedKeys),\n [user, teams, keys, maxExpandedKeys],\n );\n const expandedLimits = useMemo(\n () => allBudgetLimits(expandedSummary),\n [expandedSummary],\n );\n\n // Determine the overall widget state\n const viewState = useMemo(\n () => widgetViewState({\n loading,\n error: profileError,\n userInfo: user,\n usageError,\n hasKeys: (keys?.length ?? 0) > 0,\n }),\n [loading, profileError, user, usageError, keys],\n );\n\n // Today's spend (and yesterday's, for the hint) come from the same\n // month-to-date series the chart already fetched \u2014 no extra request.\n const today = new Date();\n const todaySpend = spendOnDay(dailySpend, today);\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n // No yesterday point when the month started today \u2014 say nothing rather\n // than imply the user spent nothing.\n const yesterdaySpend = dailySpend.some(d => d.date === toLocalDay(yesterday))\n ? spendOnDay(dailySpend, yesterday)\n : null;\n const todayHint = yesterdaySpend === null ? undefined : `vs ${fmtUsd(yesterdaySpend)} yesterday`;\n\n const summaryText =\n headline.count === 0\n ? 'no limits apply'\n : `${headline.count} limit${headline.count === 1 ? '' : 's'}`;\n\n const resolvedCtas = useMemo<(BudgetCtaSpec & { kind: BudgetCtaKind })[]>(() => {\n return resolveCtas({\n ctas,\n hasKeys: (keys?.length ?? 0) > 0,\n viewState,\n limitCount: headline.count,\n });\n }, [ctas, keys?.length, viewState, headline.count]);\n\n const renderCta = (cta: BudgetCtaSpec & { kind: BudgetCtaKind }, index: number) => {\n const label = cta.label ?? CTA_LABELS[cta.kind];\n const key = `${cta.kind}-${index}`;\n switch (cta.kind) {\n case 'new-key':\n // The shared plugin-page CTA \u2014 identical copy, icon and styling\n // everywhere. Deep-links to the module's generate-key dialog unless\n // the host takes over with `onCreateKey`.\n if (!onCreateKey && !moduleHref) return null;\n return onCreateKey ? (\n <GenerateKeyButton key={key} size=\"small\" label={label} onClick={onCreateKey} />\n ) : (\n <GenerateKeyButton key={key} size=\"small\" label={label} to={`${moduleHref}?generate=1`} />\n );\n case 'module':\n // Hide if route is not mounted\n if (!moduleHref) return null;\n return (\n <Button key={key} size=\"small\" variant=\"text\" component={Link} to={moduleHref}>\n {label}\n </Button>\n );\n case 'all-limits':\n return (\n <Button\n key={key}\n size=\"small\"\n variant=\"text\"\n onClick={toggleExpanded}\n aria-expanded={isExpanded}\n aria-controls={expandedRegionId}\n endIcon={\n <ExpandMore\n sx={muiTheme => ({\n transform: isExpanded ? 'rotate(180deg)' : 'none',\n transition: muiTheme.transitions.create('transform'),\n })}\n />\n }\n >\n {label}\n </Button>\n );\n /* istanbul ignore next \u2014 exhaustiveness */\n default:\n return null;\n }\n };\n\n const hasFooter = resolvedCtas.length > 0 || !!action;\n\n const Wrapper: ElementType = bare ? Box : Paper;\n\n return (\n <Wrapper sx={bare ? { height: '100%' } : { p: 2, height: '100%' }}>\n <Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 1.5, minWidth: 0, justifyContent: bare ? 'flex-end' : undefined }}>\n {!bare && (\n <Typography variant=\"h6\" lineHeight={1.2} sx={{ minWidth: 0, flex: 1 }}>\n {title}\n </Typography>\n )}\n {!loading && !error && (\n <StatusPill\n label={summaryText}\n tone={budgetTone(headline.closest?.pct ?? 0)}\n dot={headline.count > 0}\n />\n )}\n </Box>\n\n {viewState.kind === 'loading' && (\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.25, minHeight: size }}>\n {[0, 1, 2].map(i => (\n <Box key={i} sx={{ display: 'flex', alignItems: 'center', gap: 1.25 }}>\n <Skeleton variant=\"circular\" width={size} height={size} />\n <Box sx={{ flex: 1 }}>\n <Skeleton variant=\"text\" width=\"70%\" height={12} sx={{ mb: 0.25 }} />\n <Skeleton variant=\"text\" width=\"45%\" height={11} />\n </Box>\n <Skeleton variant=\"text\" width={64} height={12} />\n </Box>\n ))}\n </Box>\n )}\n\n {viewState.kind === 'error' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {viewState.message}\n </Typography>\n )}\n\n {viewState.kind === 'unprovisioned' && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {UNPROVISIONED_MSG}\n </Typography>\n )}\n\n {viewState.kind === 'ready' && (\n <>\n {/* Spend KPIs: today first, month-to-date second. */}\n <Box\n sx={{\n display: 'flex',\n alignItems: 'stretch',\n gap: 2,\n mb: 1.25,\n minWidth: 0,\n }}\n >\n <InlineStat\n label=\"Today spent\"\n tone=\"accent\"\n value={statValue(usageLoading, viewState.usageUnavailable, fmtUsd(todaySpend))}\n hint={statHint(usageLoading, viewState.usageUnavailable, todayHint)}\n title={usageLoading || viewState.usageUnavailable ? undefined : 'Spend since local midnight'}\n />\n <Box sx={{ width: '1px', bgcolor: 'divider', flexShrink: 0 }} />\n <InlineStat\n label=\"Month to date\"\n value={statValue(usageLoading, viewState.usageUnavailable, fmtUsd(mtdSpend))}\n hint={statHint(usageLoading, viewState.usageUnavailable, mtdCaption())}\n title={usageLoading || viewState.usageUnavailable ? undefined : 'Spend from the 1st of this month'}\n />\n </Box>\n\n {/* One row per enforcement level, hairline-separated. */}\n <Box sx={{ borderTop: '1px solid', borderColor: 'divider' }}>\n {gauges.map((gauge, i) => (\n <Box\n key={gauge.kind}\n sx={i === 0 ? undefined : { borderTop: '1px solid', borderColor: 'divider' }}\n >\n <LevelRow gauge={gauge} size={gaugeSize} keysHref={keysTabHref} />\n </Box>\n ))}\n </Box>\n\n <Box sx={{ mt: 1.25 }}>\n <SpendStrip\n data={dailySpend}\n mtdSpend={mtdSpend}\n loading={usageLoading}\n height={gaugeSize}\n usageUnavailable={viewState.usageUnavailable}\n maxBudget={user?.max_budget ?? undefined}\n />\n </Box>\n\n <Collapse in={isExpanded} unmountOnExit>\n <Box\n id={expandedRegionId}\n sx={{\n mt: 1.5,\n // Bound the expanded list so a user with many limits still\n // keeps the card compact and the toggle within reach.\n maxHeight: 300,\n overflowY: 'auto',\n }}\n >\n <LimitListPanel>\n <BudgetLimitList\n limits={expandedLimits}\n hiddenKeyCount={expandedSummary.hiddenBudgetedKeys}\n keysHref={keysTabHref}\n />\n </LimitListPanel>\n </Box>\n </Collapse>\n </>\n )}\n\n {hasFooter && (\n <Box\n sx={muiTheme => ({\n mt: 2,\n pt: 2,\n borderTop: `1px solid ${muiTheme.palette.divider}`,\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n flexWrap: 'wrap',\n })}\n >\n {resolvedCtas.map(renderCta)}\n {action}\n </Box>\n )}\n </Wrapper>\n );\n};\n", "/** Preset action-bar buttons. `label` overrides the default copy. */\nexport type BudgetCtaKind = 'new-key' | 'module' | 'all-limits';\nexport interface BudgetCtaSpec {\n kind: BudgetCtaKind;\n /** Override the default label. */\n label?: string;\n}\n/** Either a bare kind (`'module'`) or a spec object (`{ kind: 'module' }`). */\nexport type BudgetCta = BudgetCtaKind | BudgetCtaSpec;\n\nexport const DEFAULT_CTAS: BudgetCtaKind[] = ['module', 'all-limits'];\n\n/**\n * Resolves which action-bar buttons to render.\n *\n * - `new-key` is shown when explicitly listed, or automatically (first) when\n * the user has no keys yet \u2014 but never while loading or when the profile\n * errored / the user isn't provisioned (a generate flow would fail).\n * - `all-limits` is dropped when there are no limits to expand.\n */\nexport function resolveCtas(spec: {\n ctas?: BudgetCta[];\n hasKeys: boolean;\n viewState: { kind: string };\n limitCount: number;\n}): Array<BudgetCtaSpec & { kind: BudgetCtaKind }> {\n const list = (spec.ctas ?? DEFAULT_CTAS).map(cta =>\n typeof cta === 'string' ? { kind: cta } : cta,\n );\n const canGenerate = spec.viewState.kind === 'ready';\n const out = list.filter(cta => {\n if (cta.kind === 'new-key') return canGenerate;\n if (cta.kind === 'all-limits') return spec.limitCount > 0;\n return true;\n });\n if (\n spec.ctas === undefined &&\n !spec.hasKeys &&\n canGenerate &&\n !out.some(c => c.kind === 'new-key')\n ) {\n out.unshift({ kind: 'new-key' });\n }\n return out;\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAiBa,aAkBA,cAwFA;AA3Hb;AAAA;AAAA;AAiBO,IAAM,cAAqB;AAAA,MAChC,KAAK,MAAM,KAAK,IAAI;AAAA,IACtB;AAgBO,IAAM,eAAN,MAAmB;AAAA,MAMxB,YAAY,QAAgB,KAAQ,QAAe,aAAa;AALhE,aAAQ,QAAQ,oBAAI,QAAgE;AACpF,aAAQ,WAAW,oBAAI,QAA4D;AAKjF,aAAK,QAAQ;AACb,aAAK,QAAQ;AAAA,MACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWA,MAAM,QACJ,KACA,KACA,SACY;AACZ,cAAM,MAAM,KAAK,MAAM,IAAI;AAG3B,cAAM,SAAS,KAAK,MAAM,IAAI,GAAG,IAAI,GAAG;AACxC,YAAI,UAAU,MAAM,OAAO,YAAY,KAAK,OAAO;AACjD,iBAAO,OAAO;AAAA,QAChB;AAGA,cAAM,WAAW,KAAK,SAAS,IAAI,GAAG,IAAI,GAAG;AAC7C,YAAI,YAAY,MAAM,SAAS,cAAc,KAAK,OAAO;AACvD,iBAAO,SAAS;AAAA,QAClB;AAIA,cAAM,UAAU,QAAQ,EACrB,KAAK,YAAU;AAEd,cAAI,CAAC,KAAK,MAAM,IAAI,GAAG,EAAG,MAAK,MAAM,IAAI,KAAK,CAAC,CAAC;AAChD,eAAK,MAAM,IAAI,GAAG,EAAG,GAAG,IAAI,EAAE,QAAQ,WAAW,KAAK,MAAM,IAAI,EAAE;AAClE,iBAAO;AAAA,QACT,CAAC,EACA,MAAM,SAAO;AAEZ,gBAAM,kBAAkB,KAAK,SAAS,IAAI,GAAG;AAC7C,cAAI,iBAAiB;AACnB,mBAAO,gBAAgB,GAAG;AAAA,UAC5B;AACA,gBAAM;AAAA,QACR,CAAC;AAGH,YAAI,CAAC,KAAK,SAAS,IAAI,GAAG,EAAG,MAAK,SAAS,IAAI,KAAK,CAAC,CAAC;AACtD,aAAK,SAAS,IAAI,GAAG,EAAG,GAAG,IAAI,EAAE,SAAS,aAAa,KAAK,MAAM,IAAI,EAAE;AAExE,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,WAAW,KAAgC;AACzC,aAAK,MAAM,OAAO,GAAG;AACrB,aAAK,SAAS,OAAO,GAAG;AAAA,MAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,kBAAkB,KAAgC;AAChD,cAAM,eAAe,CAAC,MAAc,MAAM,aAAa,EAAE,WAAW,UAAU;AAC9E,mBAAW,SAAS,CAAC,KAAK,MAAM,IAAI,GAAG,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,GAAG;AACjE,cAAI,CAAC,MAAO;AACZ,qBAAW,KAAK,OAAO,KAAK,KAAK,GAAG;AAClC,gBAAI,aAAa,CAAC,EAAG,QAAO,MAAM,CAAC;AAAA,UACrC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGO,IAAM,uBAAuB,IAAI,aAAa;AAAA;AAAA;;;ACxD9C,SAAS,aAAa,WAAyC;AACpE,MAAI,CAAC,UAAW,QAAO;AACvB,QAAM,OAAO,IAAI,KAAK,SAAS,EAAE,QAAQ,IAAI,KAAK,IAAI;AACtD,QAAM,OAAO,QAAQ,MAAO,KAAK,KAAK;AACtC,MAAI,OAAO,EAAG,QAAO;AACrB,MAAI,OAAO,EAAG,QAAO;AACrB,SAAO;AACT;AA1EA,gCAqBa,UAwCA,eAeA;AA5Eb;AAAA;AAAA;AAAA,iCAA+D;AAmB/D;AAEO,IAAM,WAAN,cAAuB,MAAM;AAAA,MAGlC,YAAY,SAAiB,QAAgB,MAAe;AAC1D,cAAM,OAAO;AACb,aAAK,SAAS;AACd,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAgCO,IAAM,oBAAgB,yCAAkC;AAAA,MAC7D,IAAI;AAAA,IACN,CAAC;AAaM,IAAM,aAAN,MAAgD;AAAA;AAAA;AAAA;AAAA;AAAA,MAQrD,YAAY,UAAoB,OAA8B,gBAAgB;AAC5E,aAAK,WAAW;AAChB,aAAK,OAAO;AAAA,MACd;AAAA,MAEA,MAAc,WAA4B;AACxC,eAAO,OAAO,KAAK,SAAS,WACxB,KAAK,OACL,KAAK,KAAK,WAAW,SAAS;AAAA,MACpC;AAAA,MAEA,MAAc,aAAa,UAAmC;AAC5D,YAAI,CAAC,SAAS,IAAI;AAChB,cAAI;AACJ,cAAI;AAAE,mBAAO,MAAM,SAAS,KAAK;AAAA,UAAG,QAAQ;AAAE,mBAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AAAA,UAAG;AAC5F,gBAAM,YACJ,OAAO,SAAS,YAAY,QAAQ,OAAQ,KAAa,UAAU,WAC9D,KAAa,QACd;AAGN,gBAAM,UACJ,OAAO,SAAS,YAAY,QAAQ,OAAQ,KAAa,YAAY,WAChE,KAAa,UACd;AACN,cAAI,UAAU,GAAG,SAAS,MAAM,IAAI,SAAS,UAAU;AACvD,cAAI,WAAW;AACb,sBAAU,UAAU,GAAG,SAAS,KAAK,OAAO,KAAK;AAAA,UACnD;AACA,gBAAM,IAAI,SAAS,SAAS,SAAS,QAAQ,IAAI;AAAA,QACnD;AAAA,MACF;AAAA,MAEA,MAAc,IAAO,MAAc,QAA6C;AAC9E,cAAM,MAAM,IAAI,IAAI,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,IAAI,IAAI,OAAO,SAAS,MAAM;AAC7E,YAAI,QAAQ;AACV,iBAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM,IAAI,aAAa,OAAO,KAAK,KAAK,CAAC;AAAA,QACtF;AACA,cAAM,WAAW,MAAM,KAAK,SAAS,MAAM,IAAI,SAAS,CAAC;AACzD,cAAM,KAAK,aAAa,QAAQ;AAChC,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA,MAEA,MAAc,KAAQ,MAAc,MAA2B;AAC7D,cAAM,WAAW,MAAM,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,IAAI,IAAI;AAAA,UAC5E,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,QAC3B,CAAC;AACD,cAAM,KAAK,aAAa,QAAQ;AAEhC,6BAAqB,kBAAkB,IAAI;AAC3C,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA,MAEA,MAAc,IAAO,MAA0B;AAC7C,cAAM,WAAW,MAAM,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,IAAI,IAAI;AAAA,UAC5E,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAChD,CAAC;AACD,cAAM,KAAK,aAAa,QAAQ;AAEhC,6BAAqB,kBAAkB,IAAI;AAC3C,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA,MAEA,MAAc,MAAS,MAAc,MAA2B;AAC9D,cAAM,WAAW,MAAM,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,IAAI,IAAI;AAAA,UAC5E,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,QAC3B,CAAC;AACD,cAAM,KAAK,aAAa,QAAQ;AAEhC,6BAAqB,kBAAkB,IAAI;AAC3C,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA,MAEA,MAAc,IAAO,MAAc,MAA2B;AAC5D,cAAM,WAAW,MAAM,KAAK,SAAS,MAAM,GAAG,MAAM,KAAK,SAAS,CAAC,GAAG,IAAI,IAAI;AAAA,UAC5E,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,QAC3B,CAAC;AACD,cAAM,KAAK,aAAa,QAAQ;AAEhC,6BAAqB,kBAAkB,IAAI;AAC3C,eAAO,SAAS,KAAK;AAAA,MACvB;AAAA;AAAA;AAAA,MAIA,MAAM,cAAiC;AACrC,eAAO,KAAK,IAAc,YAAY;AAAA,MACxC;AAAA,MAEA,MAAM,WAAkC;AACtC,eAAO,KAAK,IAAkB,OAAO;AAAA,MACvC;AAAA,MAEA,MAAM,YAAY,SAA2D;AAC3E,eAAO,KAAK,KAA0B,kBAAkB,OAAO;AAAA,MACjE;AAAA,MAEA,MAAM,UAAU,OAAe,SAAgD;AAC7E,eAAO,KAAK,KAAiB,SAAS,mBAAmB,KAAK,CAAC,WAAW,OAAO;AAAA,MACnF;AAAA,MAEA,MAAM,UAAU,OAA8C;AAC5D,eAAO,KAAK,IAA0B,SAAS,mBAAmB,KAAK,CAAC,EAAE;AAAA,MAC5E;AAAA,MAEA,MAAM,SAAS,OAA8B;AAC3C,cAAM,KAAK,KAAK,SAAS,mBAAmB,KAAK,CAAC,UAAU,CAAC,CAAC;AAAA,MAChE;AAAA,MAEA,MAAM,WAAW,OAA8B;AAC7C,cAAM,KAAK,KAAK,SAAS,mBAAmB,KAAK,CAAC,YAAY,CAAC,CAAC;AAAA,MAClE;AAAA,MAEA,MAAM,cAAc,OAA8B;AAChD,cAAM,KAAK,KAAK,SAAS,mBAAmB,KAAK,CAAC,gBAAgB,CAAC,CAAC;AAAA,MACtE;AAAA,MAEA,MAAM,mBAA+G;AACnH,eAAO,KAAK;AAAA,UACV;AAAA,UACA,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MAEA,MAAM,aAAa,QAAsD;AACvE,cAAM,YAAoC,CAAC;AAC3C,YAAI,OAAO,SAAS,OAAW,WAAU,OAAO,OAAO,OAAO,IAAI;AAClE,YAAI,OAAO,cAAc,OAAW,WAAU,YAAY,OAAO,OAAO,SAAS;AACjF,YAAI,OAAO,WAAY,WAAU,aAAa,OAAO;AACrD,YAAI,OAAO,SAAU,WAAU,WAAW,OAAO;AACjD,YAAI,OAAO,OAAQ,WAAU,SAAS,OAAO;AAC7C,YAAI,OAAO,WAAY,WAAU,aAAa,OAAO;AACrD,YAAI,OAAO,WAAY,WAAU,aAAa,OAAO;AACrD,eAAO,KAAK,IAAwB,UAAU,SAAS;AAAA,MACzD;AAAA,MAEA,MAAM,aAAmC;AACvC,eAAO,KAAK,IAAiB,SAAS;AAAA,MACxC;AAAA,MAEA,MAAM,WAAgC;AACpC,eAAO,KAAK,IAAgB,QAAQ;AAAA,MACtC;AAAA;AAAA;AAAA,MAIA,MAAM,kBAAuC;AAC3C,eAAO,KAAK,IAAgB,gBAAgB;AAAA,MAC9C;AAAA,MAEA,MAAM,cACJ,QACA,MACmB;AACnB,eAAO,KAAK;AAAA,UACV,UAAU,mBAAmB,MAAM,CAAC;AAAA,UACpC;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,iBACJ,QACA,eACmB;AACnB,eAAO,KAAK;AAAA,UACV,UAAU,mBAAmB,MAAM,CAAC,0BAA0B;AAAA,YAC5D;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA,MAIA,MAAM,kBAA8C;AAClD,eAAO,KAAK,IAAuB,gBAAgB;AAAA,MACrD;AAAA,MAEA,MAAM,sBACJ,QACA,cACmB;AACnB,eAAO,KAAK;AAAA,UACV,UAAU,mBAAmB,MAAM,CAAC;AAAA,UACpC,EAAE,eAAe,aAAa;AAAA,QAChC;AAAA,MACF;AAAA,MAEA,MAAM,gBAA0C;AAC9C,eAAO,KAAK,IAAqB,cAAc;AAAA,MACjD;AAAA,MAEA,MAAM,kBACJ,QACA,YACmB;AACnB,eAAO,KAAK;AAAA,UACV,UAAU,mBAAmB,MAAM,CAAC;AAAA,UACpC,EAAE,aAAa,WAAW;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,MAAM,SAAS,WAAmB,SAAwC;AACxE,eAAO,KAAK,IAAkB,UAAU,EAAE,YAAY,WAAW,UAAU,QAAQ,CAAC;AAAA,MACtF;AAAA,MAEA,MAAM,aAAa,QAAgB,WAAmB,SAAwC;AAC5F,eAAO,KAAK,IAAkB,UAAU,mBAAmB,MAAM,CAAC,UAAU;AAAA,UAC1E,YAAY;AAAA,UACZ,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,YAAoC;AACxC,eAAO,KAAK,IAAmB,SAAS;AAAA,MAC1C;AAAA,MAEA,MAAM,WAAW,SAAyD;AACxE,eAAO,KAAK,KAAyB,UAAU,OAAO;AAAA,MACxD;AAAA,MAEA,MAAM,WAAW,QAAgB,SAA+C;AAC9E,eAAO,KAAK,MAAgB,UAAU,mBAAmB,MAAM,CAAC,IAAI,OAAO;AAAA,MAC7E;AAAA,IACF;AAAA;AAAA;;;AC1TA,IAAAA,6BAEa;AAFb;AAAA;AAAA;AAAA,IAAAA,8BAA+B;AAExB,IAAM,mBAAe,4CAAe;AAAA;AAAA;;;ACyDpC,SAAS,WAAW,MAAsB;AAC/C,MAAI,SAAS,QAAS,QAAO;AAC7B,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAK,MAAM,KAAK,KAAK,IAAI,KAAK,WAAW,CAAC,MAAO;AAClF,SAAO,aAAa,IAAI,aAAa,MAAM;AAC7C;AAGO,SAAS,gBAAgB;AAC9B,QAAM,YAAQ,wBAAS;AACvB,QAAM,WAAW,MAAM,QAAQ,KAAK;AACpC,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,YAAQ,qBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,MACrF,iBAAiB;AAAA,MACjB,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,MAAM,EAAE,UAAU,IAAI,MAAM,SAAS;AAAA,MACrC,UAAU;AAAA,MACV,UAAU,EAAE,YAAQ,qBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI,EAAE;AAAA,IAC9D;AAAA,IACA,QAAQ;AAAA,MACN,cAAc;AAAA,QACZ,UAAU;AAAA,QACV,OAAO;AAAA,QACP,YAAY;AAAA,MACd;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,QAAQ,EAAE,UAAM,qBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI,EAAE;AAAA,EAC1D;AACF;AAOO,SAAS,UAAU,OAAc,MAAoB;AAC1D,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAW,aAAO,MAAM,QAAQ,QAAQ;AAAA,IAC7C,KAAK;AAAW,aAAO,MAAM,QAAQ,QAAQ;AAAA,IAC7C,KAAK;AAAU,aAAO,MAAM,QAAQ,MAAM;AAAA,IAC1C,KAAK;AAAQ,aAAO,MAAM,QAAQ,KAAK;AAAA,IACvC,KAAK;AAAU,aAAO,MAAM,QAAQ,QAAQ;AAAA,IAC5C;AAAS,aAAO,MAAM,QAAQ,KAAK;AAAA,EACrC;AACF;AA5GA,mBAKM,QAGO,cAOA,YAUA,eAUA,cAYA,QASP;AAxDN;AAAA;AAAA;AAAA,oBAAgC;AAKhC,IAAM,SAAS,CAAC,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO,KAAK;AAG3F,IAAM,eAAe,CAAC,UAA0B;AACrD,YAAM,IAAI,2BAA2B,KAAK,SAAS,EAAE;AACrD,UAAI,CAAC,EAAG,QAAO;AACf,aAAO,GAAG,OAAO,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC,CAAC;AAAA,IACpD;AAGO,IAAM,aAAa,CAAC,MAAsB;AAC/C,YAAM,IAAI,KAAK;AACf,YAAM,MAAM,KAAK,IAAI,CAAC;AACtB,UAAI,OAAO,IAAK,QAAO,IAAI,IAAI,KAAK,QAAQ,OAAO,OAAO,IAAI,CAAC,CAAC;AAChE,UAAI,OAAO,IAAK,QAAO,IAAI,IAAI,KAAK,QAAQ,OAAO,MAAM,IAAI,CAAC,CAAC;AAC/D,UAAI,OAAO,IAAK,QAAO,IAAI,IAAI,KAAK,QAAQ,OAAO,MAAM,IAAI,CAAC,CAAC;AAC/D,aAAO,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,IAC7B;AAGO,IAAM,gBAAgB,CAAC,MAAsB;AAClD,YAAM,IAAI,KAAK;AACf,UAAI,KAAK,IAAI,CAAC,KAAK,IAAM,QAAO,IAAI,WAAW,CAAC,CAAC;AACjD,UAAI,KAAK,IAAI,CAAC,KAAK,GAAI,QAAO,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC9C,aAAO,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,IACzB;AAKO,IAAM,eAAe;AAAA,MAC1B;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,MACA;AAAA;AAAA,IACF;AAGO,IAAM,SAAS;AAAA,MACpB,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAEA,IAAM,cAAc;AAAA;AAAA;;;ACxDpB,IACA,YACA,cACA,mBA6CM,oBA1BO,cAmEA;AAzFb;AAAA;AAAA;AACA,iBAAgB;AAChB,mBAAkB;AAClB,wBAAuB;AACvB;AA4CM;AA1BC,IAAM,eAAsC,CAAC;AAAA,MAClD;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,CAAC,MAAc,EAAE,eAAe;AAAA,MACjD,iBAAiB;AAAA,MACjB,WAAW;AAAA,IACb,MAAM;AACJ,UAAI,CAAC,UAAU,CAAC,SAAS,OAAQ,QAAO;AACxC,YAAM,OAAO,QAAQ;AAAA,QACnB,OAAK,EAAE,UAAU,UAAa,EAAE,UAAU,SAAS,CAAC,YAAY,EAAE,UAAU;AAAA,MAC9E;AACA,UAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,aACE;AAAA,QAAC,aAAAC;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,UACX,IAAI;AAAA,YACF,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,cAAc;AAAA,YACd,QAAQ;AAAA,YACR,aAAa;AAAA,YACb,UAAU;AAAA,YACV,eAAe;AAAA,UACjB;AAAA,UAEA;AAAA;AAAA,cAAC,kBAAAC;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,IAAI,EAAE,SAAS,SAAS,YAAY,KAAK,IAAI,MAAM,eAAe,SAAS;AAAA,gBAE1E,iBAAO,UAAU,WAAW,eAAe,KAAK,IAAI;AAAA;AAAA,YACvD;AAAA,YACC,KAAK,IAAI,CAAC,KAAK,MACd;AAAA,cAAC,WAAAC;AAAA,cAAA;AAAA,gBAEC,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,IAAI,MAAM,IAAI,IAAI,IAAI;AAAA,gBAE3E;AAAA;AAAA,oBAAC,WAAAA;AAAA,oBAAA;AAAA,sBACC,IAAI;AAAA,wBACF,OAAO;AAAA,wBACP,QAAQ;AAAA,wBACR,cAAc;AAAA,wBACd,SAAS,IAAI;AAAA,wBACb,YAAY;AAAA,sBACd;AAAA;AAAA,kBACF;AAAA,kBACA;AAAA,oBAAC,kBAAAD;AAAA,oBAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,OAAM;AAAA,sBACN,IAAI,EAAE,MAAM,GAAG,IAAI,KAAK,UAAU,UAAU,cAAc,YAAY,YAAY,SAAS;AAAA,sBAE1F,cAAI;AAAA;AAAA,kBACP;AAAA,kBACA,4CAAC,kBAAAA,SAAA,EAAW,SAAQ,WAAU,IAAI,EAAE,YAAY,KAAK,oBAAoB,eAAe,GACrF,yBAAe,IAAI,KAAe,GACrC;AAAA;AAAA;AAAA,cArBK,GAAG,IAAI,WAAW,IAAI,QAAQ,CAAC;AAAA,YAsBtC,CACD;AAAA;AAAA;AAAA,MACH;AAAA,IAEJ;AAOO,IAAM,eAAuE,CAAC;AAAA,MACnF;AAAA,IACF,MACE;AAAA,MAAC,WAAAC;AAAA,MAAA;AAAA,QACC,IAAI;AAAA,UACF,SAAS;AAAA,UACT,UAAU;AAAA,UACV,KAAK;AAAA,UACL,WAAW;AAAA,UACX,QAAQ;AAAA,UACR,IAAI;AAAA,QACN;AAAA,QAEC,iBAAO,IAAI,OACV,6CAAC,WAAAA,SAAA,EAAiB,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,MAAM,UAAU,EAAE,GACpF;AAAA;AAAA,YAAC,WAAAA;AAAA,YAAA;AAAA,cACC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,cAAc,OAAO,SAAS,EAAE,OAAO,YAAY,EAAE;AAAA;AAAA,UAClF;AAAA,UACA;AAAA,YAAC,kBAAAD;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,OAAO,EAAE;AAAA,cACT,IAAI;AAAA,gBACF,UAAU;AAAA,gBACV,UAAU;AAAA,gBACV,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,YAAY;AAAA,cACd;AAAA,cAEC,YAAE;AAAA;AAAA,UACL;AAAA,aAjBQ,EAAE,IAkBZ,CACD;AAAA;AAAA,IACH;AAAA;AAAA;;;AC3HF,IACAE,aACAC,gBAiBEC,qBARW,YAuDA;AAlEb;AAAA;AAAA;AACA,IAAAF,cAAgB;AAChB,IAAAC,iBAAsB;AAEtB;AAeE,IAAAC,sBAAA;AARK,IAAM,aAOR,CAAC,EAAE,OAAO,OAAO,WAAW,MAAM,MAAM,OAAO,GAAG,MACrD;AAAA,MAAC,YAAAC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV;AAAA,QACA,IAAI;AAAA,UACF,WAAS;AACP,kBAAM,IAAI,UAAU,OAAO,IAAI;AAC/B,mBAAO;AAAA,cACL,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,QAAQ;AAAA,cACR,IAAI;AAAA,cACJ,cAAc;AAAA,cACd,QAAQ;AAAA,cACR,iBAAa,sBAAM,GAAG,SAAS,YAAY,OAAO,IAAI;AAAA,cACtD,aAAS,sBAAM,GAAG,SAAS,YAAY,OAAO,IAAI;AAAA,cAClD,OAAO,SAAS,YAAY,MAAM,QAAQ,KAAK,YAAY;AAAA,cAC3D,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,YAAY;AAAA,cACZ,UAAU;AAAA,YACZ;AAAA,UACF;AAAA,UACA,GAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,CAAC,EAAE;AAAA,QAClC;AAAA,QAEC;AAAA,iBACC;AAAA,YAAC,YAAAA;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,IAAI,YAAU;AAAA,gBACZ,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,cAAc;AAAA,gBACd,SAAS,UAAU,OAAO,IAAI;AAAA,gBAC9B,YAAY;AAAA,cACd;AAAA;AAAA,UACF;AAAA,UAEF,6CAAC,YAAAA,SAAA,EAAI,WAAU,QAAO,IAAI,EAAE,UAAU,UAAU,cAAc,WAAW,GACtE,iBACH;AAAA;AAAA;AAAA,IACF;AAIK,IAAM,UAAoE,CAAC;AAAA,MAChF;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT,MACE;AAAA,MAAC,YAAAA;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV;AAAA,QACA,IAAI,YAAU;AAAA,UACZ,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,QAAQ;AAAA,UACR,IAAI;AAAA,UACJ,cAAc;AAAA,UACd,aAAS,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,UACtF,OAAO,MAAM,QAAQ,KAAK;AAAA,UAC1B,YAAY,OAAO,mDAAmD;AAAA,UACtE,UAAU;AAAA,UACV,YAAY;AAAA,UACZ,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,UAAU;AAAA,UACV,cAAc;AAAA,QAChB;AAAA,QAEC;AAAA;AAAA,IACH;AAAA;AAAA;;;ACqFK,SAAS,iBAAmC;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE;AAAA,IAAC,YAAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,IAAI,YAAU;AAAA,QACZ,SAAS;AAAA,QACT,KAAK;AAAA,QACL,GAAG;AAAA,QACH,cAAc;AAAA,QACd,QAAQ;AAAA,QACR,aAAa,MAAM,QAAQ;AAAA,MAC7B;AAAA,MAEC,kBAAQ,IAAI,SAAO;AAClB,cAAM,WAAW,IAAI,UAAU;AAC/B,eACE;AAAA,UAAC,kBAAAC;AAAA,UAAA;AAAA,YAEC,MAAK;AAAA,YACL,iBAAe;AAAA,YACf,SAAS,MAAM,SAAS,IAAI,KAAK;AAAA,YACjC,IAAI,YAAU;AAAA,cACZ,IAAI;AAAA,cACJ,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,UAAU;AAAA,cACV,YAAY,WAAW,MAAM;AAAA;AAAA;AAAA;AAAA,cAI7B,OAAO,WAAW,MAAM,QAAQ,QAAQ,OAAO,MAAM,QAAQ,KAAK;AAAA,cAClE,SAAS,eACL,sBAAM,MAAM,QAAQ,QAAQ,MAAM,MAAM,QAAQ,SAAS,SAAS,MAAM,IAAI,IAC5E;AAAA,cACJ,YAAY,MAAM,YAAY,OAAO,CAAC,oBAAoB,OAAO,CAAC;AAAA,cAClE,WAAW;AAAA,gBACT,OAAO,WAAW,MAAM,QAAQ,QAAQ,OAAO,MAAM,QAAQ,KAAK;AAAA,gBAClE,SAAS,eACL,sBAAM,MAAM,QAAQ,QAAQ,MAAM,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI,QAC7E,sBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,cAC5C;AAAA,YACF;AAAA,YAEC,cAAI;AAAA;AAAA,UA1BA,IAAI;AAAA,QA2BX;AAAA,MAEJ,CAAC;AAAA;AAAA,EACH;AAEJ;AA1OA,IACAC,aACA,mBACAC,eACAC,oBACAC,gBA2BQC,qBArBK,aAuCA,WAuCA,aA8DA,MA2FA,aA8BA,mBASA;AAzRb;AAAA;AAAA;AACA,IAAAJ,cAAgB;AAChB,wBAAuB;AACvB,IAAAC,gBAAkB;AAClB,IAAAC,qBAAuB;AACvB,IAAAC,iBAAsB;AAEtB;AAyBQ,IAAAC,sBAAA;AArBD,IAAM,cAOR,CAAC,EAAE,OAAO,UAAU,SAAS,QAAQ,OAAO,SAAS,MACxD,8CAAC,cAAAC,SAAA,EAAM,IAAI,EAAE,cAAc,GAAG,UAAU,SAAS,GAC7C;AAAA,gBAAS,YACT;AAAA,QAAC,YAAAP;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,YACF,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,gBAAgB;AAAA,YAChB,KAAK;AAAA,YACL,UAAU;AAAA,YACV,IAAI;AAAA,YACJ,IAAI;AAAA,UACN;AAAA,UAEA;AAAA,0DAAC,YAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,EAAE,GACrB;AAAA,2DAAC,mBAAAQ,SAAA,EAAW,SAAQ,MAAK,IAAI,EAAE,YAAY,IAAI,GAAI,iBAAM;AAAA,cACxD,YACC,6CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,oBAAS;AAAA,eAEnE;AAAA,YACC,WACC,6CAAC,YAAAR,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,UAAU,OAAO,GACxE,mBACH;AAAA;AAAA;AAAA,MAEJ;AAAA,MAEF,6CAAC,YAAAA,SAAA,EAAI,IAAI,QAAQ,SAAY,EAAE,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,IAAI,IAAI,GAAI,UAAS;AAAA,OACpF;AAIK,IAAM,YAKR,CAAC,EAAE,OAAO,MAAM,SAAS,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA,MAI1C,8CAAC,cAAAO,SAAA,EAAM,SAAQ,YAAW,IAAI,EAAE,GAAG,GAAG,cAAc,GAAG,QAAQ,OAAO,GACpE;AAAA,sDAAC,YAAAP,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,YAAY,KAAK,GAAG,IAAI,KAAK,UAAU,OAAO,GACpF;AAAA;AAAA,YAAC,mBAAAQ;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,IAAI,EAAE,UAAU,IAAI,YAAY,KAAK,eAAe,UAAU,eAAe,YAAY;AAAA,cAExF;AAAA;AAAA,UACH;AAAA,UACC,QACC,6CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,gBAAK;AAAA,WAE/D;AAAA,QACA,6CAAC,YAAAR,SAAA,EAAI,IAAI,EAAE,QAAQ,OAAO,OAAO,GAAI,UAAS;AAAA,SAChD;AAAA;AAiBK,IAAM,cAA4C,CAAC,EAAE,QAAQ,MAClE;AAAA,MAAC,cAAAO;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,IAAI;AAAA,UACF,cAAc;AAAA,UACd,SAAS;AAAA,UACT,qBAAqB,EAAE,IAAI,WAAW,IAAI,UAAU,QAAQ,MAAM,SAAS;AAAA,UAC3E,UAAU;AAAA,QACZ;AAAA,QAEC,kBAAQ,IAAI,CAAC,GAAG,MACf;AAAA,UAAC,YAAAP;AAAA,UAAA;AAAA,YAEC,IAAI,YAAU;AAAA,cACZ,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,YAAY,MAAM,IAAI,IAAI;AAAA,cAC1B,WAAW;AAAA,cACX,aAAa;AAAA,cACb,CAAC,MAAM,YAAY,KAAK,IAAI,CAAC,GAAG;AAAA,gBAC9B,YAAY,IAAI,MAAM,IAAI,IAAI;AAAA,gBAC9B,WAAW,IAAI,IAAI,IAAI;AAAA,gBACvB,aAAa;AAAA,cACf;AAAA,YACF;AAAA,YAEA;AAAA,4DAAC,YAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,OAAO,IAAI,KAAK,GACrE;AAAA;AAAA,kBAAC,YAAAA;AAAA,kBAAA;AAAA,oBACC,IAAI,YAAU;AAAA,sBACZ,OAAO;AAAA,sBACP,QAAQ;AAAA,sBACR,cAAc;AAAA,sBACd,SAAS,UAAU,OAAO,EAAE,QAAQ,QAAQ;AAAA,sBAC5C,YAAY;AAAA,oBACd;AAAA;AAAA,gBACF;AAAA,gBACA;AAAA,kBAAC,mBAAAQ;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,IAAI,EAAE,UAAU,IAAI,YAAY,KAAK,eAAe,UAAU,eAAe,YAAY;AAAA,oBAExF,YAAE;AAAA;AAAA,gBACL;AAAA,iBACF;AAAA,cACA;AAAA,gBAAC,mBAAAA;AAAA,gBAAA;AAAA,kBACC,IAAI,EAAE,UAAU,IAAI,YAAY,KAAK,YAAY,MAAM,oBAAoB,eAAe;AAAA,kBAEzF,YAAE;AAAA;AAAA,cACL;AAAA,cACA;AAAA,gBAAC,mBAAAA;AAAA,gBAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,OAAM;AAAA,kBACN,IAAI,EAAE,SAAS,SAAS,IAAI,KAAK,WAAW,GAAG;AAAA,kBAE9C,YAAE,QAAQ;AAAA;AAAA,cACb;AAAA;AAAA;AAAA,UA3CK,EAAE;AAAA,QA4CT,CACD;AAAA;AAAA,IACH;AAIK,IAAM,OAAgD,CAAC,EAAE,OAAO,MAAM,MAC3E,8CAAC,YAAAR,SAAA,EAAI,IAAI,EAAE,UAAU,EAAE,GACrB;AAAA;AAAA,QAAC,mBAAAQ;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAM;AAAA,UACN,IAAI,EAAE,SAAS,SAAS,UAAU,MAAM,YAAY,KAAK,eAAe,UAAU,eAAe,YAAY;AAAA,UAE5G;AAAA;AAAA,MACH;AAAA,MACA;AAAA,QAAC,mBAAAA;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,IAAI,EAAE,YAAY,KAAK,oBAAoB,gBAAgB,IAAI,KAAK;AAAA,UAEnE;AAAA;AAAA,MACH;AAAA,OACF;AA4EK,IAAM,cAA8B,YAAU;AAAA;AAAA;AAAA,MAGnD,cAAc;AAAA,QACZ,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,eAAe;AAAA,QACf,eAAe;AAAA,QACf,OAAO,MAAM,QAAQ,KAAK;AAAA,QAC1B,qBAAiB,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,QAC9F,cAAc,aAAa,MAAM,QAAQ,OAAO;AAAA,QAChD,YAAY;AAAA,QACZ,YAAY,MAAM,QAAQ,IAAI;AAAA,QAC9B,eAAe,MAAM,QAAQ,IAAI;AAAA,MACnC;AAAA,MACA,cAAc;AAAA,QACZ,cAAc,iBAAa,sBAAM,MAAM,QAAQ,SAAS,GAAG,CAAC;AAAA,QAC5D,YAAY,MAAM,QAAQ,IAAI;AAAA,QAC9B,eAAe,MAAM,QAAQ,IAAI;AAAA,QACjC,oBAAoB;AAAA,MACtB;AAAA,MACA,8BAA8B;AAAA,QAC5B,cAAc;AAAA,MAChB;AAAA,MACA,oBAAoB;AAAA,QAClB,qBAAiB,sBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,MACzD;AAAA,IACF;AAGO,IAAM,oBAAoB,CAAC,OAAa,cAA8B,YAAU;AAAA,MACrF,OAAO,MAAM,QAAQ,KAAK;AAAA,MAC1B,WAAW;AAAA,QACT,OAAO,UAAU,OAAO,IAAI;AAAA,QAC5B,aAAS,sBAAM,UAAU,OAAO,IAAI,GAAG,GAAG;AAAA,MAC5C;AAAA,IACF;AAGO,IAAM,aAKR,CAAC,EAAE,SAAS,MAAM,QAAQ,OAAO,MACpC;AAAA,MAAC,YAAAR;AAAA,MAAA;AAAA,QACC,IAAI;AAAA,UACF;AAAA,UACA,WAAW,SAAS,SAAY;AAAA,UAChC,SAAS;AAAA,UACT,eAAe;AAAA,UACf,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,KAAK;AAAA,UACL,WAAW;AAAA,UACX,IAAI;AAAA,QACN;AAAA,QAEA;AAAA,uDAAC,mBAAAQ,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,mBAAQ;AAAA,UAC3D,QAAQ,6CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAkB,gBAAK;AAAA,UACnE;AAAA;AAAA;AAAA,IACH;AAAA;AAAA;;;AC/SF,IACAC,aACAC,gBAsBIC,qBAhBS;AARb;AAAA;AAAA;AACA,IAAAF,cAAgB;AAChB,IAAAC,iBAAsB;AACtB;AAqBI,IAAAC,sBAAA;AAhBG,IAAM,QAMR,CAAC;AAAA,MACJ;AAAA,MACA,OAAO;AAAA,MACP,SAAS;AAAA,MACT;AAAA,IACF,MAAM;AACJ,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AAChD,YAAM,YAAY,QAAQ;AAE1B,aACE,8CAAC,YAAAC,SAAA,EACD;AAAA;AAAA,UAAC,YAAAA;AAAA,UAAA;AAAA,YACC,IAAI,YAAU;AAAA,cACZ;AAAA,cACA,cAAc;AAAA,cACd,aAAS,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,cACtF,UAAU;AAAA,YACZ;AAAA,YACA,MAAK;AAAA,YACL,iBAAe;AAAA,YACf,iBAAe;AAAA,YACf,iBAAe;AAAA,YACf,cAAY;AAAA,YACZ,kBAAgB,YAAY,GAAG,KAAK,MAAM,KAAK,CAAC,sBAAiB;AAAA,YAEjE;AAAA,cAAC,YAAAA;AAAA,cAAA;AAAA,gBACC,IAAI,YAAU;AAAA,kBACZ,QAAQ;AAAA,kBACR,OAAO,GAAG,OAAO;AAAA,kBACjB,cAAc;AAAA,kBACd,SAAS,UAAU,OAAO,IAAI;AAAA,kBAC9B,YAAY,MAAM,YAAY,OAAO,OAAO;AAAA,gBAC9C;AAAA;AAAA,YACF;AAAA;AAAA,QACF;AAAA,QACG,aACC;AAAA,UAAC,YAAAA;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,WAAW;AAAA,cACX,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,IAAI;AAAA,YACN;AAAA,YACD;AAAA;AAAA,QAED;AAAA,SAEJ;AAAA,IAEJ;AAAA;AAAA;;;AChEA,IACAC,aACAC,oBACAC,gBA6CMC,qBApCO;AAZb;AAAA;AAAA;AACA,IAAAH,cAAgB;AAChB,IAAAC,qBAAuB;AACvB,IAAAC,iBAAsB;AACtB;AA4CM,IAAAC,sBAAA;AApCC,IAAM,QAcR,CAAC,EAAE,OAAO,OAAO,UAAU,OAAO,IAAI,YAAY,GAAG,OAAO,SAAS,UAAU,MAAM;AACxF,YAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,SAAS,CAAC,CAAC;AACrD,YAAM,KAAK,OAAO,aAAa;AAC/B,YAAM,IAAI,IAAI,KAAK,KAAK;AACxB,YAAM,OAAQ,UAAU,MAAO;AAC/B,YAAM,YAAY,QAAQ;AAE1B,aACE;AAAA,QAAC,YAAAC;AAAA,QAAA;AAAA,UACC,IAAI,YAAU;AAAA,YACZ,UAAU;AAAA,YACV,OAAO;AAAA,YACP,QAAQ;AAAA,YACR,OAAO,UAAU,OAAO,IAAI;AAAA,UAC9B;AAAA,UACA,MAAK;AAAA,UACL,iBAAe;AAAA,UACf,iBAAe;AAAA,UACf,iBAAe;AAAA,UACf,cAAY;AAAA,UACZ,kBAAgB,YAAY,GAAG,KAAK,MAAM,KAAK,CAAC,sBAAiB;AAAA,UAEjE;AAAA;AAAA,cAAC,YAAAA;AAAA,cAAA;AAAA,gBACC,WAAU;AAAA,gBACV,SAAS,OAAO,IAAI,IAAI,IAAI;AAAA,gBAC5B,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,IAAI,EAAE,SAAS,SAAS,WAAW,iBAAiB;AAAA,gBAEpD;AAAA;AAAA,oBAAC,YAAAA;AAAA,oBAAA;AAAA,sBACC,WAAU;AAAA,sBACV,IAAI,OAAO;AAAA,sBACX,IAAI,OAAO;AAAA,sBACX;AAAA,sBACA,MAAK;AAAA,sBACL,aAAa;AAAA,sBACb,IAAI,YAAU;AAAA,wBACZ,YAAQ;AAAA,0BACN,MAAM,QAAQ,KAAK;AAAA,0BACnB,MAAM,QAAQ,SAAS,SAAS,OAAO;AAAA,wBACzC;AAAA,sBACF;AAAA;AAAA,kBACF;AAAA,kBACA;AAAA,oBAAC,YAAAA;AAAA,oBAAA;AAAA,sBACC,WAAU;AAAA,sBACV,IAAI,OAAO;AAAA,sBACX,IAAI,OAAO;AAAA,sBACX;AAAA,sBACA,MAAK;AAAA,sBACL,aAAa;AAAA,sBACb,eAAc;AAAA,sBACd,iBAAiB,GAAG,IAAI,IAAI,IAAI,IAAI;AAAA,sBACpC,IAAI,YAAU;AAAA,wBACZ,QAAQ;AAAA,wBACR,YAAY,MAAM,YAAY,OAAO,kBAAkB;AAAA,sBACzD;AAAA;AAAA,kBACF;AAAA;AAAA;AAAA,YACF;AAAA,YACA;AAAA,cAAC,YAAAA;AAAA,cAAA;AAAA,gBACC,IAAI;AAAA,kBACF,UAAU;AAAA,kBACV,OAAO;AAAA,kBACP,SAAS;AAAA,kBACT,eAAe;AAAA,kBACf,YAAY;AAAA,kBACZ,gBAAgB;AAAA,kBAChB,YAAY;AAAA,gBACd;AAAA,gBAKA;AAAA;AAAA,oBAAC,mBAAAC;AAAA,oBAAA;AAAA,sBACC,IAAI;AAAA,wBACF,UAAU,QAAQ,KAAK,KAAK;AAAA,wBAC5B,YAAY;AAAA,wBACZ,oBAAoB;AAAA,wBACpB,OAAO,YAAY,iBAAiB;AAAA,sBACtC;AAAA,sBAEC,mBAAS,GAAG,KAAK,MAAM,KAAK,CAAC;AAAA;AAAA,kBAChC;AAAA,kBACC,WACC;AAAA,oBAAC,mBAAAA;AAAA,oBAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,IAAI;AAAA,wBACF,UAAU;AAAA,wBACV,OAAO;AAAA,wBACP,IAAI;AAAA,wBACJ,YAAY;AAAA,sBACd;AAAA,sBAEC;AAAA;AAAA,kBACH;AAAA;AAAA;AAAA,YAEJ;AAAA;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA;AAAA;;;AC5HA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;;;ACLA,IACA,eACA,uBACA,wBAuCmBC,qBAhBN;AA1Bb;AAAA;AAAA;AACA,oBAAmB;AACnB,4BAAoB;AACpB,6BAAqB;AAuCF,IAAAA,sBAAA;AAhBZ,IAAM,oBAAgD,CAAC;AAAA,MAC5D;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,MACA,YAAY;AAAA,MACZ,WAAW;AAAA,IACb,MAAM;AACJ,UAAI,WAAW,CAAC,UAAU;AACxB,eACE;AAAA,UAAC,cAAAC;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,OAAM;AAAA,YACN,kBAAgB;AAAA,YAChB;AAAA,YACA;AAAA,YACA,WAAW,6CAAC,6BAAI;AAAA,YAChB;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,MAEJ;AACA,UAAI,MAAM,CAAC,UAAU;AACnB,eACE;AAAA,UAAC,cAAAA;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,OAAM;AAAA,YACN,kBAAgB;AAAA,YAChB;AAAA,YACA;AAAA,YACA,WAAW,6CAAC,6BAAI;AAAA,YAChB,WAAW;AAAA,YACX;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,MAEJ;AACA,aACE;AAAA,QAAC,cAAAA;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAM;AAAA,UACN,kBAAgB;AAAA,UAChB;AAAA,UACA;AAAA,UACA,WAAW,6CAAC,6BAAI;AAAA,UAChB,UAAQ;AAAA,UAEP;AAAA;AAAA,MACH;AAAA,IAEJ;AAAA;AAAA;;;ACpDA,SAAS,SAAS,MAAsB;AACtC,QAAM,QAAQ,KAAK,MAAM,GAAG,EAAE,CAAC,KAAK;AACpC,QAAM,QAAQ,MAAM,MAAM,WAAW,EAAE,OAAO,OAAO;AACrD,MAAI,MAAM,UAAU,EAAG,SAAQ,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,YAAY;AACtE,SAAO,MAAM,MAAM,GAAG,CAAC,EAAE,YAAY;AACvC;AA/BA,kBACAC,aACAC,oBACA,iBACAC,eACA,gBACAC,oBACAC,gBAwCIC,qBAdE,WAoEO;AArGb;AAAA;AAAA;AAAA,mBAAuC;AACvC,IAAAL,cAAgB;AAChB,IAAAC,qBAAuB;AACvB,sBAAqB;AACrB,IAAAC,gBAAkB;AAClB,qBAAoB;AACpB,IAAAC,qBAAuB;AACvB,IAAAC,iBAAsB;AAEtB;AACA;AACA;AAoCI,IAAAC,sBAAA;AAdJ,IAAM,YAMD,CAAC,EAAE,OAAO,OAAO,MAAM,WAAW,QAAQ,MAAM;AAGnD,YAAM,SAAS,UAAU,QAAQ,QAAQ;AACzC,YAAM,UAAU,UAAU,OAAO,WAAM;AACvC,YAAM,cAAc,aAAa,UAAU;AAE3C,YAAM,UACJ,8CAAC,YAAAC,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,EAAE,GACvD;AAAA;AAAA,UAAC,YAAAA;AAAA,UAAA;AAAA,YACC,eAAY;AAAA,YACZ,IAAI,YAAU;AAAA,cACZ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,YAAY;AAAA,cACZ,SAAS,SACJ,SAAS,YAAY,MAAM,QAAQ,MAAM,QACzC,SAAS,aAAa,MAAM,QAAQ,QAAQ,QAC7C,MAAM,QAAQ,QAAQ,WACtB,sBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,YAC5C;AAAA;AAAA,QACF;AAAA,QACA;AAAA,UAAC,mBAAAC;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,IAAI;AAAA,cACF,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,cACZ,oBAAoB;AAAA,cACpB,GAAI,eAAe,EAAE,QAAQ,WAAW,gBAAgB,YAAY;AAAA,YACtE;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACA;AAAA,UAAC,mBAAAA;AAAA,UAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAM;AAAA,YACN,IAAI;AAAA,cACF,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,eAAe;AAAA,cACf,GAAI,eAAe,EAAE,QAAQ,UAAU;AAAA,YACzC;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,SACF;AAGF,UAAI,aAAa;AACf,eACE,6CAAC,mBAAAC,SAAA,EAAW,SAAkB,IAAI,EAAE,cAAc,KAAK,IAAI,KAAK,IAAI,KAAK,GACtE,mBACH;AAAA,MAEJ;AAEA,aAAO;AAAA,IACT;AAEO,IAAM,kBAA4C,CAAC;AAAA,MACxD;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,aAAS,sBAAQ,MAAM;AAC3B,YAAI,WAAW;AACb,iBAAO,EAAE,OAAO,MAAM,SAAS,MAAM,cAAc,KAAK;AAAA,QAC1D;AACA,cAAM,UAAU,KAAK,OAAO,OAAK,aAAa,EAAE,UAAU,MAAM,SAAS,EAAE;AAC3E,cAAM,eAAe,KAAK,OAAO,OAAK,aAAa,EAAE,UAAU,MAAM,MAAM,EAAE;AAC7E,eAAO,EAAE,OAAO,KAAK,QAAQ,SAAS,aAAa;AAAA,MACrD,GAAG,CAAC,MAAM,SAAS,CAAC;AAEpB,YAAM,cAAc,SAAS,cAAc,SAAS,SAAS,SAAS;AAEtE,aACE,8CAAC,cAAAC,SAAA,EAAM,IAAI,EAAE,cAAc,GAAG,UAAU,SAAS,GAC/C;AAAA;AAAA,UAAC,YAAAH;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,UAAU;AAAA,cACV,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,IAAI;AAAA,YACN;AAAA,YAEA;AAAA;AAAA,gBAAC,YAAAA;AAAA,gBAAA;AAAA,kBACC,IAAI,YAAU;AAAA,oBACZ,OAAO;AAAA,oBACP,QAAQ;AAAA,oBACR,cAAc;AAAA,oBACd,YAAY;AAAA,oBACZ,SAAS;AAAA,oBACT,YAAY;AAAA,oBACZ,gBAAgB;AAAA,oBAChB,aAAS,sBAAM,MAAM,QAAQ,QAAQ,MAAM,IAAI;AAAA,oBAC/C,OAAO,MAAM,QAAQ,QAAQ;AAAA,oBAC7B,UAAU;AAAA,oBACV,YAAY;AAAA,oBACZ,eAAe;AAAA,kBACjB;AAAA,kBAEC,mBAAS,WAAW;AAAA;AAAA,cACvB;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,GAAG,UAAU,IAAI,GACpC;AAAA,6DAAC,mBAAAC,SAAA,EAAW,SAAQ,MAAK,IAAI,EAAE,YAAY,MAAM,WAAW,aAAa,GACtE,uBACH;AAAA,gBACA;AAAA,kBAAC,mBAAAA;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,IAAI,EAAE,SAAS,SAAS,YAAY,iDAAiD;AAAA,oBAEpF,mBAAS;AAAA;AAAA,gBACZ;AAAA,gBAEA,6CAAC,YAAAD,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,KAAK,MAAM,UAAU,QAAQ,IAAI,GAAG,WAAW,GAAG,GAC3E,oBACC,6CAAC,gBAAAI,SAAA,EAAS,SAAQ,WAAU,OAAO,KAAK,QAAQ,IAAI,IAEpD,MAAM,IAAI,UACR;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAO,KAAK,cAAc,KAAK;AAAA,oBAC/B,OAAO,KAAK;AAAA;AAAA,kBAFP,KAAK;AAAA,gBAGZ,CACD,GAEL;AAAA,iBACF;AAAA,cAEA,6CAAC,qBAAkB,SAAS,oBAAoB;AAAA;AAAA;AAAA,QAClD;AAAA,QAEA,6CAAC,eAAAC,SAAA,EAAQ;AAAA,QAET;AAAA,UAAC,YAAAL;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,UAAU;AAAA,cACV,IAAI;AAAA,cACJ,IAAI;AAAA,YACN;AAAA,YAEA;AAAA,2DAAC,aAAU,OAAO,OAAO,OAAO,OAAM,QAAO,MAAK,UAAS;AAAA,cAC3D,6CAAC,eAAAK,SAAA,EAAQ,aAAY,YAAW,UAAQ,MAAC,IAAI,EAAE,IAAI,KAAK,GAAG,eAAY,QAAO;AAAA,cAC9E;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,OAAO;AAAA,kBACd,OAAM;AAAA,kBACN,MAAK;AAAA,kBACL,WAAS;AAAA,kBACT,SAAS,MAAM,qBAAqB,SAAS;AAAA;AAAA,cAC/C;AAAA,cACA,6CAAC,eAAAA,SAAA,EAAQ,aAAY,YAAW,UAAQ,MAAC,IAAI,EAAE,IAAI,KAAK,GAAG,eAAY,QAAO;AAAA,cAC9E;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,OAAO;AAAA,kBACd,OAAM;AAAA,kBACN,MAAK;AAAA,kBACL,WAAS;AAAA,kBACT,SAAS,MAAM,qBAAqB,UAAU;AAAA;AAAA,cAChD;AAAA;AAAA;AAAA,QACF;AAAA,QAEC,QACC,8EACE;AAAA,uDAAC,eAAAA,SAAA,EAAQ;AAAA,UACT,6CAAC,YAAAL,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GAAI,gBAAK;AAAA,WAC5B;AAAA,SAEJ;AAAA,IAEJ;AAAA;AAAA;;;ACxNO,SAAS,0BAAmC;AACjD,SAAO,OAAO,cAAc,eAAe,CAAC,CAAC,UAAU,WAAW;AACpE;AAMA,SAAS,wBAAwB,MAAuB;AACtD,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,QAAQ;AACjB,WAAS,MAAM,WAAW;AAC1B,WAAS,MAAM,UAAU;AACzB,WAAS,MAAM,gBAAgB;AAC/B,WAAS,KAAK,YAAY,QAAQ;AAClC,MAAI;AACF,aAAS,OAAO;AAChB,UAAM,UAAU,SAAS,YAAY,MAAM;AAC3C,aAAS,KAAK,YAAY,QAAQ;AAClC,WAAO;AAAA,EACT,QAAQ;AACN,aAAS,KAAK,YAAY,QAAQ;AAClC,WAAO;AAAA,EACT;AACF;AAMO,SAAS,iBACd,gBACA,aAAqB,KACU;AAC/B,SAAO,WAAW,MAAM;AACtB,mBAAe,KAAK;AAAA,EACtB,GAAG,UAAU;AACf;AAaO,SAAS,qBAId;AACA,QAAM,eAAW,+BAAO,mCAAW;AACnC,QAAM,CAAC,QAAQ,SAAS,QAAI,wBAAS,KAAK;AAC1C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AACrD,QAAM,eAAW,sBAA6C,IAAI;AAGlE,+BAAU,MAAM;AACd,WAAO,MAAM;AACX,UAAI,SAAS,YAAY,MAAM;AAC7B,qBAAa,SAAS,OAAO;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,OAAO,SAAmC;AAErD,QAAI,SAAS,YAAY,MAAM;AAC7B,mBAAa,SAAS,OAAO;AAC7B,eAAS,UAAU;AAAA,IACrB;AACA,aAAS,IAAI;AAEb,QAAI;AACF,UAAI,wBAAwB,GAAG;AAC7B,cAAM,UAAU,UAAU,UAAU,IAAI;AAAA,MAC1C,OAAO;AACL,cAAM,UAAU,wBAAwB,IAAI;AAC5C,YAAI,CAAC,SAAS;AACZ,gBAAM,IAAI,MAAM,uBAAuB;AAAA,QACzC;AAAA,MACF;AACA,gBAAU,IAAI;AACd,eAAS,UAAU,iBAAiB,WAAW,GAAI;AACnD,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,YAAY,eAAe,QAAQ,MAAM,IAAI,MAAM,0BAA0B;AACnF,eAAS,SAAS;AAClB,eAAS,KAAK;AAAA,QACZ,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AACD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,QAAQ,MAAM;AAC/B;AA5GA,IAAAM,eACA,wBACAC;AAFA;AAAA;AAAA;AAAA,IAAAD,gBAA4C;AAC5C,6BAAuB;AACvB,IAAAC,0BAA4B;AAAA;AAAA;;;ACkCrB,SAAS,kBAAkB,QAAsB,sBAA4C;AAClG,QAAM,UAAM,gCAAO,aAAa;AAChC,QAAM,CAAC,MAAM,OAAO,QAAI,wBAAsB;AAAA,IAC5C,UAAU;AAAA,IACV,OAAO,CAAC;AAAA,IACR,MAAM,CAAC;AAAA,IACP,QAAQ,CAAC;AAAA,IACT,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,IAAI;AAC3C,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AACtD,QAAM,sBAAkB,sBAAO,CAAC;AAEhC,QAAM,mBAAe,2BAAY,YAAY;AAC3C,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,CAAC,UAAU,OAAO,MAAM,QAAQ,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,QAChE,MAAM,QAAQ,KAAK,oBAAoB,MAAM,IAAI,YAAY,CAAC;AAAA,QAC9D,MAAM,QAAQ,KAAK,iBAAiB,MAAM,IAAI,SAAS,CAAC;AAAA,QACxD,MAAM,QAAQ,KAAK,gBAAgB,MAAM,IAAI,SAAS,CAAC;AAAA,QACvD,MAAM,QAAQ,KAAK,kBAAkB,MAAM,IAAI,WAAW,CAAC;AAAA,QAC3D,MAAM,QAAQ,KAAK,kBAAkB,MAAM,IAAI,UAAU,CAAC;AAAA,MAC5D,CAAC;AAED,cAAQ,EAAE,UAAU,OAAO,MAAM,QAAQ,OAAO,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,eAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC3D,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,KAAK,KAAK,CAAC;AAEf,+BAAU,MAAM;AACd,iBAAa;AAAA,EACf,GAAG,CAAC,KAAK,YAAY,CAAC;AAEtB,QAAM,YAAQ,2BAAY,MAAM;AAC9B,UAAM,kBAAkB,GAAG;AAC3B,oBAAgB;AAChB,iBAAa;AAAA,EACf,GAAG,CAAC,KAAK,OAAO,YAAY,CAAC;AAE7B,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AArFA,IAMAC,eACAC;AAPA;AAAA;AAAA;AAMA,IAAAD,gBAAyD;AACzD,IAAAC,0BAAuB;AACvB;AAEA;AAAA;AAAA;;;ACVA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,SAAS,gBAAgB,KAAyB;AACvD,MAAI,IAAI,WAAW;AACjB,WAAO,IAAI;AAAA,EACb;AACA,SAAO,IAAI,OAAO;AACpB;AAMO,SAAS,SAAS,KAAyB;AAChD,MAAI,CAAC,IAAI,OAAO,IAAI,IAAI,SAAS,GAAG;AAClC,WAAO;AAAA,EACT;AACA,SAAO,IAAI,IAAI,MAAM,EAAE;AACzB;AAMO,SAAS,UAAU,GAAmB;AAC3C,MAAI,MAAM,GAAG;AACX,WAAO;AAAA,EACT;AACA,SAAO,UAAU,CAAC;AACpB;AAcO,SAAS,iBACd,SACA,QACA,SACsC;AACtC,MAAI,SAAS;AACX,WAAO;AAAA,MACL,OAAO,QAAQ,SAAS,kCAAkC;AAAA,MAC1D,UAAU,CAAC,QAAQ;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AAAA,IACL,OAAO,OAAO,SACV,gCACA;AAAA,IACJ,UAAU,CAAC,OAAO;AAAA,EACpB;AACF;AAhEA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAM,mBAYO,QAeA,QAcA,0BAUA,WA4BA;AA/Eb;AAAA;AAAA;AAAA,IAAM,oBAAoB,IAAI,KAAK,aAAa,SAAS;AAAA,MACvD,OAAO;AAAA,MACP,UAAU;AAAA,MACV,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,IACzB,CAAC;AAOM,IAAM,SAAS,CAAC,MAAyC;AAC9D,UAAI,MAAM,QAAQ,MAAM,UAAa,OAAO,MAAM,CAAC,GAAG;AACpD,eAAO;AAAA,MACT;AACA,UAAI,MAAM,GAAG;AACX,eAAO;AAAA,MACT;AAEA,YAAM,MAAM,KAAK,IAAI,CAAC;AACtB,UAAI,MAAM,KAAK,MAAM,MAAM;AACzB,eAAO,IAAI,IAAI,YAAY;AAAA,MAC7B;AACA,aAAO,kBAAkB,OAAO,CAAC;AAAA,IACnC;AAEO,IAAM,SAAS,CAAC,OAAe,KAAK,GAAG,eAAe;AActD,IAAM,2BAA2B,CAAC,QAAgB,kBAA0C;AACjG,UAAI,CAAC,iBAAiB,iBAAiB,KAAK,CAAC,UAAU,UAAU,EAAG,QAAO;AAC3E,aAAO,KAAK,MAAM,SAAS,aAAa;AAAA,IAC1C;AAOO,IAAM,YAAY,CAAC,KAAgC,QAA2C;AACnG,YAAM,SAAS,MAAM,OAAO,GAAG,IAAI;AACnC,YAAM,SAAS,MAAM,OAAO,GAAG,IAAI;AACnC,UAAI,WAAW,eAAe,WAAW,aAAa;AACpD,eAAO;AAAA,MACT;AACA,aAAO,GAAG,MAAM,MAAM,MAAM;AAAA,IAC9B;AAqBO,IAAM,kBAAkB,CAC7B,OACA,WACa;AACb,UAAI,CAAC,OAAO,gBAAgB;AAC1B,eAAO,OAAO,IAAI,OAAK,EAAE,UAAU;AAAA,MACrC;AACA,YAAM,YAAY,OAAO,KAAK,MAAM,cAAc;AAClD,YAAM,gBAAgB,IAAI,IAAI,SAAS;AACvC,YAAM,QAAQ,OAAO,IAAI,OAAK,EAAE,UAAU;AAI1C,aAAO;AAAA,QACL,GAAG,MAAM,OAAO,UAAQ,cAAc,IAAI,IAAI,CAAC;AAAA,QAC/C,GAAG,UAAU,OAAO,UAAQ,CAAC,MAAM,SAAS,IAAI,CAAC;AAAA,MACnD;AAAA,IACF;AAAA;AAAA;;;ACjFO,SAAS,mBAAmB,MAAoB,QAAqC;AAC1F,MAAI,CAAC,OAAQ,QAAO;AAEpB,SAAO,KAAK,OAAO,SAAO;AACxB,UAAM,SAAS,aAAa,IAAI,UAAU;AAC1C,QAAI,WAAW,UAAW,QAAO,WAAW;AAC5C,QAAI,WAAW,WAAY,QAAO,WAAW;AAC7C,WAAO;AAAA,EACT,CAAC;AACH;AAxBA;AAAA;AAAA;AAKA;AAAA;AAAA;;;AC0EA,SAAS,gBAAgB,QAAmC,WAA2B;AACrF,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,WAAW,OAAQ,QAAO,GAAG,KAAK,MAAM,IAAI,KAAK,SAAS,EAAE,QAAQ,IAAI,KAAK,IAAI,KAAK,KAAQ,CAAC;AACnG,SAAO,WAAW,SAAS;AAC7B;AAEA,SAAS,WAAW,QAAyC;AAC3D,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO;AACT;AAEA,SAAS,WAAW,EAAE,UAAU,GAA2B;AACzD,QAAM,SAAS,aAAa,SAAS;AACrC,MAAI,CAAC,QAAQ;AACX,WAAO,6CAAC,mBAAAC,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,mBAAK;AAAA,EACjE;AAGA,MAAI,WAAW,MAAM;AACnB,WACE,6CAAC,mBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAC/B,qBAAW,SAAU,GACxB;AAAA,EAEJ;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,gBAAgB,QAAQ,SAAU;AAAA,MACzC,MAAM,WAAW,MAAM;AAAA,MACvB,OAAO,WAAW,WAAW,SAAU,CAAC;AAAA;AAAA,EAC1C;AAEJ;AAEA,SAAS,WAAW,KAAmB;AACrC,MAAI,OAAO,IAAK,QAAO;AACvB,MAAI,OAAO,GAAI,QAAO;AACtB,SAAO;AACT;AAEA,SAAS,aAAa,YAAqB,SAAmB;AAC5D,MAAI,WAAY,QAAO,6CAAC,wBAAAC,SAAA,EAAiB,MAAM,IAAI;AACnD,MAAI,QAAS,QAAO,6CAAC,mCAAS,UAAS,SAAQ;AAC/C,SAAO,6CAAC,+BAAK,UAAS,SAAQ;AAChC;AAEA,SAAS,WAAW,EAAE,OAAO,UAAU,GAA0C;AAC/E,MAAI,CAAC,WAAW;AACd,WACE,8CAAC,mBAAAD,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GACzF;AAAA,aAAO,KAAK;AAAA,MACb,6CAAC,mBAAAA,SAAA,EAAW,WAAU,QAAO,SAAQ,WAAU,IAAI,EAAE,IAAI,KAAK,SAAS,IAAI,GAAG,yBAE9E;AAAA,OACF;AAAA,EAEJ;AACA,QAAM,MAAM,KAAK,IAAI,KAAM,QAAQ,YAAa,GAAG;AACnD,SACE,8CAAC,YAAAE,SAAA,EAAI,UAAU,KACb;AAAA,kDAAC,mBAAAF,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,oBAAoB,gBAAgB,IAAI,IAAI,GAC3E;AAAA,aAAO,KAAK;AAAA,MACb,8CAAC,mBAAAA,SAAA,EAAW,WAAU,QAAO,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,IAAI,IAAI,GAAG;AAAA;AAAA,QAClF,OAAO,SAAS;AAAA,SACrB;AAAA,OACF;AAAA,IACA,6CAAC,SAAM,OAAO,KAAK,MAAM,WAAW,GAAG,GAAG,QAAQ,GAAG;AAAA,KACvD;AAEJ;AAKA,SAAS,YAAY,GAAe,GAAe,SAA0B;AAC3E,UAAQ,SAAS;AAAA,IACf,KAAK;AAAS,cAAQ,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE;AAAA,IACxE,KAAK;AAAW,aAAO,EAAE,WAAW,cAAc,EAAE,UAAU;AAAA,IAC9D,KAAK;AAAW,cAAQ,EAAE,cAAc,IAAI,cAAc,EAAE,cAAc,EAAE;AAAA,IAC5E,KAAK;AAAU,cAAQ,EAAE,cAAc,aAAa,EAAE,cAAc;AAAA,IACpE,KAAK;AAAU,cAAQ,EAAE,aAAa,aAAa,EAAE,aAAa,cAAc,EAAE,aAAa,aAAa,EAAE,aAAa;AAAA,IAC3H,KAAK;AAAU,cAAQ,EAAE,UAAU,CAAC,GAAG,KAAK,GAAG,EAAE,eAAe,EAAE,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC;AAAA,IACzF;AAAS,aAAO;AAAA,EAClB;AACF;AApKA,IAAAG,eACA,cACA,kBACA,kBACA,uBACA,kBACA,iBACA,uBACAC,gBACA,mBACAC,aACAC,oBACA,eACA,oBACA,sBACA,sBACA,kBACA,yBACAC,kBACA,uBACA,gBACA,aACAC,gBACAC,wBACA,gCACA,wCAqEWC,qBA7BL,YAMA,YA+FO;AAtKb;AAAA;AAAA;AAAA,IAAAP,gBAAsC;AACtC,mBAAkB;AAClB,uBAAsB;AACtB,uBAAsB;AACtB,4BAA2B;AAC3B,uBAAsB;AACtB,sBAAqB;AACrB,4BAA2B;AAC3B,IAAAC,iBAAmB;AACnB,wBAAuB;AACvB,IAAAC,cAAgB;AAChB,IAAAC,qBAAuB;AACvB,oBAAmB;AACnB,yBAAwB;AACxB,2BAA0B;AAC1B,2BAA0B;AAC1B,uBAAsB;AACtB,8BAA6B;AAC7B,IAAAC,mBAAqB;AACrB,4BAA2B;AAC3B,qBAAoB;AACpB,kBAAiB;AACjB,IAAAC,iBAAsB;AACtB,IAAAC,yBAA2F;AAC3F,qCAA8B;AAC9B,6CAIO;AACP;AACA;AACA;AACA;AACA;AACA;AAIA;AAuDW,IAAAC,sBAAA;AA7BX,IAAM,aAAa,CAAC,UAA0B;AAC5C,UAAI,CAAC,MAAO,QAAO;AACnB,UAAI,MAAM,UAAU,GAAI,QAAO;AAC/B,aAAO,GAAG,MAAM,MAAM,GAAG,EAAE,CAAC;AAAA,IAC9B;AAEA,IAAM,aAAa,CAAC,YAA4B;AAC9C,UAAI;AACF,eAAO,IAAI,KAAK,OAAO,EAAE,mBAAmB;AAAA,MAC9C,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAyFO,IAAM,YAAgC,CAAC;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AAEJ,YAAM,uBAAmB,8CAAc,EAAE,YAAY,kEAA2B,CAAC;AACjF,YAAM,uBAAmB,8CAAc,EAAE,YAAY,kEAA2B,CAAC;AACjF,YAAM,wBAAoB,8CAAc,EAAE,YAAY,mEAA4B,CAAC;AACnF,YAAM,gBAAgB,CAAC,iBAAiB,WAAW,iBAAiB;AACpE,YAAM,gBAAgB,CAAC,iBAAiB,WAAW,iBAAiB;AAEpE,YAAM,eAAe,CAAC,iBAAiB,WAAW,CAAC,iBAAiB;AACpE,YAAM,eAAe,CAAC,iBAAiB,WAAW,CAAC,iBAAiB;AACpE,YAAM,iBAAiB,CAAC,kBAAkB,WAAW,kBAAkB;AACvE,YAAM,gBAAgB,CAAC,kBAAkB,WAAW,CAAC,kBAAkB;AAGvE,YAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAA4B,IAAI;AAC9E,YAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,KAAK;AAG5D,YAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAA4B,IAAI;AAChF,YAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAAS,KAAK;AAK9D,YAAM,YAAY,mBAAmB;AAGrC,YAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,EAAE;AAC/C,YAAM,CAAC,SAAS,UAAU,QAAI,wBAAkB,SAAS;AACzD,YAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAwB,MAAM;AAExE,YAAM,aAAa,CAAC,gBAAyB;AAC3C,YAAI,YAAY,aAAa;AAC3B,2BAAiB,aAAW,YAAY,QAAQ,SAAS,KAAK;AAAA,QAChE,OAAO;AACL,qBAAW,WAAW;AACtB,2BAAiB,KAAK;AAAA,QACxB;AAAA,MACF;AAEA,YAAM,mBAAe,uBAAQ,MAAM;AACjC,YAAI,SAAS;AAEb,iBAAS,mBAAmB,QAAQ,MAAM;AAE1C,YAAI,WAAW,KAAK,GAAG;AACrB,gBAAM,IAAI,WAAW,YAAY;AACjC,mBAAS,OAAO;AAAA,YAAO,QACpB,EAAE,aAAa,IAAI,YAAY,EAAE,SAAS,CAAC,KAC5C,EAAE,QAAQ,KAAK,OAAK,EAAE,YAAY,EAAE,SAAS,CAAC,CAAC;AAAA,UACjD;AAAA,QACF;AACA,eAAO,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AAChC,gBAAM,aAAa,YAAY,GAAG,GAAG,OAAO;AAC5C,iBAAO,kBAAkB,QAAQ,aAAa,CAAC;AAAA,QACjD,CAAC;AAAA,MACH,GAAG,CAAC,MAAM,YAAY,SAAS,eAAe,MAAM,CAAC;AAErD,YAAM,iBAAiB,CAAC,MAAkB;AACxC,kBAAU,CAAC;AAAA,MACb;AAEA,YAAM,iBAAiB,OAAO,QAAoB;AAChD,cAAM,QAAQ,IAAI,SAAS,IAAI;AAC/B,2BAAmB,IAAI;AACvB,YAAI;AACF,gBAAM,aAAa,KAAK;AAAA,QAC1B,UAAE;AACA,6BAAmB,KAAK;AAAA,QAC1B;AAAA,MACF;AAEA,YAAM,eAAe,OAAO,QAAoB;AAC9C,YAAI,CAAC,gBAAiB;AACtB,cAAM,QAAQ,IAAI,SAAS,IAAI;AAC/B,2BAAmB,IAAI;AACvB,YAAI;AACF,gBAAM,WAAW,KAAK;AAAA,QACxB,UAAE;AACA,6BAAmB,KAAK;AACxB,6BAAmB,IAAI;AAAA,QACzB;AAAA,MACF;AAEA,YAAM,oBAAoB,CAAC,QAAoB;AAC7C,YAAI,IAAI,SAAS;AAEf,yBAAe,GAAG;AAAA,QACpB,OAAO;AAEL,6BAAmB,GAAG;AAAA,QACxB;AAAA,MACF;AAEA,YAAM,sBAAsB,YAAY;AACtC,YAAI,CAAC,iBAAkB;AACvB,4BAAoB,IAAI;AACxB,YAAI;AACF,gBAAM,QAAQ,iBAAiB,SAAS,iBAAiB;AACzD,gBAAM,YAAY,KAAK;AAAA,QACzB,UAAE;AACA,8BAAoB,KAAK;AACzB,8BAAoB,IAAI;AAAA,QAC1B;AAAA,MACF;AAIA,YAAM,CAAC,mBAAmB,oBAAoB,QAAI,wBAAwB,IAAI;AAC9E,YAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,KAAK;AAE5D,YAAM,kBAAc,uBAAQ,MAAM;AAChC,eAAO,KAAK,OAAO,OAAK,aAAa,EAAE,UAAU,MAAM,SAAS;AAAA,MAClE,GAAG,CAAC,IAAI,CAAC;AAET,YAAM,qBAAqB,YAAY;AACrC,YAAI,sBAAsB,QAAQ,sBAAsB,EAAG;AAC3D,2BAAmB,IAAI;AACvB,YAAI;AACF,gBAAM,mBAAmB;AAAA,QAC3B,UAAE;AACA,6BAAmB,KAAK;AACxB,+BAAqB,IAAI;AAAA,QAC3B;AAAA,MACF;AAEA,YAAM,kBAAkB,MAAM;AAC5B,YAAI,SAAS;AACX,iBACE,6CAAC,gBAAAC,SAAA,EACC,uDAAC,iBAAAC,SAAA,EAAU,SAAS,GAAG,IAAI,EAAE,IAAI,EAAE,GACjC,uDAAC,iBAAAC,SAAA,EAAS,SAAQ,WAAU,QAAQ,KAAK,GAC3C,GACF;AAAA,QAEJ;AACA,YAAI,aAAa,WAAW,GAAG;AAC7B,iBACE,6CAAC,gBAAAF,SAAA,EACC,uDAAC,iBAAAC,SAAA,EAAU,SAAS,GACjB,uBACC;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA;AAAA,UACP,IAEA;AAAA,YAAC;AAAA;AAAA,cACC,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,QACE;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAM;AAAA,kBACN,SAAS;AAAA;AAAA,cACX;AAAA;AAAA,UAEJ,GAEJ,GACF;AAAA,QAEJ;AACA,eAAO,aAAa,IAAI,CAAC,QAAQ;AAC/B,gBAAM,QAAQ,IAAI,SAAS,IAAI;AAC/B,gBAAM,YAAY,IAAI,UAAU,CAAC;AACjC,gBAAM,aAAa;AAAA,YACjB,IAAI;AAAA,YACJ,EAAE,SAAS,eAAe,QAAQ,aAAa;AAAA,YAC/C,EAAE,SAAS,gBAAgB,QAAQ,cAAc;AAAA,UACnD;AACA,iBACE;AAAA,YAAC,gBAAAD;AAAA,YAAA;AAAA,cAEC,IACE,IAAI,UACA,YAAU;AAAA;AAAA;AAAA,gBAGR,WAAW,mBAAmB,MAAM,QAAQ,MAAM,IAAI;AAAA,gBACtD,QAAQ,EAAE,OAAO,MAAM,QAAQ,KAAK,UAAU;AAAA,cAChD,KACA;AAAA,cAGN;AAAA,6DAAC,iBAAAC,SAAA,EACC,wDAAC,YAAAV,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,GAAG,UAAS,QACvD;AAAA,+DAAC,mBAAAF,SAAA,EAAW,SAAQ,SACjB,cAAI,aAAa,UACpB;AAAA,kBACC,IAAI,WAAW,6CAAC,cAAW,OAAM,WAAU,MAAK,UAAS;AAAA,mBAC5D,GACF;AAAA,gBACA,6CAAC,iBAAAY,SAAA,EACC,wDAAC,YAAAV,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,KAC3C;AAAA;AAAA,oBAAC,mBAAAF;AAAA,oBAAA;AAAA,sBACC,SAAQ;AAAA,sBACR,WAAU;AAAA,sBACV,OAAM;AAAA,sBACN,OAAO;AAAA,sBACP,IAAI,YAAU;AAAA,wBACZ,YAAY;AAAA,wBACZ,UAAU;AAAA,wBACV,aAAS,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,wBACtF,IAAI;AAAA,wBACJ,IAAI;AAAA,wBACJ,cAAc;AAAA,wBACd,YAAY;AAAA,sBACd;AAAA,sBAEC,qBAAW,KAAK;AAAA;AAAA,kBACnB;AAAA,kBACA,6CAAC,eAAAc,SAAA,EAAQ,OAAO,UAAU,SAAS,WAAW,eAAe,WAAU,OACrE;AAAA,oBAAC,kBAAAC;AAAA,oBAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,UAAU,KAAK,KAAK;AAAA,sBACnC,cAAW;AAAA,sBACX,IAAI,kBAAkB,QAAQ;AAAA,sBAE7B,oBAAU,SAAS,6CAAC,gCAAM,IAAI,EAAE,UAAU,GAAG,GAAG,IAAK,6CAAC,sCAAY,IAAI,EAAE,UAAU,GAAG,GAAG;AAAA;AAAA,kBAC3F,GACF;AAAA,mBACF,GACF;AAAA,gBACA,6CAAC,iBAAAH,SAAA,EACC,uDAAC,mBAAAZ,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,qBAAW,IAAI,UAAU,GAAE,GACjF;AAAA,gBACA,6CAAC,iBAAAY,SAAA,EACC,uDAAC,cAAW,WAAW,IAAI,YAAY,GACzC;AAAA,gBACA,6CAAC,iBAAAA,SAAA,EACC,uDAAC,cAAW,OAAO,IAAI,SAAS,GAAG,WAAW,IAAI,YAAY,GAChE;AAAA,gBACA,6CAAC,iBAAAA,SAAA,EACC,uDAAC,mBAAAZ,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GACzF,oBAAU,IAAI,WAAW,IAAI,SAAS,GACzC,GACF;AAAA,gBACA,6CAAC,iBAAAY,SAAA,EACE,oBAAU,WAAW,IACpB,6CAAC,mBAAAZ,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,wBAAU,IAE7D,8CAAC,YAAAE,SAAA,EAAI,SAAQ,QAAO,KAAK,KAAK,UAAS,QACpC;AAAA,4BAAU,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,UAC1B,6CAAC,WAAoB,OAAO,OAAO,OAAO,SAA5B,KAAmC,CAClD;AAAA,kBACA,UAAU,SAAS,KAClB;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO,IAAI,UAAU,SAAS,CAAC;AAAA,sBAC/B,MAAM;AAAA,sBACN,OAAO,UAAU,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA;AAAA,kBACrC;AAAA,mBAEJ,GAEJ;AAAA,gBACA,6CAAC,iBAAAU,SAAA,EAAU,OAAM,SACf,wDAAC,YAAAV,SAAA,EAAI,SAAQ,QAAO,gBAAe,YAAW,KAAK,MACjD;AAAA,+DAAC,eAAAY,SAAA,EAAQ,eAAa,MAAC,OAAO,eAAe,+BAA+B,YAAY,WAAU,OAChG,uDAAC,UACC;AAAA,oBAAC,kBAAAC;AAAA,oBAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,eAAe,GAAG;AAAA,sBACjC,UAAU,CAAC;AAAA,sBACX,cAAY,eAAe,+BAA+B;AAAA,sBAC1D,IAAI,kBAAkB,QAAQ;AAAA,sBAE9B,uDAAC,+BAAK,UAAS,SAAQ;AAAA;AAAA,kBACzB,GACF,GACF;AAAA,kBACA,6CAAC,eAAAD,SAAA,EAAQ,eAAa,MAAC,OAAO,WAAW,OAAO,WAAU,OACxD,uDAAC,UACC;AAAA,oBAAC,kBAAAC;AAAA,oBAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,kBAAkB,GAAG;AAAA,sBACpC,UAAU,mBAAmB,WAAW;AAAA,sBACxC,cAAY,WAAW;AAAA,sBACvB,IAAI,kBAAkB,SAAS;AAAA,sBAE9B,uBAAa,iBAAiB,IAAI,OAAO;AAAA;AAAA,kBAC5C,GACF,GACF;AAAA,kBACA,6CAAC,eAAAD,SAAA,EAAQ,eAAa,MAAC,OAAO,eAAe,iCAAiC,cAAc,WAAU,OACpG,uDAAC,UACC;AAAA,oBAAC,kBAAAC;AAAA,oBAAA;AAAA,sBACC,MAAK;AAAA,sBACL,SAAS,MAAM,oBAAoB,GAAG;AAAA,sBACtC,UAAU,CAAC;AAAA,sBACX,cAAY,eAAe,iCAAiC;AAAA,sBAC5D,IAAI,kBAAkB,QAAQ;AAAA,sBAE9B,uDAAC,iCAAO,UAAS,SAAQ;AAAA;AAAA,kBAC3B,GACF,GACF;AAAA,mBACF,GACF;AAAA;AAAA;AAAA,YA7HK;AAAA,UA8HP;AAAA,QAEJ,CAAC;AAAA,MACH;AAEA,aACE,8EACE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,UACE,UACI,kBACA,GAAG,aAAa,MAAM,GAAG,aAAa,OAAO,KAAK,MAAM,KAAK,EAAE,OAAO,aAAa,WAAW,IAAI,KAAK,GAAG;AAAA,YAEhH,OAAK;AAAA,YACL,SACE,8EACE;AAAA;AAAA,gBAAC,iBAAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAM;AAAA,kBACN,aAAY;AAAA,kBACZ,OAAO;AAAA,kBACP,UAAU,OAAK,cAAc,EAAE,OAAO,KAAK;AAAA,kBAC3C,IAAI,EAAE,UAAU,IAAI;AAAA,kBACpB,YAAY;AAAA,oBACV,gBACE,6CAAC,sBAAAC,SAAA,EAAe,UAAS,SACvB,uDAAC,iCAAO,UAAS,SAAQ,OAAM,YAAW,GAC5C;AAAA,kBAEJ;AAAA;AAAA,cACF;AAAA,cACC,YAAY,SAAS,KACpB;AAAA,gBAAC,eAAAC;AAAA,gBAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,OAAM;AAAA,kBACN,WAAW,6CAAC,oCAAU;AAAA,kBACtB,SAAS,MAAM,qBAAqB,YAAY,MAAM;AAAA,kBACtD,IAAI,YAAU;AAAA,oBACZ,OAAO,MAAM,QAAQ,KAAK;AAAA,oBAC1B,aAAa,MAAM,QAAQ;AAAA,oBAC3B,WAAW;AAAA,sBACT,OAAO,MAAM,QAAQ,MAAM;AAAA,sBAC3B,iBAAa,sBAAM,MAAM,QAAQ,MAAM,MAAM,GAAG;AAAA,sBAChD,aAAS,sBAAM,MAAM,QAAQ,MAAM,MAAM,IAAI;AAAA,oBAC/C;AAAA,kBACF;AAAA,kBACD;AAAA;AAAA,oBACiB,YAAY;AAAA,oBAAO;AAAA;AAAA;AAAA,cACrC;AAAA,eAEJ;AAAA,YAGD;AAAA,wBACC,6CAAC,YAAAhB,SAAA,EAAI,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,cAAc,WAAS,aAAa,MAAM,QAAQ,OAAO,GAAG,GACnF;AAAA,gBAAC,YAAAiB;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,OAAO,YAAY,WAAW,YAAY,YAAY,UAAU;AAAA,kBAChE,UAAU;AAAA,kBACV,YAAY,6CAAC,gCAAM;AAAA,kBACnB,SAAQ;AAAA;AAAA,cACV,GACF;AAAA,cAEF,6CAAC,sBAAAC,SAAA,EACC,wDAAC,aAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,6DAAC,iBAAAC,SAAA,EACC,wDAAC,gBAAAX,SAAA,EACC;AAAA,+DAAC,iBAAAC,SAAA,EAAU,eAAe,YAAY,UAAU,gBAAgB,OAC9D,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,SAAS,WAAW,YAAY,UAAU,gBAAgB,OAAO,SAAS,MAAM,WAAW,OAAO,GAAG,mBAAK,GAChJ;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,oBAAM;AAAA,kBACjB,6CAAC,iBAAAA,SAAA,EAAU,eAAe,YAAY,YAAY,gBAAgB,OAChE,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,WAAW,WAAW,YAAY,YAAY,gBAAgB,OAAO,SAAS,MAAM,WAAW,SAAS,GAAG,qBAAO,GACxJ;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,eAAe,YAAY,YAAY,gBAAgB,OAChE,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,WAAW,WAAW,YAAY,YAAY,gBAAgB,OAAO,SAAS,MAAM,WAAW,SAAS,GAAG,qBAAO,GACxJ;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,eAAe,YAAY,WAAW,gBAAgB,OAC/D,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,UAAU,WAAW,YAAY,WAAW,gBAAgB,OAAO,SAAS,MAAM,WAAW,QAAQ,GAAG,oBAAM,GACpJ;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,eAAe,YAAY,WAAW,gBAAgB,OAC/D,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,UAAU,WAAW,YAAY,WAAW,gBAAgB,OAAO,SAAS,MAAM,WAAW,QAAQ,GAAG,iCAAmB,GACjK;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,eAAe,YAAY,WAAW,gBAAgB,OAC/D,uDAAC,sBAAAW,SAAA,EAAe,QAAQ,YAAY,UAAU,WAAW,YAAY,WAAW,gBAAgB,OAAO,SAAS,MAAM,WAAW,QAAQ,GAAG,oBAAM,GACpJ;AAAA,kBACA,6CAAC,iBAAAX,SAAA,EAAU,OAAM,SAAQ,qBAAO;AAAA,mBAClC,GACF;AAAA,gBACA,6CAAC,iBAAAY,SAAA,EACE,0BAAgB,GACnB;AAAA,iBACF,GACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGA;AAAA,UAAC,cAAAC;AAAA,UAAA;AAAA,YACC,MAAM,CAAC,CAAC;AAAA,YACR,SAAS,MAAM,CAAC,mBAAmB,mBAAmB,IAAI;AAAA,YAC1D,UAAS;AAAA,YACT,WAAS;AAAA,YAET;AAAA,2DAAC,mBAAAC,SAAA,EAAY,wBAAU;AAAA,cACvB,6CAAC,qBAAAC,SAAA,EACC,wDAAC,mBAAA3B,SAAA,EAAW;AAAA;AAAA,gBACJ,6CAAC,YAAQ,0BAAgB,mBAAoB,CAAC,CAAgB,GAAE;AAAA,gBAAS;AAAA,iBACjF,GACF;AAAA,cACA,8CAAC,qBAAA4B,SAAA,EACC;AAAA;AAAA,kBAAC,eAAAV;AAAA,kBAAA;AAAA,oBACC,SAAS,MAAM,mBAAmB,IAAI;AAAA,oBACtC,UAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,gBACA;AAAA,kBAAC,eAAAA;AAAA,kBAAA;AAAA,oBACC,SAAS,MAAM,mBAAmB,aAAa,eAAe;AAAA,oBAC9D,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,UAAU;AAAA,oBAET,4BAAkB,6CAAC,wBAAAjB,SAAA,EAAiB,MAAM,IAAI,IAAK;AAAA;AAAA,gBACtD;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGA;AAAA,UAAC,cAAAwB;AAAA,UAAA;AAAA,YACC,MAAM,CAAC,CAAC;AAAA,YACR,SAAS,MAAM,CAAC,oBAAoB,oBAAoB,IAAI;AAAA,YAC5D,UAAS;AAAA,YACT,WAAS;AAAA,YAET;AAAA,4DAAC,mBAAAC,SAAA,EAAY;AAAA;AAAA,gBACJ,6CAAC,YAAQ,6BAAmB,gBAAgB,gBAAgB,IAAI,IAAG;AAAA,gBAAU,oBAAoB,SAAS,gBAAgB,IAAI,cAAS,SAAS,gBAAgB,CAAC,MAAM;AAAA,gBAAG;AAAA,iBACnL;AAAA,cACA,6CAAC,qBAAAC,SAAA,EACC,uDAAC,mBAAA3B,SAAA,EAAW,4GAEZ,GACF;AAAA,cACA,8CAAC,qBAAA4B,SAAA,EACC;AAAA,6DAAC,eAAAV,SAAA,EAAO,SAAS,MAAM,oBAAoB,IAAI,GAAG,UAAU,kBAAkB,oBAE9E;AAAA,gBACA;AAAA,kBAAC,eAAAA;AAAA,kBAAA;AAAA,oBACC,SAAS;AAAA,oBACT,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,UAAU;AAAA,oBAET,6BAAmB,6CAAC,wBAAAjB,SAAA,EAAiB,MAAM,IAAI,IAAK;AAAA;AAAA,gBACvD;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,QAGA;AAAA,UAAC,cAAAwB;AAAA,UAAA;AAAA,YACC,MAAM,sBAAsB;AAAA,YAC5B,SAAS,MAAM,CAAC,mBAAmB,qBAAqB,IAAI;AAAA,YAC5D,UAAS;AAAA,YACT,WAAS;AAAA,YAET;AAAA,2DAAC,mBAAAC,SAAA,EAAY,iCAAmB;AAAA,cAChC,6CAAC,qBAAAC,SAAA,EACC,uDAAC,mBAAA3B,SAAA,EACE,gCAAsB,QAAQ,UAAU,iBAAiB,GAC5D,GACF;AAAA,cACA,8CAAC,qBAAA4B,SAAA,EACC;AAAA,6DAAC,eAAAV,SAAA,EAAO,SAAS,MAAM,qBAAqB,IAAI,GAAG,UAAU,iBAAiB,oBAE9E;AAAA,gBACA;AAAA,kBAAC,eAAAA;AAAA,kBAAA;AAAA,oBACC,SAAS;AAAA,oBACT,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,UAAU;AAAA,oBAET,4BAAkB,6CAAC,wBAAAjB,SAAA,EAAiB,MAAM,IAAI,IAAK;AAAA;AAAA,gBACtD;AAAA,iBACF;AAAA;AAAA;AAAA,QACF;AAAA,SACF;AAAA,IAEJ;AAAA;AAAA;;;ACjoBO,SAAS,gBACd,UACA,UAA6B,CAAC,GACZ;AAClB,QAAM;AAAA,IACJ,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,WAAW;AAAA,EACb,IAAI;AAEJ,QAAM,SAA2B,CAAC;AAGlC,QAAM,SAAS,WAAY,SAAgC,QAAS,SAA8B,cAAc;AAChH,MAAI,CAAC,MAAM,KAAK,GAAG;AACjB,WAAO,QAAQ;AAAA,EACjB;AAIA,MAAI,UAAU;AACZ,UAAM,SAAU,SAAgC;AAChD,QAAI,gBAAgB,CAAC,QAAQ;AAC3B,aAAO,OAAO;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,YAAY,SAAS;AAC3B,MAAI,CAAC,oBAAoB,cAAc,UAAa,cAAc,QAAQ,aAAa,IAAI;AACzF,WAAO,SAAS;AAAA,EAClB;AAEA,SAAO;AACT;AAMO,SAAS,kBACd,QACA,WAAoB,MACL;AACf,QAAM,aAAa,WACf,CAAC,QAAQ,SAAS,UAAU,YAAY,QAAQ,IAChD,CAAC,SAAS,UAAU,QAAQ;AAEhC,aAAW,SAAS,YAAY;AAC9B,QAAI,OAAO,KAA+B,GAAG;AAC3C,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAOO,SAAS,cAAc,UAA8B,MAAY,oBAAI,KAAK,GAAkB;AACjG,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,QAAQ,SAAS,MAAM,iBAAiB;AAC9C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,CAAC,EAAE,UAAU,IAAI,IAAI;AAC3B,QAAM,QAAQ,SAAS,UAAU,EAAE;AACnC,MAAI,MAAM,KAAK,EAAG,QAAO;AAEzB,QAAM,SAAS,IAAI,KAAK,GAAG;AAE3B,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,QAAQ,OAAO,QAAQ,IAAI,KAAK;AACvC;AAAA,IACF,KAAK;AACH,aAAO,QAAQ,OAAO,QAAQ,IAAI,QAAQ,CAAC;AAC3C;AAAA,IACF,KAAK;AACH,aAAO,SAAS,OAAO,SAAS,IAAI,KAAK;AACzC;AAAA,IACF,KAAK;AACH,aAAO,YAAY,OAAO,YAAY,IAAI,KAAK;AAC/C;AAAA,IACF;AACE,aAAO;AAAA,EACX;AAGA,QAAM,QAAQ,OAAO,eAAe,SAAS,EAAE,OAAO,QAAQ,CAAC;AAC/D,QAAM,MAAM,OAAO,QAAQ;AAC3B,QAAM,OAAO,OAAO,YAAY;AAChC,SAAO,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI;AACzC;AAMO,SAAS,mBACd,gBACe;AACf,QAAM,aAAa,eAChB,IAAI,OAAK,EAAE,oBAAoB,EAC/B,OAAO,CAAC,MAAmB,OAAO,MAAM,YAAY,IAAI,CAAC;AAC5D,MAAI,WAAW,WAAW,EAAG,QAAO;AACpC,SAAO,KAAK,IAAI,GAAG,UAAU;AAC/B;AAnIA;AAAA;AAAA;AAAA;AAAA;;;ACuCO,SAAS,qBAAqB,OAAkB,YAAgC;AACrF,aAAO,wDAAe,OAAO,UAAU;AACzC;AAEO,SAAS,gBAAgB,YAAqB,gBAA6C;AAChG,MAAI,WAAY,QAAO;AACvB,MAAI,eAAgB,QAAO;AAC3B,SAAO;AACT;AAEO,SAAS,eAAe,WAAoB,cAA+B;AAChF,MAAI,UAAW,QAAO;AACtB,MAAI,aAAc,QAAO;AACzB,SAAO;AACT;AAEO,SAAS,iBAAiB,eAAwB,gBAA+B,WAAwC;AAC9H,MAAI,iBAAiB,CAAC,UAAW,QAAO;AACxC,MAAI,mBAAmB,KAAM,QAAO,UAAK,OAAO,cAAc,CAAC;AAC/D,SAAO;AACT;AAWO,SAAS,kBACd,UACA,SACA,iBACkB;AAClB,QAAM,MAAwB,CAAC;AAC/B,OAAK,QAAQ,aAAa,SAAS,SAAS,aAAa,KAAK;AAC5D,QAAI,YAAY,QAAQ;AAAA,EAC1B;AACA,MAAI,CAAC,YAAY,QAAQ,QAAQ,SAAS,MAAM,GAAG;AACjD,QAAI,SAAS,QAAQ,UAAU,CAAC;AAAA,EAClC;AACA,QAAM,aAAa,kBAAkB,OAAO,QAAQ;AACpD,OAAK,cAAc,WAAW,SAAS,cAAc,OAAO;AAC1D,QAAI,aAAa;AAAA,EACnB;AACA,MAAI,QAAQ,cAAc,SAAS,UAAW,KAAI,YAAY,QAAQ;AACtE,MAAI,QAAQ,cAAc,SAAS,UAAW,KAAI,YAAY,QAAQ;AACtE,SAAO;AACT;AAzFA,IAEA4B,yCAEM,sBAUO,YAWA,UAqCP;AA9DN;AAAA;AAAA;AACA;AACA,IAAAA,0CAA+B;AAE/B,IAAM,uBAAuB,CAAC,aAA8B;AAC1D,YAAM,QAAQ,YAAY,QACvB,MAAM,GAAG,EAAE,CAAC,EACZ,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,YAAY,EAAE,KAAK;AAC9B,YAAM,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AAClD,aAAO,GAAG,IAAI,IAAI,IAAI;AAAA,IACxB;AAEO,IAAM,aAAa,CAAC,cAA2C;AAAA,MACpE,OAAO,qBAAqB,QAAQ;AAAA,MACpC,QAAQ,CAAC;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,WAAW;AAAA,MACX,SAAS;AAAA,MACT,UAAU;AAAA,IACZ;AAEO,IAAM,WAAW,CAAC,OAAqC;AAAA,MAC5D,WAAW,EAAE,aAAa;AAAA,MAC1B,QAAQ,EAAE,UAAU,CAAC;AAAA,MACrB,YAAY,EAAE;AAAA,MACd,WAAW,EAAE;AAAA,MACb,WAAW,EAAE;AAAA,IACf;AA+BA,IAAM,cAAc,CAAC,IAAc,CAAC,GAAG,IAAc,CAAC,MACpD,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,CAAC,GAAG,MAAM,MAAM,EAAE,CAAC,CAAC;AAAA;AAAA;;;ACtDvD,SAAS,UAAU,KAAqB;AACtC,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAWO,SAAS,cAAc,SAAwB,KAAa,OAAyB;AAC1F,MAAI,CAAC,SAAS;AACZ,UAAM,IAAI,MAAM,wBAAwB;AAAA,EAC1C;AACA,QAAM,OAAO,UAAU,OAAO;AAC9B,QAAM,UAAU,GAAG,IAAI;AACvB,SAAO;AAAA,IACL,gBAAgB;AAAA,IAChB,MAAM,QAAQ,OAAO;AAAA,8BACK,GAAG;AAAA;AAAA;AAAA,gBAGjB,KAAK;AAAA;AAAA;AAAA,IAGjB,QAAQ;AAAA;AAAA;AAAA,aAGC,GAAG;AAAA,cACF,OAAO;AAAA;AAAA;AAAA;AAAA,WAIV,KAAK;AAAA;AAAA;AAAA;AAAA,IAIZ,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAOQ,OAAO;AAAA,qBACR,GAAG;AAAA;AAAA;AAAA,WAGb,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA,IAKZ,IAAI;AAAA;AAAA,kBAEU,OAAO;AAAA,iBACR,GAAG;AAAA;AAAA;AAAA,iBAGH,KAAK,eAAe,KAAK;AAAA;AAAA;AAAA;AAAA,IAItC,YAAY;AAAA,+BACe,GAAG;AAAA,6BACL,IAAI;AAAA,iBAChB,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBpB;AACF;AAjGA,IAAAC,eACAC,aACAC,oBACAC,oBACA,aACA,YACAC,iBACAC,wBAiHMC,qBAbA,oBAMO;AAjHb;AAAA;AAAA;AAAA,IAAAN,gBAA6B;AAC7B,IAAAC,cAAgB;AAChB,IAAAC,qBAAuB;AACvB,IAAAC,qBAAuB;AACvB,kBAAiB;AACjB,iBAAgB;AAChB,IAAAC,kBAAoB;AACpB,IAAAC,yBAAmC;AAiH7B,IAAAC,sBAAA;AAbN,IAAM,qBAA0D;AAAA,MAC9D,UAAU;AAAA,MACV,IAAI;AAAA,MACJ,eAAe;AAAA,IACjB;AAEO,IAAM,cAAoC,CAAC,EAAE,UAAU,OAAO,UAAU,MAAM;AACnF,YAAM,CAAC,KAAK,MAAM,QAAI,wBAAqB,MAAM;AACjD,YAAM,aAAa,QAAQ,gBAAgB,eAAe;AAC1D,YAAM,OAAO,SAAS,UAA4B;AAClD,YAAM,WAAW,mBAAmB,GAAG;AACvC,aACE,8CAAC,YAAAC,SAAA,EACC;AAAA,sDAAC,YAAAC,SAAA,EAAK,OAAO,KAAK,UAAU,CAAC,GAAG,MAAM,OAAO,CAAe,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG,SAAQ,cACpF;AAAA,uDAAC,WAAAC,SAAA,EAAI,OAAM,QAAO,OAAM,QAAO;AAAA,UAC/B,6CAAC,WAAAA,SAAA,EAAI,OAAM,cAAa,OAAM,UAAS;AAAA,UACvC,6CAAC,WAAAA,SAAA,EAAI,OAAM,YAAW,OAAM,YAAW;AAAA,UACvC,6CAAC,WAAAA,SAAA,EAAI,OAAM,MAAK,OAAM,MAAK;AAAA,UAC3B,6CAAC,WAAAA,SAAA,EAAI,OAAM,eAAc,OAAM,eAAc;AAAA,WAC/C;AAAA,QACC,YACC,6CAAC,mBAAAC,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAAQ,IAAI,KACtE,oBACH;AAAA,QAEF;AAAA,UAAC,YAAAH;AAAA,UAAA;AAAA,YACC,UAAS;AAAA,YACT,GAAG;AAAA,YACH,IAAI,EAAE,iBAAiB,gBAAgB,QAAQ,aAAa,aAAa,WAAW,cAAc,EAAE;AAAA,YAEpG;AAAA,2DAAC,gBAAAI,SAAA,EAAQ,OAAO,UAAU,SAAS,WAAW,gBAAgB,WAAU,OACtE;AAAA,gBAAC,mBAAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAS,MAAM,UAAU,KAAK,IAAI;AAAA,kBAClC,cAAW;AAAA,kBACX,IAAI,EAAE,UAAU,YAAY,KAAK,GAAG,OAAO,EAAE;AAAA,kBAE5C,oBAAU,SAAS,6CAAC,gCAAM,UAAS,SAAQ,IAAK,6CAAC,sCAAY,UAAS,SAAQ;AAAA;AAAA,cACjF,GACF;AAAA,cACA;AAAA,gBAAC,mBAAAF;AAAA,gBAAA;AAAA,kBACC,WAAU;AAAA,kBACV,IAAI;AAAA,oBACF,YAAY;AAAA,oBACZ,UAAU;AAAA,oBACV,YAAY;AAAA,oBACZ,WAAW;AAAA,oBACX,IAAI;AAAA,oBACJ,IAAI;AAAA,kBACN;AAAA,kBAEC;AAAA;AAAA,cACH;AAAA,cACC,SACC,8CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAAQ,IAAI,GAAG;AAAA;AAAA,gBAC5D;AAAA,gBAAM;AAAA,iBACtB;AAAA;AAAA;AAAA,QAEJ;AAAA,SACF;AAAA,IAEJ;AAAA;AAAA;;;ACgqBA,SAAS,QAAQ,UAAkC;AACjD,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,QAAQ,WAAW;AACzB,SAAO,QAAQ,OAAO,KAAK,WAAW,KAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,MAAM,QAAQ,CAAC,CAAC;AACxF;AAEA,SAAS,oBACP,UACA,WACe;AACf,MAAI,CAAC,YAAY,CAAC,UAAW,QAAO;AACpC,QAAM,MAAM,CAAC,MAAe;AAC1B,QAAI,CAAC,EAAG,QAAO;AACf,QAAI,KAAK,IAAW,QAAO,IAAI,IAAI,KAAW,QAAQ,CAAC,CAAC;AACxD,QAAI,KAAK,IAAO,QAAO,GAAG,KAAK,MAAM,IAAI,GAAI,CAAC;AAC9C,WAAO,OAAO,CAAC;AAAA,EACjB;AACA,QAAM,SAAS,IAAI,QAAQ;AAC3B,QAAM,UAAU,IAAI,SAAS;AAC7B,MAAI,UAAU,QAAS,QAAO,OAAO,MAAM,SAAS,OAAO;AAC3D,MAAI,OAAQ,QAAO,OAAO,MAAM;AAChC,MAAI,QAAS,QAAO,OAAO,OAAO;AAClC,SAAO;AACT;AA/1BA,IAAAG,eACAC,aACAC,oBACAC,gBACAC,qBACAC,uBACAC,uBACAC,mBACA,iBACAC,gBACAC,oBACAC,0BACA,qBACA,iBACA,yBACA,cACA,kBACA,yBACA,yBACAC,iBACAC,wBACAC,cACAC,wBACAC,iCAUAC,yCAyWQC,sBAnTK;AAvFb;AAAA;AAAA;AAAA,IAAAjB,gBAAyD;AACzD,IAAAC,cAAgB;AAChB,IAAAC,qBAAuB;AACvB,IAAAC,iBAAmB;AACnB,IAAAC,sBAAwB;AACxB,IAAAC,wBAA0B;AAC1B,IAAAC,wBAA0B;AAC1B,IAAAC,oBAAsB;AACtB,sBAAqB;AACrB,IAAAC,iBAAmB;AACnB,IAAAC,qBAAuB;AACvB,IAAAC,2BAA6B;AAC7B,0BAAyB;AACzB,sBAAqB;AACrB,8BAA6B;AAC7B,mBAAkB;AAClB,uBAAsB;AACtB,8BAA6B;AAC7B,8BAA6B;AAC7B,IAAAC,kBAAoB;AACpB,IAAAC,yBAA2B;AAC3B,IAAAC,eAAiB;AACjB,IAAAC,yBAAqD;AACrD,IAAAC,kCAA8B;AAU9B,IAAAC,0CAA2F;AAC3F;AACA;AACA;AAgBA;AASA;AA6UQ,IAAAC,uBAAA;AAnTD,IAAM,gBAAwC,CAAC;AAAA,MACpD;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,WAAW,SAAS;AAC1B,YAAM,CAAC,cAAc,eAAe,QAAI,wBAA6B,WAAW,QAAQ,CAAC;AACzF,YAAM,CAAC,eAAe,gBAAgB,QAAI,wBAA2B,CAAC,CAAC;AACvE,YAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,KAAK;AAC5D,YAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,YAAM,CAAC,aAAa,cAAc,QAAI,wBAAwB,IAAI;AAClE,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,wBAA0B,IAAI;AAC1E,YAAM,CAAC,aAAa,cAAc,QAAI,wBAAiB,EAAE;AACzD,YAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAwB,IAAI;AACtE,YAAM,CAAC,WAAW,YAAY,QAAI,wBAAwB,IAAI;AAC9D,YAAM,CAAC,mBAAmB,oBAAoB,QAAI,wBAAS,KAAK;AAChE,YAAM,CAAC,sBAAsB,uBAAuB,QAAI,wBAAS,KAAK;AACtE,YAAM,CAAC,QAAQ,SAAS,QAAI,wBAA+B,IAAI;AAC/D,YAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AACtD,YAAM,CAAC,yBAAyB,0BAA0B,QAAI,wBAAS,KAAK;AAC5E,YAAM,CAAC,SAAS,UAAU,QAAI,wBAAkC,CAAC,CAAC;AAClE,YAAM,CAAC,iBAAiB,kBAAkB,QAAI,wBAAS,KAAK;AAG5D,YAAM,mBAAe,sBAAyB,IAAI;AAClD,YAAM,oBAAgB,sBAAyB,IAAI;AACnD,YAAM,qBAAiB,sBAAyB,IAAI;AAGpD,YAAM,kBAAkB,mBAAmB;AAC3C,YAAM,mBAAmB,mBAAmB;AAC5C,YAAM,oBAAoB,mBAAmB;AAG7C,YAAM,2BAAuB,+CAAc,EAAE,YAAY,uEAA+B,CAAC;AACzF,YAAM,gBAAgB,CAAC,qBAAqB,WAAW,qBAAqB;AAI5E,mCAAU,MAAM;AACd,YAAI,MAAM;AACR,cAAI,UAAU;AACZ,4BAAgB,WAAW,QAAQ,CAAC;AAAA,UACtC,WAAW,WAAW;AACpB,6BAAiB,SAAS,SAAS,CAAC;AACpC;AAAA,cACE,uBAAuB,yBAAyB,SAC7C,UAAU,eAAe,QAAQ,UAAU,eAAe;AAAA,YAC/D;AAAA,UACF,OAAO;AACL,6BAAiB,CAAC,CAAC;AACnB,+BAAmB,KAAK;AAAA,UAC1B;AACA,yBAAe,IAAI;AACnB,4BAAkB,IAAI;AACtB,yBAAe,EAAE;AACjB,2BAAiB,IAAI;AACrB,uBAAa,IAAI;AACjB,+BAAqB,KAAK;AAC1B,0BAAgB,KAAK;AACrB,qCAA2B,KAAK;AAChC,qBAAW,CAAC,CAAC;AACb,6BAAmB,KAAK;AAAA,QAC1B;AAAA,MACF,GAAG,CAAC,MAAM,UAAU,WAAW,UAAU,uBAAuB,oBAAoB,CAAC;AAOrF,YAAM,qBAAiB,sBAAO,WAAW;AACzC,qBAAe,UAAU;AACzB,mCAAU,MAAM;AACd,YAAI,CAAC,KAAM,QAAO;AAClB,YAAI,YAAY;AAChB,uBAAe,QAAQ,EACpB,KAAK,OAAK;AAAE,cAAI,CAAC,UAAW,WAAU,CAAC;AAAA,QAAG,CAAC,EAC3C,MAAM,MAAM;AAAE,cAAI,CAAC,UAAW,WAAU,IAAI;AAAA,QAAG,CAAC;AACnD,eAAO,MAAM;AAAE,sBAAY;AAAA,QAAM;AAAA,MACnC,GAAG,CAAC,IAAI,CAAC;AAET,YAAM,uBAAuB,uBAAuB,wBAAwB;AAC5E,YAAM,eAAe,uBAAuB,gBAAgB;AAE5D,YAAM,WAAW,WAAW,eAAe;AAC3C,YAAM,cAAc,CAAC,UAAmE;AACtF,YAAI,UAAU;AACZ,0BAAgB,WAAS,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,QACjD,OAAO;AACL,2BAAiB,WAAS,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE;AAAA,QAClD;AAAA,MACF;AAIA,YAAM,gBAAgB,WAAW,aAAa,QAAQ,cAAc,cAAc;AAClF,YAAM,gBAAgB,CAAC,UAAkB;AACvC,YAAI,SAAU,aAAY,EAAE,OAAO,MAAM,CAAC;AAAA,YACrC,aAAY,EAAE,WAAW,MAAM,CAAC;AAAA,MACvC;AAEA,YAAM,eAAe,MAAM,KAAK,OAAK,EAAE,aAAa,WAAW,aAAa,UAAU,OAAU,KAAK;AAIrG,YAAM,kBAAkB,WAAW,aAAa,UAAU,WAAW;AACrE,YAAM,gBAAgB,MAAM,KAAK,OAAK,EAAE,YAAY,eAAe,KAAK;AAMxE,YAAM,sBAAkB,uBAAQ,MAAM;AACpC,eAAO,OAAO,OAAO,OAAK,qBAAqB,GAAG,eAAe,MAAM,CAAC;AAAA,MAC1E,GAAG,CAAC,QAAQ,aAAa,CAAC;AAE1B,YAAM,iBAAiB,gBAAgB,OAAO,QAAM,SAAS,UAAU,CAAC,GAAG,SAAS,EAAE,UAAU,CAAC;AAGjG,YAAM,mBAAmB,gBAAgB,UAAU;AAAA,QACjD;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAGD,YAAM,YAAY,CAAC,UAAkB,QAAQ,KAAK,KAAK;AACvD,YAAM,aAAa,UAAU,OAAO,KAAK,CAAC,CAAC,iBAAiB;AAC5D,YAAM,YAAY,UAAU,MAAM,KAAK,CAAC,CAAC,iBAAiB;AAC1D,YAAM,gBAAgB,UAAU,QAAQ,KAAK,CAAC,CAAC,iBAAiB;AAIhE,YAAM,iBAAiB,CAAC,CAAC,gBAAgB,KAAK,KAAK,OAAK,EAAE,cAAc,gBAAgB,MAAM,SAAS;AAGvG,YAAM,qBAAiB,uBAAQ,MAAM;AACnC,YAAI,mBAAmB,cAAe,QAAO;AAC7C,cAAM,gBAAgB,mBAAmB,cAAc;AACvD,YAAI,kBAAkB,KAAM,QAAO;AACnC,eAAO,yBAAyB,SAAS,cAAc,GAAG,aAAa;AAAA,MACzE,GAAG,CAAC,SAAS,YAAY,gBAAgB,iBAAiB,aAAa,CAAC;AAExE,YAAM,iBAAiB,YAAY;AAEjC,cAAM,SAAS,gBAAgB,cAAc;AAAA,UAC3C;AAAA,UACA;AAAA,UACA,UAAU;AAAA,QACZ,CAAC;AAED,YAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,6BAAmB,IAAI;AAEvB,gBAAM,eAAe,kBAAkB,QAAQ,IAAI;AACnD,cAAI,iBAAiB,UAAU,aAAa,SAAS;AACnD,yBAAa,QAAQ,MAAM;AAAA,UAC7B,WAAW,iBAAiB,WAAW,cAAc,SAAS;AAC5D,0BAAc,QAAQ,MAAM;AAAA,UAC9B,WAAW,iBAAiB,YAAY,eAAe,SAAS;AAC9D,2BAAe,QAAQ,MAAM;AAAA,UAC/B;AACA;AAAA,QACF;AAEA,sBAAc,IAAI;AAClB,yBAAiB,IAAI;AACrB,YAAI;AACF,gBAAM,UAA8B;AAAA,YAClC,GAAI;AAAA,YACJ,YAAY,kBAAkB,OAAO,aAAa;AAAA,UACpD;AACA,gBAAM,WAAW,MAAM,YAAY,OAAO;AAI1C,gBAAM,QAAQ,aAAa,SAAS,CAAC,KAAK,gBAAgB,CAAC,GAAG,cAAc;AAC5E,yBAAe,SAAS,GAAG;AAC3B,yBAAe,KAAK;AACpB,4BAAkB,IAAI;AACtB,cAAI;AACF,kBAAM,gBAAgB,MAAM,YAAY;AACxC,gBAAI,cAAc,SAAS;AACzB,gCAAkB,cAAc,cAAc,SAAS,SAAS,KAAK,KAAK,CAAC;AAAA,YAC7E;AAAA,UACF,QAAQ;AAAA,UAER;AACA,0BAAgB,WAAW,QAAQ,CAAC;AACpC,6BAAmB,KAAK;AAAA,QAC1B,SAAS,OAAY;AACnB,2BAAiB,OAAO,WAAW,wBAAwB;AAAA,QAC7D,UAAE;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,eAAe,YAAY;AAC/B,YAAI,CAAC,UAAW;AAGhB,cAAM,SAAS,gBAAgB,eAAe;AAAA,UAC5C;AAAA,UACA;AAAA,UACA,UAAU;AAAA,QACZ,CAAC;AAED,YAAI,OAAO,KAAK,MAAM,EAAE,SAAS,GAAG;AAClC,6BAAmB,IAAI;AAEvB,gBAAM,eAAe,kBAAkB,QAAQ,KAAK;AACpD,cAAI,iBAAiB,WAAW,cAAc,SAAS;AACrD,0BAAc,QAAQ,MAAM;AAAA,UAC9B,WAAW,iBAAiB,YAAY,eAAe,SAAS;AAC9D,2BAAe,QAAQ,MAAM;AAAA,UAC/B;AACA;AAAA,QACF;AAEA,sBAAc,IAAI;AAClB,qBAAa,IAAI;AACjB,YAAI;AACF,gBAAM,UAAU,kBAAkB,SAAS,SAAS,GAAG,eAAe,eAAe;AACrF,cAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,kBAAM,YAAY,UAAU,SAAS,UAAU,KAAK,OAAO;AAAA,UAC7D;AACA,kBAAQ;AAAA,QACV,SAAS,OAAY;AACnB,uBAAa,OAAO,WAAW,sBAAsB;AAAA,QACvD,UAAE;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,mBAAmB,YAAY;AACnC,YAAI,CAAC,aAAa,CAAC,gBAAiB;AACpC,gCAAwB,IAAI;AAC5B,YAAI;AACF,gBAAM,gBAAgB,UAAU,SAAS,UAAU,GAAG;AACtD,+BAAqB,KAAK;AAC1B,kBAAQ;AAAA,QACV,SAAS,GAAQ;AAEf,+BAAqB,KAAK;AAC1B,uBAAa,GAAG,WAAW,uBAAuB;AAAA,QACpD,UAAE;AACA,kCAAwB,KAAK;AAAA,QAC/B;AAAA,MACF;AAEA,YAAM,4BAA4B,MAAM;AACtC,gBAAQ;AACR,yBAAiB,IAAI;AACrB,qBAAa,IAAI;AACjB,uBAAe,IAAI;AACnB,0BAAkB,IAAI;AACtB,wBAAgB,WAAW,QAAQ,CAAC;AACpC,yBAAiB,CAAC,CAAC;AACnB,2BAAmB,KAAK;AACxB,6BAAqB,KAAK;AAC1B,wBAAgB,KAAK;AACrB,mCAA2B,KAAK;AAAA,MAClC;AAGA,YAAM,0BAA0B,MAAM;AACpC,YAAI,eAAe,CAAC,cAAc;AAEhC,qCAA2B,IAAI;AAAA,QACjC,OAAO;AACL,oCAA0B;AAAA,QAC5B;AAAA,MACF;AAEA,YAAM,gCAAgC,MAAM;AAC1C,mCAA2B,KAAK;AAChC,kCAA0B;AAAA,MAC5B;AAGA,YAAM,oBAAoB,CAAC,QAAiB,WAAmB;AAE7D,YAAI,gBAAgB,WAAW,mBAAmB,WAAW,kBAAkB;AAC7E;AAAA,QACF;AACA,gCAAwB;AAAA,MAC1B;AAEA,YAAM,cAAc,CAAC,MAAiB;AACpC,cAAM,SAAS,QAAQ,EAAE,oBAAoB;AAC7C,cAAM,UAAU,QAAQ,EAAE,qBAAqB;AAC/C,cAAM,MAAM,oBAAoB,EAAE,kBAAkB,EAAE,iBAAiB;AACvE,eACE,+CAAC,YAAAC,SAAA,EACC;AAAA,yDAAC,YAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,KAAK,IAAI,IAAI,GAClE;AAAA,0DAAC,UAAM,YAAE,YAAW;AAAA,YACnB,EAAE,6BAA6B,8CAAC,aAAAC,SAAA,EAAK,MAAK,SAAQ,SAAQ,YAAW,OAAM,SAAQ;AAAA,YACnF,EAAE,mBAAmB,8CAAC,aAAAA,SAAA,EAAK,MAAK,SAAQ,SAAQ,YAAW,OAAM,UAAS;AAAA,aAC7E;AAAA,UACC,OACC,8CAAC,mBAAAC,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAC9D,eACH;AAAA,WAEA,UAAU,YACV,+CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAC9D;AAAA;AAAA,YAAO;AAAA,YAAO;AAAA,YAAQ;AAAA,aACzB;AAAA,WAEJ;AAAA,MAEJ;AAEA,YAAM,kBAAkB,MAAM;AAC5B,YAAI,MAAM,SAAS,GAAG;AACpB,iBACE;AAAA,YAAC,oBAAAC;AAAA,YAAA;AAAA,cACC,SAAS;AAAA,cACT,gBAAgB,OAAK,EAAE,cAAc,EAAE;AAAA,cACvC,OAAO;AAAA,cACP,UAAU,CAAC,IAAI,SAAS;AACtB,sBAAM,oBAAoB,SAAS,UAAU,CAAC,GAAG,OAAO,UAAQ;AAC9D,wBAAM,QAAQ,OAAO,KAAK,OAAK,EAAE,eAAe,IAAI;AACpD,yBAAO,QAAQ,qBAAqB,OAAO,MAAM,MAAM,IAAI;AAAA,gBAC7D,CAAC;AACD,4BAAY,EAAE,SAAS,MAAM,SAAS,QAAQ,iBAAiB,CAAC;AAAA,cAClE;AAAA,cACA,UAAU,CAAC;AAAA,cACX,QAAQ,MAAM,WAAW,WAAS,EAAE,GAAG,MAAM,MAAM,KAAK,EAAE;AAAA,cAC1D,aAAa,YACX;AAAA,gBAAC,kBAAAC;AAAA,gBAAA;AAAA,kBACE,GAAG;AAAA,kBACJ,UAAU;AAAA,kBACV,OAAM;AAAA,kBACN,OAAO;AAAA,kBACP,YACE,WACI,eAAe,WAAW,YAAY,IACtC;AAAA,kBAEN,UAAU,YAAY;AAAA,kBACtB,WAAS;AAAA;AAAA,cACX;AAAA;AAAA,UAEJ;AAAA,QAEJ;AACA,YAAI,gBAAgB,UAAU;AAC5B,iBACE,8CAAC,mBAAAF,SAAA,EAAW,SAAQ,SAAQ,OAAM,SAAQ,iHAE1C;AAAA,QAEJ;AACA,eAAO;AAAA,MACT;AAEA,YAAM,YAAY,WAAW,SAAS,WAAW,OAAO;AAExD,YAAM,mBAAmB,MAAM;AAC7B,YAAI,YAAY,CAAC,gBAAiB,QAAO;AAEzC,YAAI,CAAC,QAAQ,YAAY,wBAAwB,CAAC,cAAe,QAAO;AACxE,eACE,+CAAC,YAAAF,SAAA,EAAI,IAAI,GAAG,IAAI,GAAG,WAAU,aAAY,IAAI,EAAE,aAAa,UAAU,GACpE;AAAA,wDAAC,mBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAAQ,IAAI,GAAG,yBAE5E;AAAA,UACC,CAAC,oBACA;AAAA,YAAC,eAAAG;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAM;AAAA,cACN,SAAQ;AAAA,cACR,SAAS,MAAM,qBAAqB,IAAI;AAAA,cACzC;AAAA;AAAA,UAED,IAEA,+CAAC,YAAAL,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,GAAG,UAAS,QACvD;AAAA,0DAAC,mBAAAE,SAAA,EAAW,SAAQ,SAAQ,OAAM,gBAAe,qCAEjD;AAAA,YACA;AAAA,cAAC,eAAAG;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,SAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,SAAS;AAAA,gBAER,iCAAuB,8CAAC,yBAAAC,SAAA,EAAiB,MAAM,IAAI,IAAK;AAAA;AAAA,YAC3D;AAAA,YACA,8CAAC,eAAAD,SAAA,EAAO,MAAK,SAAQ,SAAS,MAAM,qBAAqB,KAAK,GAAG,oBAEjE;AAAA,aACF;AAAA,WAEJ;AAAA,MAEJ;AAEA,YAAM,UAAU,CAAC,QAAwB;AACvC,YAAI,IAAI,UAAU,EAAG,QAAO;AAC5B,eAAO,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;AAAA,MAC9C;AAEA,UAAI,cAAc;AAClB,UAAI,YAAa,eAAc;AAAA,eACtB,SAAU,eAAc;AAEjC,YAAM,cAAc,WAAW,aAAa;AAC5C,aACE;AAAA,QAAC,eAAAE;AAAA,QAAA;AAAA,UACC;AAAA,UACA,SAAS;AAAA,UACT,sBAAsB,CAAC,CAAC;AAAA,UACxB,UAAS;AAAA,UACT,WAAS;AAAA,UAET;AAAA,0DAAC,oBAAAC,SAAA,EAAa,uBAAY;AAAA,YAC1B,8CAAC,sBAAAC,SAAA,EACE,wBACC,+CAAC,YAAAT,SAAA,EACC;AAAA,4DAAC,aAAAU,SAAA,EAAM,UAAS,WAAU,IAAI,EAAE,IAAI,EAAE,GAAG,8DAEzC;AAAA,cACA;AAAA,gBAAC,YAAAV;AAAA,gBAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,YAAW;AAAA,kBACX,KAAK;AAAA,kBACL,IAAI;AAAA,kBACJ,GAAG;AAAA,kBACH,IAAI;AAAA,oBACF,iBAAiB;AAAA,oBACjB,QAAQ;AAAA,oBACR,aAAa;AAAA,oBACb,cAAc;AAAA,kBAChB;AAAA,kBAEA;AAAA;AAAA,sBAAC,mBAAAE;AAAA,sBAAA;AAAA,wBACC,WAAU;AAAA,wBACV,OAAM;AAAA,wBACN,IAAI,EAAE,YAAY,aAAa,WAAW,aAAa,MAAM,EAAE;AAAA,wBAE9D;AAAA;AAAA,oBACH;AAAA,oBACA,8CAAC,gBAAAS,SAAA,EAAQ,OAAO,gBAAgB,SAAS,WAAW,gBAAgB,WAAU,OAC5E;AAAA,sBAAC,mBAAAC;AAAA,sBAAA;AAAA,wBACC,cAAW;AAAA,wBACX,SAAS,YAAY;AACnB,gCAAM,UAAU,MAAM,gBAAgB,KAAK,WAAW;AACtD,8BAAI,SAAS;AACX,4CAAgB,IAAI;AAAA,0BACtB;AAAA,wBACF;AAAA,wBAEC,0BAAgB,SAAS,8CAAC,gCAAM,IAAK,8CAAC,sCAAY;AAAA;AAAA,oBACrD,GACF;AAAA;AAAA;AAAA,cACF;AAAA,cAEC,eAAe,CAAC,kBACf,+CAAC,YAAAZ,SAAA,EAAI,IAAI,GACP;AAAA,8DAAC,mBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAAQ,cAAY,MAAC,6BAElF;AAAA,gBACA,8CAAC,mBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,qCAEnD;AAAA,iBACF;AAAA,cAGD,kBACC,+CAAC,YAAAF,SAAA,EAAI,IAAI,GACP;AAAA,8DAAC,mBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAAQ,cAAY,MAAC,oFAElF;AAAA,gBACA;AAAA,kBAAC,YAAAF;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,YAAW;AAAA,oBACX,KAAK;AAAA,oBACL,GAAG;AAAA,oBACH,IAAI;AAAA,sBACF,iBAAiB;AAAA,sBACjB,QAAQ;AAAA,sBACR,aAAa;AAAA,sBACb,cAAc;AAAA,oBAChB;AAAA,oBAEA;AAAA;AAAA,wBAAC,mBAAAE;AAAA,wBAAA;AAAA,0BACC,WAAU;AAAA,0BACV,OAAM;AAAA,0BACN,IAAI,EAAE,YAAY,aAAa,UAAU,IAAI,WAAW,aAAa,MAAM,EAAE;AAAA,0BAE5E,yBAAe;AAAA;AAAA,sBAClB;AAAA,sBACA,8CAAC,gBAAAS,SAAA,EAAQ,OAAO,kBAAkB,SAAS,WAAW,iBAAiB,WAAU,OAC/E;AAAA,wBAAC,mBAAAC;AAAA,wBAAA;AAAA,0BACC,MAAK;AAAA,0BACL,cAAW;AAAA,0BACX,SAAS,MAAM,kBAAkB,KAAK,eAAe,cAAc;AAAA,0BAElE,4BAAkB,SAAS,8CAAC,gCAAM,UAAS,SAAQ,IAAK,8CAAC,sCAAY,UAAS,SAAQ;AAAA;AAAA,sBACzF,GACF;AAAA;AAAA;AAAA,gBACF;AAAA,iBACF;AAAA,cAGD,kBACC,+CAAC,YAAAZ,SAAA,EAAI,IAAI,GACP;AAAA,+DAAC,YAAAA,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,GAAG,IAAI,GAClD;AAAA,gEAAC,+BAAK,UAAS,SAAQ,OAAM,UAAS;AAAA,kBACtC,8CAAC,mBAAAE,SAAA,EAAW,SAAQ,aAAY,0DAEhC;AAAA,mBACF;AAAA,gBACA,8CAAC,eAAY,UAAU,gBAAgB,OAAO,aAAa,WAAW,kBAAkB;AAAA,iBAC1F;AAAA,eAEJ,IAEA,+CAAC,YAAAF,SAAA,EAAI,SAAQ,QAAO,eAAc,UAAS,KAAK,GAAG,IAAI,GACpD;AAAA,eAAC,YACA,8CAAC,mBAAAE,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAChC,wDAAC,UAAK,OAAO,EAAE,YAAY,aAAa,OAAO,UAAU,GAAI,kBAAQ,SAAS,GAAE,GAClF;AAAA,cAED,iBACC,8CAAC,aAAAQ,SAAA,EAAM,UAAS,SAAQ,SAAS,MAAM,iBAAiB,IAAI,GACzD,yBACH;AAAA,cAED,aACC,8CAAC,aAAAA,SAAA,EAAM,UAAS,SAAQ,SAAS,MAAM,aAAa,IAAI,GACrD,qBACH;AAAA,cAID,gBAAgB;AAAA,eAEf,gBAAgB,SAAS,KAAK,gBAC9B,gFACG;AAAA,8BACC;AAAA,kBAAC,kBAAAN;AAAA,kBAAA;AAAA,oBACC,OAAM;AAAA,oBACN,UAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,YAAW;AAAA,oBACX,WAAS;AAAA;AAAA,gBACX,IAEA;AAAA,kBAAC,oBAAAD;AAAA,kBAAA;AAAA,oBACC,UAAQ;AAAA,oBACR,SAAS;AAAA,oBACT,SAAS,OAAK,EAAE,QAAQ;AAAA,oBACxB,gBAAgB,OAAK,EAAE;AAAA,oBACvB,OAAO;AAAA,oBACP,UAAU,CAAC,IAAI,aACb,YAAY,EAAE,QAAQ,SAAS,IAAI,OAAK,EAAE,UAAU,EAAE,CAAC;AAAA,oBAEzD,cAAc,CAAC,OAAO,MAAM,8CAAC,QAAI,GAAG,OAAQ,sBAAY,CAAC,GAAE;AAAA,oBAC3D,aAAa,YACX;AAAA,sBAAC,kBAAAC;AAAA,sBAAA;AAAA,wBACE,GAAG;AAAA,wBACJ,OAAM;AAAA,wBACN,YACE,gBACI,2DACA;AAAA,wBAEN,WAAS;AAAA;AAAA,oBACX;AAAA;AAAA,gBAEJ;AAAA,gBAED,eAAe,iBACd,8CAAC,eAAAC,SAAA,EAAO,MAAK,SAAQ,SAAS,eAAe,mBAE7C;AAAA,iBAEJ;AAAA,cAGD,wBACC;AAAA,gBAAC,wBAAAQ;AAAA,gBAAA;AAAA,kBACC,SACE;AAAA,oBAAC,gBAAAC;AAAA,oBAAA;AAAA,sBACC,SAAS;AAAA,sBACT,UAAU,CAAC,MAAM;AACf,2CAAmB,EAAE,OAAO,OAAO;AACnC,4BAAI,EAAE,OAAO,SAAS;AACpB,sCAAY,EAAE,YAAY,KAAK,CAAC;AAAA,wBAClC,OAAO;AACL,sCAAY,EAAE,YAAY,cAAc,cAAc,aAAa,cAAc,IAAI,CAAC;AAAA,wBACxF;AAAA,sBACF;AAAA;AAAA,kBACF;AAAA,kBAEF,OAAM;AAAA;AAAA,cACR;AAAA,cAEF;AAAA,gBAAC,kBAAAV;AAAA,gBAAA;AAAA,kBACC,UAAU;AAAA,kBACV,OAAM;AAAA,kBACN,MAAK;AAAA,kBACL,OAAO,kBAAkB,KAAK,SAAS,cAAc;AAAA,kBACrD,UAAU,CAAC,MAAM;AACf,gCAAY,EAAE,YAAY,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,KAAK,IAAI,OAAU,CAAC;AAC/E,qCAAiB,IAAI;AACrB,iCAAa,IAAI;AAAA,kBACnB;AAAA,kBACA,QAAQ,MAAM,WAAW,WAAS,EAAE,GAAG,MAAM,QAAQ,KAAK,EAAE;AAAA,kBAC5D,OAAO;AAAA,kBACP,YAAY,iBAAiB,eAAe,gBAAgB,eAAe;AAAA,kBAC3E,UAAU;AAAA,kBACV,UAAQ;AAAA,kBACR,WAAS;AAAA,kBACT,YAAY;AAAA,oBACV,gBAAgB,8CAAC,uBAAAW,SAAA,EAAe,UAAS,SAAQ,eAAC;AAAA,kBACpD;AAAA,kBACA,YAAY,EAAE,KAAK,GAAG,MAAM,KAAK;AAAA;AAAA,cACnC;AAAA,cAEC,CAAC,WAAW,OACX,gFACE;AAAA;AAAA,kBAAC,kBAAAX;AAAA,kBAAA;AAAA,oBACC,QAAM;AAAA,oBACN,OAAM;AAAA,oBACN,OAAO,aAAa,YAAY;AAAA,oBAChC,UAAU,CAAC,MAAM,YAAY,EAAE,UAAU,EAAE,OAAO,MAAM,CAAC;AAAA,oBACzD,WAAS;AAAA,oBAER,wEAAsB,IAAI,CAAC,aAC1B,8CAAC,gBAAAY,SAAA,EAAwB,OAAO,UAC7B,2EAAoB,QAAQ,KADhB,QAEf,CACD;AAAA;AAAA,gBACH;AAAA,gBACC,aAAa,YACZ,8CAAC,mBAAAd,SAAA,EAAW,SAAQ,WAAU,OAAM,kBACjC,wBAAc,aAAa,QAAQ,GACtC;AAAA,iBAEJ;AAAA,cAGF;AAAA,gBAAC,kBAAAE;AAAA,gBAAA;AAAA,kBACC,UAAU;AAAA,kBACV,OAAM;AAAA,kBACN,OAAO;AAAA,kBACP,UAAU,CAAC,MAAM;AACf,kCAAc,EAAE,OAAO,KAAK;AAC5B,qCAAiB,IAAI;AACrB,iCAAa,IAAI;AAAA,kBACnB;AAAA,kBACA,QAAQ,MAAM,WAAW,WAAS,EAAE,GAAG,MAAM,OAAO,KAAK,EAAE;AAAA,kBAC3D,OAAO;AAAA,kBACP,OAAO,iBAAiB,YAAY;AAAA,kBACpC,YAAY,gBAAgB,YAAY,cAAc;AAAA,kBACtD,UAAQ;AAAA,kBACR,WAAS;AAAA;AAAA,cACX;AAAA,cAEA,+CAAC,iBAAAa,SAAA,EAAU,gBAAc,MAAC,WAAW,GAAG,IAAI,EAAE,QAAQ,aAAa,aAAa,WAAW,YAAY,EAAE,SAAS,OAAO,EAAE,GACzH;AAAA,8DAAC,wBAAAC,SAAA,EAAiB,YAAY,8CAAC,qCAAW,GACxC,wDAAC,mBAAAhB,SAAA,EAAW,SAAQ,SAAQ,YAAY,KAAK,sBAAQ,GACvD;AAAA,gBACA,+CAAC,wBAAAiB,SAAA,EAAiB,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GACvE;AAAA;AAAA,oBAAC,kBAAAf;AAAA,oBAAA;AAAA,sBACC,OAAM;AAAA,sBACN,MAAK;AAAA,sBACL,OAAO,SAAS,aAAa;AAAA,sBAC7B,UAAU,CAAC,MACT,YAAY,EAAE,WAAW,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,KAAK,IAAI,OAAU,CAAC;AAAA,sBAEhF,YAAW;AAAA,sBACX,WAAS;AAAA;AAAA,kBACX;AAAA,kBACA;AAAA,oBAAC,kBAAAA;AAAA,oBAAA;AAAA,sBACC,OAAM;AAAA,sBACN,MAAK;AAAA,sBACL,OAAO,SAAS,aAAa;AAAA,sBAC7B,UAAU,CAAC,MACT,YAAY,EAAE,WAAW,EAAE,OAAO,QAAQ,OAAO,EAAE,OAAO,KAAK,IAAI,OAAU,CAAC;AAAA,sBAEhF,YAAW;AAAA,sBACX,WAAS;AAAA;AAAA,kBACX;AAAA,mBACF;AAAA,iBACF;AAAA,cACC,iBAAiB;AAAA,eACpB,GAEJ;AAAA,YACA,8CAAC,sBAAAgB,SAAA,EACE,wBACC,8CAAC,eAAAf,SAAA,EAAO,SAAS,yBAAyB,SAAQ,aAAY,OAAM,WAAU,kBAE9E,IAEA,gFACE;AAAA,4DAAC,eAAAA,SAAA,EAAO,SAAS,2BAA2B,oBAAM;AAAA,cAClD;AAAA,gBAAC,eAAAA;AAAA,gBAAA;AAAA,kBACC,SAAS,WAAW,iBAAiB;AAAA,kBACrC,SAAQ;AAAA,kBACR,OAAM;AAAA,kBACN,UAAU;AAAA,kBAET,uBAAa,8CAAC,yBAAAC,SAAA,EAAiB,MAAM,IAAI,IAAK;AAAA;AAAA,cACjD;AAAA,eACF,GAEJ;AAAA,YAGA,+CAAC,eAAAC,SAAA,EAAO,MAAM,yBAAyB,SAAS,MAAM,2BAA2B,KAAK,GAAG,UAAS,MAAK,WAAS,MAC9G;AAAA,4DAAC,oBAAAC,SAAA,EAAY,oCAAsB;AAAA,cACnC,8CAAC,sBAAAC,SAAA,EACC,wDAAC,mBAAAP,SAAA,EAAW,uDAEZ,GACF;AAAA,cACA,+CAAC,sBAAAkB,SAAA,EACC;AAAA,8DAAC,eAAAf,SAAA,EAAO,SAAS,MAAM,2BAA2B,KAAK,GAAG,qBAE1D;AAAA,gBACA;AAAA,kBAAC,eAAAA;AAAA,kBAAA;AAAA,oBACC,SAAS;AAAA,oBACT,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACP;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA,eACF;AAAA;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA;AAAA;;;ACt0BA,IAAAgB,eACAC,gBACAC,qBACAC,uBACAC,uBACAC,mBACAC,gBACAC,eACAC,kBACAC,0BACAC,sBACAC,0BACAC,kBACAC,cACAC,iBACAC,oBACAC,oBACAC,iBACAC,eACAC,eACAC,mBACAC,mBACAC,wBACAC,mBACAC,kBACAC,wBACAC,yBACA,6BACA,sBA+bMC,sBAzaA,yBAOA,yBACA,yBA2CO;AArGb;AAAA;AAAA;AAAA,IAAA3B,gBAAsE;AACtE,IAAAC,iBAAmB;AACnB,IAAAC,sBAAwB;AACxB,IAAAC,wBAA0B;AAC1B,IAAAC,wBAA0B;AAC1B,IAAAC,oBAAsB;AACtB,IAAAC,iBAAmB;AACnB,IAAAC,gBAAkB;AAClB,IAAAC,mBAAqB;AACrB,IAAAC,2BAA6B;AAC7B,IAAAC,uBAAyB;AACzB,IAAAC,2BAA6B;AAC7B,IAAAC,mBAAqB;AACrB,IAAAC,eAAgB;AAChB,IAAAC,kBAAoB;AACpB,IAAAC,qBAAuB;AACvB,IAAAC,qBAAuB;AACvB,IAAAC,kBAAoB;AACpB,IAAAC,gBAAkB;AAClB,IAAAC,gBAAkB;AAClB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,yBAA2B;AAC3B,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,IAAAC,yBAAqC;AACrC,IAAAC,0BAAuB;AACvB,kCAA8B;AAC9B,2BAA+C;AAE/C;AA6bM,IAAAC,uBAAA;AAzaN,IAAM,0BAAmE;AAAA,MACvE,EAAE,OAAO,MAAM,OAAO,aAAa;AAAA,MACnC,EAAE,OAAO,MAAM,OAAO,cAAc;AAAA,MACpC,EAAE,OAAO,OAAO,OAAO,gBAAgB;AAAA,MACvC,EAAE,OAAO,OAAO,OAAO,kBAAkB;AAAA,MACzC,EAAE,OAAO,QAAQ,OAAO,gBAAgB;AAAA,IAC1C;AACA,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;AA2CzB,IAAM,mBAA8C,CAAC;AAAA,MAC1D;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,CAAC,OAAO,QAAQ,QAAI,wBAAS,EAAE;AACrC,YAAM,CAAC,QAAQ,SAAS,QAAI,wBAAmB,CAAC,CAAC;AACjD,YAAM,CAAC,WAAW,YAAY,QAAI,wBAAiB,EAAE;AACrD,YAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,KAAK;AAChD,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,wBAAS,EAAE;AACvD,YAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,YAAM,CAAC,OAAO,QAAQ,QAAI,wBAAwB,IAAI;AAKtD,YAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,EAAE;AACjD,YAAM,CAAC,WAAW,YAAY,QAAI,wBAAS,EAAE;AAC7C,YAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,EAAE;AACnD,YAAM,CAAC,YAAY,aAAa,QAAI,wBAAS,KAAK;AAClD,YAAM,CAAC,aAAa,cAAc,QAAI,wBAAwB,IAAI;AAClE,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,wBAA0B,CAAC,CAAC;AAExE,YAAM,CAAC,OAAO,QAAQ,QAAI,wBAAmB,CAAC,CAAC;AAC/C,YAAM,CAAC,QAAQ,SAAS,QAAI,wBAAS,KAAK;AAC1C,YAAM,CAAC,SAAS,UAAU,QAAI,wBAAwB,IAAI;AAE1D,YAAM,CAAC,QAAQ,SAAS,QAAI,wBAAmB,CAAC,CAAC;AACjD,YAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,KAAK;AAC5C,YAAM,CAAC,UAAU,WAAW,QAAI,wBAAwB,IAAI;AAE5D,YAAM,uBAAuB,QAAQ,gBAAgB,wBAAwB;AAC7E,YAAM,mBACJ,QAAQ,gBAAgB,oBAAoB;AAG9C,YAAM,wBAAwB,QAAQ,SAAS,6BAA6B;AAC5E,YAAM,kBAAkB,yBAAyB,SAAS;AAE1D,YAAM,WAAW,SAAS;AAE1B,YAAM,cAAU;AAAA,QACd,MACE,WACI,eAAe,IAAI,QAAM;AAAA,UACvB,SAAS,EAAE;AAAA,UACX,YAAY,EAAE;AAAA,UACd,MAAM;AAAA,QACR,EAAE,IACF,MAAM,sBAAsB,CAAC;AAAA,QACnC,CAAC,UAAU,gBAAgB,IAAI;AAAA,MACjC;AACA,YAAM,cAAc,CAAC,CAAC,oBAAoB,CAAC,CAAC;AAE5C,YAAM,OAAO,eAAe,CAAC;AAK7B,YAAM,iBAAa,gCAAO,yCAAa;AACvC,YAAM,CAAC,aAAa,cAAc,QAAI,wBAAuB,CAAC,CAAC;AAC/D,YAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AACtD,YAAM,uBAAmB,sBAAuB;AAEhD,YAAM,uBAAmB,2BAAY,OAAO,SAAiB;AAE3D,YAAI,iBAAiB,SAAS;AAC5B,uBAAa,iBAAiB,OAAO;AAAA,QACvC;AAEA,YAAI,CAAC,KAAK,KAAK,GAAG;AAChB,yBAAe,CAAC,CAAC;AACjB;AAAA,QACF;AAEA,wBAAgB,IAAI;AACpB,yBAAiB,UAAU,WAAW,YAAY;AAChD,cAAI;AACF,kBAAM,EAAE,MAAM,IAAI,MAAM,WAAW,cAAc;AAAA,cAC/C,QAAQ,EAAE,MAAM,OAAO;AAAA,cACvB,gBAAgB;AAAA,gBACd,MAAM,KAAK,KAAK;AAAA,gBAChB,QAAQ,CAAC,iBAAiB,4BAA4B,oBAAoB;AAAA,cAC5E;AAAA,cACA,OAAO;AAAA,YACT,CAAC;AACD,2BAAe,KAAqB;AAAA,UACtC,QAAQ;AACN,2BAAe,CAAC,CAAC;AAAA,UACnB,UAAE;AACA,4BAAgB,KAAK;AAAA,UACvB;AAAA,QACF,GAAG,GAAG;AAAA,MACR,GAAG,CAAC,UAAU,CAAC;AAEf,YAAM,kBAAc,uBAAsB,MAAM;AAC9C,cAAM,iBAAiB,IAAI;AAAA,UACzB,QACG,IAAI,OAAK,EAAE,YAAY,YAAY,CAAC,EACpC,OAAO,CAAC,MAAmB,CAAC,CAAC,CAAC;AAAA,QACnC;AACA,gBAAQ,eAAe,CAAC,GACrB,IAAI,OAAK;AACR,gBAAM,UAAM,yCAAmB,CAAC;AAChC,gBAAM,cACJ,EAAE,MAAM,SAAS,eAAe,EAAE,SAAS,SAAS,EAAE,SAAS;AACjE,gBAAM,QAAQ,EAAE,MAAM,SAAS;AAC/B,iBAAO;AAAA,YACL;AAAA,YACA;AAAA,YACA,OAAO,QAAQ,GAAG,WAAW,KAAK,KAAK,MAAM;AAAA,UAC/C;AAAA,QACF,CAAC,EACA,OAAO,OAAK,EAAE,EAAE,SAAS,eAAe,IAAI,EAAE,MAAM,YAAY,CAAC,EAAE,EACnE,OAAO,OAAK,CAAC,eAAe,KAAK,OAAK,EAAE,kBAAkB,EAAE,GAAG,CAAC,EAChE,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,cAAc,EAAE,KAAK,CAAC;AAAA,MAClD,GAAG,CAAC,aAAa,SAAS,cAAc,CAAC;AAGzC,mCAAU,MAAM;AACd,eAAO,MAAM;AACX,cAAI,iBAAiB,SAAS;AAC5B,yBAAa,iBAAiB,OAAO;AAAA,UACvC;AAAA,QACF;AAAA,MACF,GAAG,CAAC,CAAC;AAEL,mCAAU,MAAM;AACd,YAAI,MAAM;AACR,cAAI,SAAS,UAAU,MAAM;AAC3B,qBAAS,KAAK,cAAc,EAAE;AAC9B,sBAAU,KAAK,UAAU,CAAC,CAAC;AAC3B,gBAAI,uBAAuB;AAEzB,2BAAa,EAAE;AAAA,YACjB,OAAO;AACL;AAAA,gBACE,KAAK,aAAa,OAAO,KAAK,UAAU,IAAI,OAAO,gBAAgB;AAAA,cACrE;AAAA,YACF;AACA,yBAAa,wBAAwB,CAAC,KAAK,UAAU;AACrD,8BAAkB,KAAK,mBAAmB,uBAAuB;AAAA,UACnE,OAAO;AACL,qBAAS,EAAE;AACX,sBAAU,CAAC,CAAC;AAEZ,yBAAa,OAAO,gBAAgB,CAAC;AACrC,yBAAa,oBAAoB;AACjC,8BAAkB,uBAAuB;AAAA,UAC3C;AACA,mBAAS,IAAI;AACb,yBAAe,EAAE;AACjB,uBAAa,EAAE;AACf,0BAAgB,EAAE;AAClB,yBAAe,IAAI;AACnB,4BAAkB,CAAC,CAAC;AACpB,mBAAS,MAAM,mBAAmB,iBAAiB,CAAC,CAAC;AACrD,qBAAW,IAAI;AACf,oBAAU,MAAM,mBAAmB,eAAe,CAAC,CAAC;AACpD,sBAAY,IAAI;AAAA,QAClB;AAAA,MACF,GAAG,CAAC,MAAM,MAAM,MAAM,sBAAsB,kBAAkB,qBAAqB,CAAC;AAEpF,YAAM,eAAe,YAAY;AAC/B,iBAAS,IAAI;AAEb,YAAI,CAAC,MAAM,KAAK,GAAG;AACjB,mBAAS,wBAAwB;AACjC;AAAA,QACF;AAEA,YAAI,OAAO,WAAW,GAAG;AACvB,mBAAS,gCAAgC;AACzC;AAAA,QACF;AAEA,YAAI,CAAC,WAAW;AAEd,gBAAM,kBAAkB,mBAAmB,CAAC,UAAU,KAAK;AAC3D,cAAI,CAAC,iBAAiB;AACpB,gBAAI,CAAC,WAAW;AACd,uBAAS,wDAAwD;AACjE;AAAA,YACF;AACA,kBAAM,SAAS,WAAW,SAAS;AACnC,gBAAI,MAAM,MAAM,KAAK,UAAU,GAAG;AAChC,uBAAS,kCAAkC;AAC3C;AAAA,YACF;AACA,gBAAI,SAAS,kBAAkB;AAC7B,uBAAS,yBAAyB,gBAAgB,EAAE;AACpD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAEA,YAAI;AACF,wBAAc,IAAI;AAClB,cAAI;AAEJ,cAAI,SAAS,UAAU;AACrB,sBAAU;AAAA,cACR,YAAY,MAAM,KAAK;AAAA,cACvB;AAAA,cACA,GAAI,YAAY,EAAE,YAAY,KAAK,IAAI,EAAE,YAAY,WAAW,SAAS,EAAE;AAAA,cAC3E,GAAI,kBAAkB,EAAE,iBAAiB,eAAe;AAAA,YAC1D;AAAA,UACF,OAAO;AAGL,gBAAI,cAA8C,CAAC;AACnD,gBAAI,WAAW;AACb,4BAAc,EAAE,YAAY,KAAK;AAAA,YACnC,WAAW,UAAU,KAAK,GAAG;AAC3B,4BAAc,EAAE,YAAY,WAAW,SAAS,EAAE;AAAA,YACpD;AACA,sBAAU;AAAA,cACR,YAAY,MAAM,KAAK;AAAA,cACvB;AAAA,cACA,GAAG;AAAA,cACH,GAAI,kBAAkB,EAAE,iBAAiB,eAAe;AAAA,YAC1D;AAAA,UACF;AAEA,gBAAM;AAAA,YACJ;AAAA,YACA,WACI,eAAe,IAAI,CAAC,EAAE,eAAe,gBAAgB,OAAO;AAAA,cAC1D;AAAA,cACA,GAAI,oBAAoB,UAAa,EAAE,gBAAgB;AAAA,YACzD,EAAE,IACF;AAAA,UACN;AACA,kBAAQ;AAAA,QACV,SAAS,KAAK;AACZ,mBAAS,eAAe,QAAQ,IAAI,UAAU,mBAAmB;AAAA,QACnE,UAAE;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,kBAAkB,YAAY;AAClC,YAAI,CAAC,UAAU,KAAK,KAAM,CAAC,YAAY,CAAC,YAAc;AACtD,uBAAe,IAAI;AAEnB,cAAM,SACJ,CAAC,eAAe,eAAe,WAAW,YAAY,IAAI;AAC5D,YAAI,WAAW,WAAc,MAAM,MAAM,KAAK,UAAU,IAAI;AAC1D,yBAAe,8CAA8C;AAC7D;AAAA,QACF;AACA,YAAI,UAAU;AACZ,gBAAM,MAAM,UAAU,KAAK;AAC3B,cAAI,CAAC,eAAe,KAAK,OAAK,EAAE,kBAAkB,GAAG,GAAG;AACtD,8BAAkB,UAAQ;AAAA,cACxB,GAAG;AAAA,cACH,EAAE,eAAe,KAAK,OAAO,YAAY,KAAK,KAAK,KAAK,iBAAiB,OAAO;AAAA,YAClF,CAAC;AAAA,UACH;AACA,yBAAe,EAAE;AACjB,uBAAa,EAAE;AACf,0BAAgB,EAAE;AAClB;AAAA,QACF;AACA,YAAI;AACF,wBAAc,IAAI;AAClB,gBAAM,YAAa,UAAU,KAAK,GAAG,MAAM;AAC3C,yBAAe,EAAE;AACjB,uBAAa,EAAE;AACf,0BAAgB,EAAE;AAAA,QACpB,SAAS,KAAK;AACZ,yBAAe,eAAe,QAAQ,IAAI,UAAU,sBAAsB;AAAA,QAC5E,UAAE;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,qBAAqB,OAAO,WAAmB;AACnD,YAAI,UAAU;AACZ,4BAAkB,UAAQ,KAAK,OAAO,OAAK,EAAE,kBAAkB,MAAM,CAAC;AACtE;AAAA,QACF;AACA,YAAI,CAAC,eAAgB;AACrB,uBAAe,IAAI;AACnB,YAAI;AACF,wBAAc,IAAI;AAClB,gBAAM,eAAe,MAAM;AAAA,QAC7B,SAAS,KAAK;AACZ,yBAAe,eAAe,QAAQ,IAAI,UAAU,yBAAyB;AAAA,QAC/E,UAAE;AACA,wBAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAEA,YAAM,2BAA2B,YAAY;AAC3C,YAAI,CAAC,qBAAsB;AAC3B,mBAAW,IAAI;AACf,YAAI;AACF,oBAAU,IAAI;AACd,gBAAM,qBAAqB,KAAK;AAAA,QAClC,SAAS,KAAK;AACZ,qBAAW,eAAe,QAAQ,IAAI,UAAU,gCAAgC;AAAA,QAClF,UAAE;AACA,oBAAU,KAAK;AAAA,QACjB;AAAA,MACF;AAEA,YAAM,uBAAuB,YAAY;AACvC,YAAI,CAAC,iBAAkB;AACvB,oBAAY,IAAI;AAChB,YAAI;AACF,qBAAW,IAAI;AACf,gBAAM,iBAAiB,MAAM;AAAA,QAC/B,SAAS,KAAK;AACZ,sBAAY,eAAe,QAAQ,IAAI,UAAU,4BAA4B;AAAA,QAC/E,UAAE;AACA,qBAAW,KAAK;AAAA,QAClB;AAAA,MACF;AAEA,YAAM,aAAa,UAAU,IAAI,OAAK,EAAE,UAAU;AAGlD,YAAM,kBAAkB,wBAAwB,KAAK,OAAK,EAAE,UAAU,cAAc,IAChF,0BACA,CAAC,GAAG,yBAAyB,EAAE,OAAO,gBAAgB,OAAO,eAAe,CAAC;AACjF,YAAM,qBAAqB,SAAS,UAAU,CAAC,CAAC;AAChD,YAAM,aAAa,gBAAgB,CAAC,GAAG,IAAI,OAAK,EAAE,EAAE;AACpD,YAAM,UAAU,CAAC,QACd,gBAAgB,CAAC,GAAG,KAAK,OAAK,EAAE,OAAO,EAAE,GAAG,QAAQ;AACvD,YAAM,iBAAiB,SAAS,UAAU,CAAC,CAAC;AAC5C,YAAM,cAAc,cAAc,CAAC,GAAG,IAAI,OAAK,EAAE,EAAE;AACnD,YAAM,WAAW,CAAC,QACf,cAAc,CAAC,GAAG,KAAK,OAAK,EAAE,OAAO,EAAE,GAAG,QAAQ;AAGrD,YAAM,oBAAoB,CAAC,cAAsB,eAA+D;AAC9G,YAAI,CAAC,YAAa,QAAO,EAAE,UAAU,MAAM;AAC3C,YAAI,iBAAiB,eAAe;AAClC,iBAAO,EAAE,UAAU,MAAM,QAAQ,4BAA4B;AAAA,QAC/D;AACA,YAAI,oBAAoB,SAAS,UAAU,GAAG;AAC5C,iBAAO,EAAE,UAAU,MAAM,QAAQ,0CAA0C,UAAU,GAAG;AAAA,QAC1F;AACA,eAAO,EAAE,UAAU,MAAM;AAAA,MAC3B;AAEA,YAAM,cAAc,WAAW,gBAAgB;AAE/C,YAAM,iBAAiB,MAAM;AAC3B,YAAI,aAAa;AACf,iBAAO,yBAAoB,MAAM,cAAc,eAAe;AAAA,QAChE;AACA,eAAO,SAAS,WAAW,gBAAgB;AAAA,MAC7C;AAEA,aACE,+CAAC,eAAAC,SAAA,EAAO,MAAY,SAAkB,UAAU,OAAO,OAAO,MAAM,WAAS,MAC3E;AAAA,sDAAC,oBAAAC,SAAA,EAAa,yBAAe,GAAE;AAAA,QAC/B,+CAAC,sBAAAC,SAAA,EAAc,IAAI,EAAE,IAAI,GAAG,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GAC1E;AAAA,mBAAS,8CAAC,cAAAC,SAAA,EAAM,UAAS,SAAS,iBAAM;AAAA,UAExC,eACC,+CAAC,cAAAA,SAAA,EAAM,UAAS,QAAO;AAAA;AAAA,YACV,MAAM,oBAAoB,KAAK,OAAK,EAAE,YAAY,aAAa,GAAG,QAAQ;AAAA,YAAS;AAAA,aAChG;AAAA,UAGF;AAAA,YAAC,aAAAC;AAAA,YAAA;AAAA,cACC,IAAI;AAAA,gBACF,SAAS;AAAA,gBACT,qBAAqB;AAAA,kBACnB,IAAI;AAAA,kBACJ,IAAI,OAAO,kCAAkC;AAAA,gBAC/C;AAAA,gBACA,KAAK;AAAA,gBACL,YAAY;AAAA,cACd;AAAA,cAEC;AAAA,iBAAC,eACA,+CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GACzD;AAAA,0BAAQ,8CAAC,mBAAAC,SAAA,EAAW,SAAQ,aAAY,sBAAQ;AAAA,kBACjD;AAAA,oBAAC,kBAAAC;AAAA,oBAAA;AAAA,sBACC,OAAM;AAAA,sBACN,OAAO;AAAA,sBACP,UAAU,OAAK,SAAS,EAAE,OAAO,KAAK;AAAA,sBACtC,UAAU;AAAA,sBACV,WAAS;AAAA;AAAA,kBACX;AAAA,kBAEA;AAAA,oBAAC,qBAAAC;AAAA,oBAAA;AAAA,sBACC,UAAQ;AAAA,sBACR,SAAS;AAAA,sBACT,OAAO;AAAA,sBACP,UAAU,CAAC,GAAG,aAAa,UAAU,QAAQ;AAAA,sBAC7C,UAAU;AAAA,sBACV,aAAa,YACX;AAAA,wBAAC,kBAAAD;AAAA,wBAAA;AAAA,0BACE,GAAG;AAAA,0BACJ,OAAM;AAAA,0BACN,UAAQ;AAAA,0BACR,YAAW;AAAA;AAAA,sBACb;AAAA;AAAA,kBAEJ;AAAA,kBAEA;AAAA,oBAAC,aAAAF;AAAA,oBAAA;AAAA,sBACC,IAAI;AAAA,wBACF,SAAS;AAAA,wBACT,qBAAqB,EAAE,IAAI,OAAO,IAAI,UAAU;AAAA,wBAChD,KAAK;AAAA,sBACP;AAAA,sBAEA;AAAA;AAAA,0BAAC,kBAAAE;AAAA,0BAAA;AAAA,4BACC,OAAO,kBAAkB,uBAAuB;AAAA,4BAChD,MAAK;AAAA,4BACL,OAAO;AAAA,4BACP,UAAU,OAAK,aAAa,EAAE,OAAO,KAAK;AAAA,4BAC1C,UAAU,cAAc;AAAA,4BACxB,YAAY,EAAE,KAAK,GAAG,KAAK,iBAAiB;AAAA,4BAC5C,YACE,kBACI,iFACA,aAAa,gBAAgB;AAAA,4BAEnC,WAAS;AAAA;AAAA,wBACX;AAAA,wBAEA;AAAA,0BAAC,kBAAAA;AAAA,0BAAA;AAAA,4BACC,QAAM;AAAA,4BACN,OAAM;AAAA,4BACN,OAAO;AAAA,4BACP,UAAU,OAAK,kBAAkB,EAAE,OAAO,KAAK;AAAA,4BAC/C,UAAU,cAAc;AAAA,4BACxB,YAAW;AAAA,4BACX,WAAS;AAAA,4BAER,0BAAgB,IAAI,OACnB,8CAAC,iBAAAE,SAAA,EAAuB,OAAO,EAAE,OAC9B,YAAE,SADU,EAAE,KAEjB,CACD;AAAA;AAAA,wBACH;AAAA;AAAA;AAAA,kBACF;AAAA,kBAEC,wBACC;AAAA,oBAAC,yBAAAC;AAAA,oBAAA;AAAA,sBACC,SAAS,8CAAC,iBAAAC,SAAA,EAAS,SAAS,WAAW,UAAU,OAAK,aAAa,EAAE,OAAO,OAAO,GAAG,UAAU,YAAY;AAAA,sBAC5G,OAAM;AAAA;AAAA,kBACR;AAAA,mBAEJ;AAAA,gBAGD,eACC,+CAAC,aAAAN,SAAA,EACC;AAAA,gEAAC,mBAAAC,SAAA,EAAW,SAAQ,aAAY,IAAI,EAAE,IAAI,WAAW,OAAO,EAAE,GAC3D,qBAAW,oBAAoB,WAClC;AAAA,kBACC,YACC,8CAAC,mBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAAG,kEAElE;AAAA,kBAED,eACC,8CAAC,cAAAF,SAAA,EAAM,UAAS,SAAQ,IAAI,EAAE,IAAI,EAAE,GAAG,SAAS,MAAM,eAAe,IAAI,GACtE,uBACH;AAAA,kBAED,QAAQ,WAAW,IAClB,8CAAC,mBAAAE,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAC5D,qBAAW,8DAAyD,mBACvE,IAEA,8CAAC,uBAAAM,SAAA,EAAe,WAAW,cAAAC,SAAO,SAAQ,YAAW,IAAI,EAAE,cAAc,KAAK,IAAI,IAAI,GACpF,yDAAC,cAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,kEAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAAC,SAAA,EACC;AAAA,oEAAC,kBAAAC,SAAA,EAAU,kBAAI;AAAA,sBACf,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,kBAAI;AAAA,sBAC7B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,IAAI,EAAE,OAAO,GAAG,GAAG;AAAA,uBAC9C,GACF;AAAA,oBACA,8CAAC,kBAAAC,SAAA,EACE,kBAAQ,IAAI,OACX,+CAAC,iBAAAF,SAAA,EACC;AAAA,oEAAC,kBAAAC,SAAA,EACE,YAAE,aACD,gFACE;AAAA,sEAAC,mBAAAX,SAAA,EAAW,SAAQ,SAAS,YAAE,YAAW;AAAA,wBAC1C;AAAA,0BAAC,mBAAAA;AAAA,0BAAA;AAAA,4BACC,SAAQ;AAAA,4BACR,OAAM;AAAA,4BACN,IAAI,EAAE,YAAY,kDAAkD,UAAU,GAAG;AAAA,4BAEhF,YAAE;AAAA;AAAA,wBACL;AAAA,yBACF,IAEA;AAAA,wBAAC,mBAAAA;AAAA,wBAAA;AAAA,0BACC,SAAQ;AAAA,0BACR,IAAI,EAAE,YAAY,iDAAiD;AAAA,0BAElE,YAAE;AAAA;AAAA,sBACL,GAEJ;AAAA,sBACA,8CAAC,kBAAAW,SAAA,EAAU,OAAM,SACf,wDAAC,cAAW,OAAO,EAAE,MAAM,MAAM,EAAE,SAAS,UAAU,WAAW,WAAW,KAAK,OAAO,GAC1F;AAAA,sBACA,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SACb,iBAAM;AACN,8BAAM,EAAE,UAAU,OAAO,IAAI,kBAAkB,EAAE,SAAS,EAAE,IAAI;AAEhE,+BACE,8CAAC,gBAAAE,SAAA,EAAQ,OAAO,UAAU,IACxB,wDAAC,UACC;AAAA,0BAAC,mBAAAC;AAAA,0BAAA;AAAA,4BACC,MAAK;AAAA,4BACL,MAAK;AAAA,4BACL,cAAY,UAAU,EAAE,OAAO;AAAA,4BAC/B,UAAU,cAAc;AAAA,4BACxB,SAAS,MAAM,mBAAmB,EAAE,OAAO;AAAA,4BAE3C,wDAAC,uBAAAC,QAAA,EAAW,UAAS,SAAQ;AAAA;AAAA,wBAC/B,GACF,GACF;AAAA,sBAEJ,GAAG,GACL;AAAA,yBA7Ca,EAAE,OA8CjB,CACD,GACH;AAAA,qBACF,GACF;AAAA,kBAEF,+CAAC,aAAAhB,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,KAAK,GAAG,YAAY,cAAc,UAAU,OAAO,GAC7E;AAAA;AAAA,sBAAC,qBAAAG;AAAA,sBAAA;AAAA,wBACC,UAAQ;AAAA,wBACR,eAAa;AAAA,wBACb,SAAS;AAAA,wBACT,SAAS;AAAA,wBACT,YAAY;AAAA,wBACZ,eAAe,CAAC,GAAG,eAAe,WAAW;AAC3C,yCAAe,aAAa;AAI5B,8BAAI,WAAW,WAAW,WAAW,SAAS;AAC5C,yCAAa,aAAa;AAE1B,6CAAiB,aAAa;AAAA,0BAChC;AAAA,wBACF;AAAA,wBACA,UAAU,CAAC,GAAG,aAAa;AACzB,8BAAI,YAAY,OAAO,aAAa,UAAU;AAC5C,2CAAe,SAAS,KAAK;AAC7B,yCAAa,SAAS,GAAG;AAAA,0BAC3B;AAAA,wBACF;AAAA,wBACA,gBAAgB,OAAM,OAAO,MAAM,WAAW,IAAI,EAAE;AAAA,wBACpD,sBAAsB,CAAC,GAAG,MAAM,EAAE,SAAS,OAAO,MAAM,WAAW,IAAI,EAAE;AAAA,wBACzE,UAAU;AAAA,wBACV,IAAI,EAAE,MAAM,YAAY;AAAA,wBACxB,aAAa,YACX;AAAA,0BAAC,kBAAAD;AAAA,0BAAA;AAAA,4BACE,GAAG;AAAA,4BACJ,OAAM;AAAA,4BACN,aAAY;AAAA,4BACZ,MAAK;AAAA,4BACL,YAAW;AAAA,4BACX,YAAY;AAAA,8BACV,GAAG,OAAO;AAAA,8BACV,cACE,gFACG;AAAA,+CAAe,8CAAC,yBAAAe,SAAA,EAAiB,OAAM,WAAU,MAAM,IAAI,IAAK;AAAA,gCAChE,OAAO,WAAW;AAAA,iCACrB;AAAA,4BAEJ;AAAA;AAAA,wBACF;AAAA;AAAA,oBAEJ;AAAA,oBACC,CAAC,eACA;AAAA,sBAAC,kBAAAf;AAAA,sBAAA;AAAA,wBACC,OAAM;AAAA,wBACN,MAAK;AAAA,wBACL,OAAO;AAAA,wBACP,UAAU,OAAK,gBAAgB,EAAE,OAAO,KAAK;AAAA,wBAC7C,UAAU;AAAA,wBACV,MAAK;AAAA,wBACL,IAAI,EAAE,OAAO,IAAI;AAAA;AAAA,oBACnB;AAAA,oBAEF;AAAA,sBAAC,eAAAgB;AAAA,sBAAA;AAAA,wBACC,SAAS;AAAA,wBACT,UAAU,cAAc,CAAC,UAAU,KAAK;AAAA,wBACxC,SAAQ;AAAA,wBACR,IAAI,EAAE,IAAI,IAAI;AAAA,wBACf;AAAA;AAAA,oBAED;AAAA,qBACF;AAAA,mBACF;AAAA;AAAA;AAAA,UAGJ;AAAA,UAEC,CAAC,eAAe,sBACf,+CAAC,aAAAlB,SAAA,EACC;AAAA,0DAAC,gBAAAmB,SAAA,EAAQ,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,YACxB,8CAAC,mBAAAlB,SAAA,EAAW,SAAQ,aAAY,IAAI,EAAE,IAAI,EAAE,GAAG,6BAE/C;AAAA,YACA,8CAAC,mBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAAG,yFAGlE;AAAA,YACC,WACC,8CAAC,cAAAF,SAAA,EAAM,UAAS,SAAQ,IAAI,EAAE,IAAI,EAAE,GAAG,SAAS,MAAM,WAAW,IAAI,GAClE,mBACH;AAAA,YAEF;AAAA,cAAC,qBAAAI;AAAA,cAAA;AAAA,gBACC,UAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP,gBAAgB;AAAA,gBAChB,UAAU,CAAC,GAAG,MAAM,SAAS,CAAC;AAAA,gBAC9B,UAAU;AAAA,gBACV,aAAa,YACX,8CAAC,kBAAAD,SAAA,EAAW,GAAG,QAAQ,OAAM,4BAA2B;AAAA;AAAA,YAE5D;AAAA,YACA,8CAAC,aAAAF,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,gBAAgB,YAAY,IAAI,EAAE,GAC5D;AAAA,cAAC,eAAAkB;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,SAAQ;AAAA,gBAEP,mBAAS,iBAAY;AAAA;AAAA,YACxB,GACF;AAAA,aACF;AAAA,UAGD,CAAC,eAAe,kBACf,+CAAC,aAAAlB,SAAA,EACC;AAAA,0DAAC,gBAAAmB,SAAA,EAAQ,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,YACxB,8CAAC,mBAAAlB,SAAA,EAAW,SAAQ,aAAY,IAAI,EAAE,IAAI,EAAE,GAAG,yBAE/C;AAAA,YACA,8CAAC,mBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAAG,kKAIlE;AAAA,YACC,YACC,8CAAC,cAAAF,SAAA,EAAM,UAAS,SAAQ,IAAI,EAAE,IAAI,EAAE,GAAG,SAAS,MAAM,YAAY,IAAI,GACnE,oBACH;AAAA,YAEF;AAAA,cAAC,qBAAAI;AAAA,cAAA;AAAA,gBACC,UAAQ;AAAA,gBACR,SAAS;AAAA,gBACT,OAAO;AAAA,gBACP,gBAAgB;AAAA,gBAChB,UAAU,CAAC,GAAG,MAAM,UAAU,CAAC;AAAA,gBAC/B,UAAU;AAAA,gBACV,aAAa,YACX,8CAAC,kBAAAD,SAAA,EAAW,GAAG,QAAQ,OAAM,wBAAuB;AAAA;AAAA,YAExD;AAAA,YACA,8CAAC,aAAAF,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,gBAAgB,YAAY,IAAI,EAAE,GAC5D;AAAA,cAAC,eAAAkB;AAAA,cAAA;AAAA,gBACC,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,SAAQ;AAAA,gBAEP,oBAAU,iBAAY;AAAA;AAAA,YACzB,GACF;AAAA,aACF;AAAA,WAEJ;AAAA,QACA,+CAAC,sBAAAE,SAAA,EACC;AAAA,wDAAC,eAAAF,SAAA,EAAO,SAAS,SAAS,UAAU,YACjC,wBAAc,SAAS,UAC1B;AAAA,UACC,CAAC,eACA,8CAAC,eAAAA,SAAA,EAAO,SAAS,cAAc,UAAU,YAAY,SAAQ,aAC1D,uBAAa,cAAc,aAC9B;AAAA,WAEJ;AAAA,SACF;AAAA,IAEJ;AAAA;AAAA;;;ACnwBA,SAAS,SAAS,OAAe,QAAwB;AACvD,MAAI,UAAU,EAAG,QAAO;AACxB,SAAQ,QAAQ,SAAU;AAC5B;AASO,SAAS,mBACd,MACA,OACA,MACA,UAAU,GACK;AACf,QAAM,WAAW,KACd,OAAO,QAAM,EAAE,cAAc,KAAK,CAAC,EACnC,IAAI,OAAK;AACR,UAAM,QAAQ,EAAE,SAAS;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,aAAa,EAAE,OAAO;AAAA,MAC/B,UAAU,EAAE;AAAA,MACZ,QAAQ,EAAE;AAAA,MACV;AAAA,MACA,gBAAgB,EAAE;AAAA,MAClB,KAAK,SAAS,OAAO,EAAE,UAAW;AAAA,IACpC;AAAA,EACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAE/B,QAAM,aACJ,SAAS,KAAK,cAAc,KAAK,cAAc,KAAK,KAC/C,MAAM;AACL,UAAM,SAAS,KAAK,cAAc,KAAK,cAAc;AACrD,UAAM,QAAQ,KAAK,iBAAiB,KAAK,SAAS;AAClD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,UAAU,KAAK,cAAc,KAAK;AAAA,MAClC;AAAA,MACA;AAAA,MACA,gBAAgB,KAAK;AAAA,MACrB,WAAW,KAAK;AAAA,MAChB,KAAK,SAAS,OAAO,MAAM;AAAA,IAC7B;AAAA,EACF,GAAG,IACH;AAEN,QAAM,aAA4B,MAC/B,OAAO,QAAM,EAAE,cAAc,KAAK,KAAK,EAAE,kBAAkB,IAAI,EAC/D,IAAI,OAAK;AACR,QAAI,EAAE,kBAAkB,MAAM;AAC5B,aAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO,EAAE,cAAc;AAAA,QACvB,UAAU,EAAE;AAAA,QACZ,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,gBAAgB,EAAE;AAAA,QAClB,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,cAAc,CAAC,CAAC;AAAA,QACjD,QAAQ;AAAA,MACV;AAAA,IACF;AACA,UAAM,QAAQ,EAAE,SAAS;AACzB,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,EAAE,cAAc;AAAA,MACvB,UAAU,EAAE;AAAA,MACZ,QAAQ,EAAE;AAAA,MACV;AAAA,MACA,gBAAgB,EAAE;AAAA,MAClB,KAAK,SAAS,OAAO,EAAE,UAAW;AAAA,IACpC;AAAA,EACF,CAAC,EACA,KAAK,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;AAE/B,SAAO;AAAA,IACL,MAAM,SAAS,MAAM,GAAG,OAAO;AAAA,IAC/B,oBAAoB,KAAK,IAAI,GAAG,SAAS,SAAS,OAAO;AAAA,IACzD,eAAe,KAAK;AAAA,IACpB,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AACF;AASO,SAAS,gBAAgB,SAAuC;AACrE,SAAO;AAAA,IACL,GAAG,QAAQ;AAAA,IACX,GAAI,QAAQ,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;AAAA,IACrC,GAAG,QAAQ;AAAA,EACb;AACF;AA0BO,SAAS,kBAAkB,SAAuC;AACvE,QAAM,UAAsD;AAAA,IAC1D,KAAK,QAAQ;AAAA,IACb,MAAM,QAAQ,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;AAAA,IACvC,MAAM,QAAQ;AAAA,EAChB;AACA,SAAO,YAAY,IAAI,UAAQ;AAC7B,UAAM,SAAS,QAAQ,IAAI;AAC3B,UAAM,QACJ,SAAS,QAAQ,OAAO,SAAS,QAAQ,qBAAqB,OAAO;AACvE,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,OAAO,OAAO,SACV,OAAO,OAAO,CAAC,GAAG,MAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAE,IAC/C;AAAA,IACN;AAAA,EACF,CAAC;AACH;AAQO,SAAS,eAAe,SAG7B;AACA,QAAM,MAAqB;AAAA,IACzB,GAAG,QAAQ;AAAA,IACX,GAAI,QAAQ,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC;AAAA,IACrC,GAAG,QAAQ;AAAA,EACb;AACA,QAAM,QACJ,QAAQ,KAAK,SACb,QAAQ,sBACP,QAAQ,OAAO,IAAI,KACpB,QAAQ,MAAM;AAChB,QAAM,UAAU,IAAI,SAChB,IAAI,OAAO,CAAC,GAAG,MAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAE,IAC5C;AACJ,SAAO,EAAE,OAAO,QAAQ;AAC1B;AAGO,SAAS,kBAAkB,UAAkC;AAClE,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,IAAI,mBAAmB,KAAK,QAAQ;AAC1C,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,IAAI,OAAO,EAAE,CAAC,CAAC;AACrB,QAAM,OAAO,EAAE,CAAC;AAChB,MAAI,SAAS,IAAK,QAAO,MAAM,IAAI,UAAU,SAAS,CAAC;AACvD,MAAI,SAAS,IAAK,QAAO,MAAM,IAAI,WAAW,SAAS,CAAC;AACxD,MAAI,SAAS,IAAK,QAAO,MAAM,IAAI,iBAAiB,SAAS,CAAC;AAC9D,SAAO,MAAM,IAAI,iBAAiB,SAAS,CAAC;AAC9C;AAGO,SAASG,YAAW,KAAmB;AAC5C,QAAM,aAAS,4DAAmB,GAAG;AACrC,MAAI,WAAW,OAAQ,QAAO;AAC9B,MAAI,WAAW,OAAQ,QAAO;AAC9B,SAAO;AACT;AA0BO,SAAS,cAAc,UAA0C;AACtE,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,MACL,OAAO;AAAA,MACP,KAAK;AAAA,MACL,WAAW;AAAA,MACX,KAAK;AAAA,MACL,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,QAAQ,SAAS,SAAS;AAChC,QAAM,MAAM,SAAS,cAAc;AAEnC,MAAI,QAAQ,QAAQ,OAAO,GAAG;AAC5B,WAAO;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL,WAAW;AAAA,MACX,KAAK;AAAA,MACL,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,EACF;AAEA,QAAM,YAAY,KAAK,IAAI,GAAG,MAAM,KAAK;AACzC,QAAM,MAAO,QAAQ,MAAO;AAG5B,MAAIC;AACJ,MAAI,SAAS,mBAAmB,SAAS,iBAAiB;AACxD,QAAI;AACF,YAAM,YAAY,IAAI,KAAK,SAAS,eAAe;AAEnD,YAAM,MAAM,IAAI,KAAK,eAAe,SAAS;AAAA,QAC3C,OAAO;AAAA,QACP,KAAK;AAAA,QACL,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,UAAU;AAAA,MACZ,CAAC;AACD,YAAM,YAAY,IAAI,OAAO,SAAS;AACtC,MAAAA,cAAa,UAAU,SAAS;AAAA,IAClC,QAAQ;AACN,MAAAA,cAAa;AAAA,IACf;AAAA,EACF,OAAO;AACL,IAAAA,cAAa;AAAA,EACf;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,YAAAA;AAAA,EACF;AACF;AAnUA,IAEAC,yCA8JM;AAhKN;AAAA;AAAA;AAEA,IAAAA,0CAAmC;AA8JnC,IAAM,cAA0C,CAAC,OAAO,QAAQ,MAAM;AAAA;AAAA;;;ACtEtE,SAAS,SAAS,MAAoB;AACpC,MAAI,QAAQ,KAAM,QAAO;AACzB,MAAI,QAAQ,IAAK,QAAO;AACxB,SAAO;AACT;AA9FA,IAAAC,eACAC,eACAC,cACAC,oBACAC,mBACAC,kBACA,aACAC,eACAC,gBACAC,eACAC,mBACAC,mBACAC,wBACAC,mBACAC,kBACAC,kBACA,iBAiFEC,sBApBI,cACA,eAEA,eAOA,QASA,eAKA,iBAYA,iBAoBO;AArIb;AAAA;AAAA;AAAA,IAAAf,gBAA4D;AAC5D,IAAAC,gBAAkB;AAClB,IAAAC,eAAgB;AAChB,IAAAC,qBAAuB;AACvB,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,kBAAiB;AACjB,IAAAC,gBAAkB;AAClB,IAAAC,iBAAmB;AACnB,IAAAC,gBAAkB;AAClB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,yBAA2B;AAC3B,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqB;AACrB,sBAeO;AASP;AACA;AACA;AAuDE,IAAAC,uBAAA;AApBF,IAAM,eAAe;AACrB,IAAM,gBAAgB;AAEtB,IAAM,gBAA4C;AAAA,MAChD,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAEA,IAAM,SAAS,CAAC,MAAc,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AASrD,IAAM,gBAAyC,CAAC,EAAE,SAAS,IAAI,MAC7D,8CAAC,iBAAAC,SAAA,EAAS,SAAQ,WAAU,QAAgB;AAI9C,IAAM,kBAKD,CAAC,EAAE,SAAS,OAAO,SAAS,KAAK,SAAS,MAAM;AACnD,UAAI,QAAS,QAAO,8CAAC,iBAAc,QAAgB;AACnD,UAAI,MAAO,QAAO,8CAAC,cAAW,SAAQ,2BAA0B,QAAgB;AAChF,aAAO,+EAAG,UAAS;AAAA,IACrB;AAGA,IAAM,kBAA0D,CAAC,EAAE,MAAM,SAAS,MAAM;AACtF,UAAI,aAAa,EAAG,QAAO,8CAAC,mBAAAC,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,oBAAC;AAC/E,YAAM,OAAO,SAAS,IAAI;AAC1B,aACE,+CAAC,aAAAC,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,GAG3C;AAAA,sDAAC,aAAAA,SAAA,EAAI,OAAO,IAAI,YAAY,GAC1B,wDAAC,SAAM,OAAO,OAAO,KAAK,MAAY,QAAQ,GAAG,GACnD;AAAA,QACA;AAAA,UAAC,mBAAAD;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,IAAI,EAAE,oBAAoB,gBAAgB,UAAU,GAAG;AAAA,YAEtD,iBAAO,IAAI;AAAA;AAAA,QACd;AAAA,SACF;AAAA,IAEJ;AAEO,IAAM,aAAkC,CAAC;AAAA,MAC9C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,QAAQ,cAAc;AAC5B,YAAM,CAAC,eAAe,gBAAgB,QAAI,wBAAiB,KAAK;AAChE,YAAM,CAAC,KAAK,MAAM,QAAI,wBAAiB,OAAO;AAG9C,YAAM,qBAAiB;AAAA,QACrB,MAAM,gBAAgB,OAAO,MAAM;AAAA,QACnC,CAAC,OAAO,MAAM;AAAA,MAChB;AAGA,mCAAU,MAAM;AACd,YAAI,kBAAkB,SAAS,CAAC,eAAe,SAAS,aAAa,GAAG;AACtE,2BAAiB,KAAK;AAAA,QACxB;AAAA,MACF,GAAG,CAAC,gBAAgB,aAAa,CAAC;AAElC,YAAM,qBAAqB,CAAC,WAAuB;AACjD,cAAM,MAAM,oBAAI,KAAK;AACrB,cAAM,QAAQ,oBAAI,KAAK;AACvB,YAAI,WAAW,QAAS,OAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AAAA,iBACxC,WAAW,MAAO,OAAM,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,iBACtD,WAAW,KAAM,OAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC;AAAA,iBAClD,WAAW,MAAO,OAAM,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAC7D,YAAI;AAAE,uBAAa,QAAQ,eAAe,MAAM;AAAA,QAAG,QAAQ;AAAA,QAAe;AAC1E,0BAAkB,EAAE,OAAO,IAAI,GAAG,MAAM;AAAA,MAC1C;AAGA,YAAM,gBAAY;AAAA,QAChB,OACG,OAAO,eAAe,CAAC,GAAG,IAAI,QAAM;AAAA,UACnC,MAAM,EAAE;AAAA,UACR,OAAO,EAAE;AAAA,UACT,cAAc,EAAE;AAAA,UAChB,kBAAkB,EAAE;AAAA,UACpB,aAAa,EAAE;AAAA,UACf,aAAa,EAAE;AAAA,UACf,oBAAoB,EAAE;AAAA,UACtB,gBAAgB,EAAE;AAAA,QACpB,EAAE;AAAA,QACJ,CAAC,KAAK;AAAA,MACR;AAGA,YAAM,qBAAiB,uBAAQ,MAAM;AACnC,YAAI,MAAM;AACV,eAAO,UAAU,IAAI,OAAK;AAAE,iBAAO,EAAE;AAAO,iBAAO,EAAE,MAAM,EAAE,MAAM,YAAY,IAAI;AAAA,QAAG,CAAC;AAAA,MACzF,GAAG,CAAC,SAAS,CAAC;AAGd,YAAM,sBAAkB;AAAA,QACtB,MACE,UACG,OAAO,OAAK,EAAE,cAAc,CAAC,EAC7B,IAAI,QAAM;AAAA,UACT,MAAM,EAAE;AAAA,UACR,aAAa,YAAa,EAAE,qBAAqB,EAAE,cAAe,KAAK,QAAQ,CAAC,CAAC;AAAA,QACnF,EAAE;AAAA,QACN,CAAC,SAAS;AAAA,MACZ;AAGA,YAAM,EAAE,kBAAkB,WAAW,eAAe,QAAI,uBAAQ,MAAM;AACpE,cAAM,OAAO,OAAO,kBAAkB,CAAC;AACvC,cAAM,cAAsC,CAAC;AAC7C,mBAAW,KAAK,KAAM,aAAY,EAAE,KAAK,KAAK,YAAY,EAAE,KAAK,KAAK,KAAK,EAAE;AAE7E,cAAM,MAAM,OAAO,QAAQ,WAAW,EACnC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,IAAI,CAAC,EAC5B,MAAM,GAAG,YAAY,EACrB,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAEjB,cAAM,UAAkD,CAAC;AACzD,mBAAW,KAAK,MAAM;AACpB,cAAI,CAAC,QAAQ,EAAE,IAAI,EAAG,SAAQ,EAAE,IAAI,IAAI,CAAC;AACzC,gBAAM,SAAS,IAAI,SAAS,EAAE,KAAK,IAAI,EAAE,QAAQ;AACjD,kBAAQ,EAAE,IAAI,EAAE,MAAM,KAAK,QAAQ,EAAE,IAAI,EAAE,MAAM,KAAK,KAAK,EAAE;AAAA,QAC/D;AAEA,cAAM,SAAS,OAAO,QAAQ,OAAO,EAClC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,EAAE,EAAE;AAEtC,cAAM,WAAW,OAAO,KAAK,OAAM,EAAU,QAAQ,CAAC;AACtD,eAAO,EAAE,kBAAkB,QAAQ,WAAW,WAAW,CAAC,GAAG,KAAK,OAAO,IAAI,IAAI;AAAA,MACnF,GAAG,CAAC,KAAK,CAAC;AAGV,YAAM,gBAAY,uBAAQ,MAAM;AAC9B,cAAM,UAAU,OAAO,QAA6B,OAAO,kBAAkB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,OAAO;AAAA,UACpG;AAAA,UACA,OAAO,EAAE;AAAA,UACT,cAAc,EAAE;AAAA,UAChB,kBAAkB,EAAE;AAAA,UACpB,aAAa,EAAE;AAAA,UACf,aAAa,EAAE;AAAA,UACf,oBAAoB,EAAE;AAAA,UACtB,gBAAgB,EAAE;AAAA,UAClB,aAAa,EAAE,eAAe,IAAI,EAAE,sBAAsB,EAAE,eAAe;AAAA,QAC7E,EAAE;AACF,eAAO,kBAAkB,QAAQ,UAAU,QAAQ,OAAO,OAAK,EAAE,UAAU,aAAa;AAAA,MAC1F,GAAG,CAAC,OAAO,aAAa,CAAC;AAGzB,YAAM,wBAAoB;AAAA,QACxB,MAAM,CAAC,GAAG,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,QAClE,CAAC,SAAS;AAAA,MACZ;AAGA,YAAM,cAAU;AAAA,QACd,MACE,OAAO,QAA2B,OAAO,gBAAgB,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC,OAAO;AAAA,UAClF;AAAA,UACA,UAAU,EAAE,aAAa,QAAQ,MAAM,GAAG,CAAC;AAAA,UAC3C,QAAQ,EAAE,WAAW;AAAA,UACrB,QAAQ,EAAE;AAAA,UACV,OAAO,EAAE;AAAA,UACT,aAAa,EAAE;AAAA,UACf,cAAc,EAAE;AAAA,UAChB,kBAAkB,EAAE;AAAA,UACpB,aAAa,EAAE;AAAA,UACf,oBAAoB,EAAE;AAAA,UACtB,gBAAgB,EAAE;AAAA,UAClB,aAAa,EAAE,eAAe,IAAI,EAAE,sBAAsB,EAAE,eAAe;AAAA,QAC7E,EAAE;AAAA,QACJ,CAAC,KAAK;AAAA,MACR;AAEA,YAAM,sBAAkB;AAAA,QACtB,MAAM,CAAC,GAAG,OAAO,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,QAChE,CAAC,OAAO;AAAA,MACV;AAEA,YAAM,gBAAgB,OAAO,gBAAgB;AAC7C,YAAM,qBAAqB,gBAAgB,KAAK,OAAO,uBAAuB,KAAK,gBAAgB;AACnG,YAAM,YAAY,cAAc,YAAY,IAAI;AAGhD,YAAM,mBAAwB,UAAU,OAAO,UAAU,MAAM,IAC3D,CAAC,GAAG,CAAC,YAAoB,KAAK,IAAI,SAAS,UAAU,GAAI,IAAI,IAAI,IACjE,CAAC,GAAG,MAAM;AAEd,YAAM,cAAoB,kBAAkB,IAAI,YAAY,SAAS,kBAAkB;AAEvF,YAAM,UAAU;AAAA,QACd;AAAA,UACE,OAAO;AAAA,UACP,OAAO,OAAO,OAAO,eAAe,CAAC;AAAA,UACrC,MAAM;AAAA,UACN,MAAM;AAAA,QACR;AAAA,QACA,GAAI,UAAU,SAAS,YAAY,UAAU,QAAQ,QAAQ,UAAU,cAAc,OACjF;AAAA,UACE;AAAA,YACE,OAAO;AAAA,YACP,OAAO,UAAU,YAAY,IAAI,OAAO,UAAU,SAAS,IAAI;AAAA,YAC/D,MAAM,GAAG,OAAO,UAAU,KAAK,CAAC,OAAO,OAAO,UAAU,GAAG,CAAC,SAAM,UAAU,cAAc,EAAE;AAAA,YAC5F,MAAO,UAAU,QAAQ,QAAQ,UAAU,OAAO,MAAM,WAAW;AAAA,UACrE;AAAA,QACF,IACA,CAAC;AAAA,QACL;AAAA,UACE,OAAO;AAAA,UACP,OAAO,OAAO,aAAa;AAAA,UAC3B,MAAM,GAAG,OAAO,OAAO,mBAAmB,CAAC,CAAC;AAAA,UAC5C,MAAM;AAAA,QACR;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,OAAO,gBAAgB,IAAI,OAAO,kBAAkB,IAAI;AAAA,UACxD,MAAM,gBAAgB,IAAI,GAAG,OAAO,OAAO,uBAAuB,CAAC,CAAC,eAAe;AAAA,UACnF,MAAM;AAAA,QACR;AAAA,QACA;AAAA,UACE,OAAO;AAAA,UACP,OAAO,WAAW,OAAO,gBAAgB,CAAC;AAAA,UAC1C,MAAM,GAAG,WAAW,OAAO,iBAAiB,CAAC,CAAC,YAAS,WAAW,OAAO,qBAAqB,CAAC,CAAC;AAAA,UAChG,MAAM;AAAA,QACR;AAAA,MACF;AAEA,YAAM,gBAAgB,MAAM;AAC1B,YAAI,SAAS;AACX,iBACE,8CAAC,iBAAAE,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,IAAI,EAAE,IAAI,EAAE,GACjC,wDAAC,iBAAAJ,SAAA,EAAS,SAAQ,WAAU,QAAQ,IAAI,GAC1C,GACF;AAAA,QAEJ;AACA,YAAI,QAAQ,WAAW,GAAG;AACxB,iBACE,8CAAC,iBAAAG,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,wDAAC,cAAW,SAAQ,kCAAiC,GAAE,GAChF;AAAA,QAEJ;AACA,eAAO,CAAC,GAAG,OAAO,EACf,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EACjE,IAAI,OACH,+CAAC,iBAAAD,SAAA,EACC;AAAA,yDAAC,kBAAAC,SAAA,EACC;AAAA,0DAAC,mBAAAH,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,YAAY,IAAI,GAAI,YAAE,UAAS;AAAA,YAChE,EAAE,SACD,+CAAC,mBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB;AAAA;AAAA,cAAO,EAAE;AAAA,eAAO,IACnE;AAAA,aACN;AAAA,UACA,8CAAC,kBAAAG,SAAA,EACC,yDAAC,aAAAF,SAAA,EAAI,SAAQ,QAAO,KAAK,KAAK,UAAS,QACpC;AAAA,cAAE,OAAO,MAAM,GAAG,CAAC,EAAE,IAAI,OACxB,8CAAC,WAAgB,OAAO,GAAG,OAAO,KAApB,CAAuB,CACtC;AAAA,YACA,EAAE,OAAO,SAAS,KAAK,8CAAC,WAAQ,OAAO,IAAI,EAAE,OAAO,SAAS,CAAC,IAAI,MAAM,OAAO;AAAA,aAClF,GACF;AAAA,UACA,8CAAC,kBAAAE,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,KAAK,GAAE;AAAA,UAC1C,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,WAAW,GAAE;AAAA,UAChD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,qBAAW,EAAE,WAAW,GAAE;AAAA,UACpD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,cAAc,GAAE;AAAA,UACnD,8CAAC,kBAAAA,SAAA,EACC,wDAAC,mBAAgB,MAAM,EAAE,aAAa,UAAU,EAAE,aAAa,GACjE;AAAA,aArBa,EAAE,OAsBjB,CACD;AAAA,MACL;AAEA,YAAM,kBAAkB,MAAM;AAC5B,YAAI,SAAS;AACX,iBACE,8CAAC,iBAAAD,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,IAAI,EAAE,IAAI,EAAE,GACjC,wDAAC,iBAAAJ,SAAA,EAAS,SAAQ,WAAU,QAAQ,IAAI,GAC1C,GACF;AAAA,QAEJ;AACA,YAAI,UAAU,WAAW,GAAG;AAC1B,iBACE,8CAAC,iBAAAG,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,wDAAC,cAAW,SAAQ,oCAAmC,GAAE,GAClF;AAAA,QAEJ;AACA,eAAO,CAAC,GAAG,SAAS,EACjB,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,cAAc,EAAE,WAAW,EACjE,IAAI,OACH,+CAAC,iBAAAD,SAAA,EACC;AAAA,wDAAC,kBAAAC,SAAA,EACC,yDAAC,aAAAF,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,GAC3C;AAAA,0DAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,cAAc,OAAO,SAAS,WAAW,EAAE,KAAK,GAAG,YAAY,EAAE,GAAG;AAAA,YACpG,8CAAC,mBAAAD,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,YAAY,IAAI,GAAI,YAAE,OAAM;AAAA,aAChE,GACF;AAAA,UACA,8CAAC,kBAAAG,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,KAAK,GAAE;AAAA,UAC1C,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,WAAW,GAAE;AAAA,UAChD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,kBAAkB,GAAE;AAAA,UACvD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,iBAAO,EAAE,cAAc,GAAE;AAAA,UACnD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,qBAAW,EAAE,YAAY,GAAE;AAAA,UACrD,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAS,qBAAW,EAAE,gBAAgB,GAAE;AAAA,UACzD,8CAAC,kBAAAA,SAAA,EACC,wDAAC,mBAAgB,MAAM,EAAE,aAAa,UAAU,EAAE,aAAa,GACjE;AAAA,aAfa,EAAE,KAgBjB,CACD;AAAA,MACL;AAEA,YAAM,eACJ;AAAA,QAAC,kBAAAC;AAAA,QAAA;AAAA,UACC,QAAM;AAAA,UACN,MAAK;AAAA,UACL,OAAM;AAAA,UACN,OAAO;AAAA,UACP,UAAU,OAAK,mBAAmB,EAAE,OAAO,KAAmB;AAAA,UAC9D,IAAI,EAAE,UAAU,IAAI;AAAA,UAElB,iBAAO,KAAK,aAAa,EAAmB,IAAI,OAChD,8CAAC,iBAAAC,SAAA,EAAiB,OAAO,GAAI,wBAAc,CAAC,KAA7B,CAA+B,CAC/C;AAAA;AAAA,MACH;AAGF,UAAI,YAAY;AACd,eACE;AAAA,UAAC;AAAA;AAAA,YACC,OAAM;AAAA,YACN,UAAU,GAAG,cAAc,aAAa,CAAC,SAAM,UAAU,MAAM,mBAAmB,CAAC,WAAM,UAAU,IAAI,mBAAmB,CAAC;AAAA,YAC3H,SAAS;AAAA,YAET,yDAAC,cAAAC,SAAA,EAAM,UAAS,SAAQ;AAAA;AAAA,cACO,WAAmB,WAAW;AAAA,cAC1D,gBACC,8CAAC,aAAAL,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,eAAAM,SAAA,EAAO,MAAK,SAAQ,SAAS,cAAc,mBAAK,GACnD;AAAA,eAEJ;AAAA;AAAA,QACF;AAAA,MAEJ;AAEA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,UAAU,GAAG,cAAc,aAAa,CAAC,SAAM,UAAU,MAAM,mBAAmB,CAAC,WAAM,UAAU,IAAI,mBAAmB,CAAC;AAAA,UAC3H,SAAS;AAAA,UAET;AAAA,0DAAC,eAAY,SAAkB;AAAA,YAE/B;AAAA,cAAC,aAAAN;AAAA,cAAA;AAAA,gBACC,IAAI;AAAA,kBACF,SAAS;AAAA,kBACT,YAAY;AAAA,kBACZ,gBAAgB;AAAA,kBAChB,KAAK;AAAA,kBACL,UAAU;AAAA,kBACV,IAAI;AAAA,kBACJ,IAAI;AAAA,gBACN;AAAA,gBAEA;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,OAAO;AAAA,sBACP,UAAU;AAAA,sBACV,SAAS;AAAA,wBACP,EAAE,OAAO,SAAS,OAAO,QAAQ;AAAA,wBACjC,EAAE,OAAO,UAAU,OAAO,iBAAiB;AAAA,wBAC3C,EAAE,OAAO,QAAQ,OAAO,eAAe;AAAA,sBACzC;AAAA;AAAA,kBACF;AAAA,kBACC,QAAQ,YACP;AAAA,oBAAC,kBAAAG;AAAA,oBAAA;AAAA,sBACC,QAAM;AAAA,sBACN,MAAK;AAAA,sBACL,OAAM;AAAA,sBACN,OAAO;AAAA,sBACP,UAAU,OAAK,iBAAiB,EAAE,OAAO,KAAK;AAAA,sBAC9C,IAAI,EAAE,UAAU,IAAI;AAAA,sBAEpB;AAAA,sEAAC,iBAAAC,SAAA,EAAS,OAAM,OAAM,wBAAU;AAAA,wBAC/B,OACE,OAAO,OAAK,eAAe,SAAS,EAAE,UAAU,CAAC,EACjD,IAAI,OACH,8CAAC,iBAAAA,SAAA,EAA4B,OAAO,EAAE,YAAa,YAAE,cAAtC,EAAE,UAA+C,CACjE;AAAA;AAAA;AAAA,kBACL;AAAA;AAAA;AAAA,YAEJ;AAAA,YAGC,QAAQ,WACP,+CAAC,YAAAG,SAAA,EAAK,WAAS,MAAC,SAAS,GAGvB;AAAA,4DAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IACb,yDAAC,aAAU,OAAM,wBAAuB,QAAQ,KAC9C;AAAA,8DAAC,mBAAgB,SAAkB,OAAO,iBAAiB,WAAW,GAAG,QAAQ,KAC/E,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,6BAAU,MAAM,kBAAkB,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GAChF;AAAA,gEAAC,iCAAe,GAAG,MAAM,MAAM;AAAA,kBAC/B,8CAAC,yBAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,kBACnE,8CAAC,yBAAM,eAAe,eAAe,OAAO,IAAK,GAAG,MAAM,MAAM;AAAA,kBAChE;AAAA,oBAAC;AAAA;AAAA,sBACC,QAAQ,MAAM;AAAA,sBACd,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,UAAQ,MAAC;AAAA;AAAA,kBAC1D;AAAA,kBACC,eAAe,IAAI,OAClB;AAAA,oBAAC;AAAA;AAAA,sBAEC,MAAK;AAAA,sBACL,SAAS;AAAA,sBACT,SAAQ;AAAA,sBACR,QAAQ,WAAW,CAAC;AAAA,sBACpB,aAAa;AAAA,sBACb,MAAM,WAAW,CAAC;AAAA,sBAClB,aAAa;AAAA;AAAA,oBAPR;AAAA,kBAQP,CACD;AAAA,mBACH,GACF,GACF;AAAA,gBACC,CAAC,WAAW,eAAe,SAAS,KACnC,8CAAC,gBAAa,QAAQ,eAAe,IAAI,QAAM,EAAE,MAAM,GAAG,OAAO,WAAW,CAAC,EAAE,EAAE,GAAG;AAAA,iBAExF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,aAAU,OAAM,qBACf,wDAAC,mBAAgB,SAAkB,OAAO,UAAU,WAAW,GAC7D,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,6BAAU,MAAM,WAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GACzE;AAAA,8DAAC,iCAAe,GAAG,MAAM,MAAM;AAAA,gBAC/B,8CAAC,yBAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,gBACnE,8CAAC,yBAAM,eAAe,YAAY,OAAO,IAAK,GAAG,MAAM,MAAM;AAAA,gBAC7D,8CAAC,2BAAQ,QAAQ,MAAM,QAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,GAAI;AAAA,gBAClF,8CAAC,0BAAQ,GAAG,MAAM,QAAQ;AAAA,gBAC1B,8CAAC,wBAAK,MAAK,YAAW,SAAQ,gBAAe,MAAK,SAAQ,SAAQ,OAAM,QAAQ,OAAO,OAAO,aAAa,KAAK,MAAM,OAAO,OAAO,aAAa,MAAM;AAAA,gBACvJ,8CAAC,wBAAK,MAAK,YAAW,SAAQ,oBAAmB,MAAK,UAAS,SAAQ,OAAM,QAAQ,OAAO,QAAQ,aAAa,KAAK,MAAM,OAAO,QAAQ,aAAa,MAAM;AAAA,iBAChK,GACF,GACF,GACF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,aAAU,OAAM,kBACf,wDAAC,mBAAgB,SAAkB,OAAO,UAAU,WAAW,GAC7D,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,4BAAS,MAAM,WAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GAAG,gBAAe,OAC1F;AAAA,8DAAC,iCAAe,GAAG,MAAM,MAAM;AAAA,gBAC/B,8CAAC,yBAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,gBACnE,8CAAC,yBAAM,eAAe,YAAY,OAAO,IAAK,GAAG,MAAM,MAAM;AAAA,gBAC7D,8CAAC,2BAAQ,QAAQ,MAAM,QAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,GAAI;AAAA,gBAClF,8CAAC,0BAAQ,GAAG,MAAM,QAAQ;AAAA,gBAC1B,8CAAC,uBAAI,SAAQ,sBAAqB,MAAK,cAAa,MAAM,OAAO,SAAS,SAAQ,KAAI;AAAA,gBACtF,8CAAC,uBAAI,SAAQ,kBAAiB,MAAK,UAAS,MAAM,OAAO,SAAS,SAAQ,KAAI,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG;AAAA,iBACtG,GACF,GACF,GACF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,aAAU,OAAM,sBACf,wDAAC,mBAAgB,SAAkB,OAAO,gBAAgB,WAAW,GACnE,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,6BAAU,MAAM,iBAAiB,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GAC/E;AAAA,8DAAC,iCAAe,GAAG,MAAM,MAAM;AAAA,gBAC/B,8CAAC,yBAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,gBACnE,8CAAC,yBAAM,QAAQ,CAAC,GAAG,GAAG,GAAG,eAAe,OAAK,GAAG,CAAC,KAAK,OAAO,IAAK,GAAG,MAAM,MAAM;AAAA,gBACjF;AAAA,kBAAC;AAAA;AAAA,oBACC,QAAQ,MAAM;AAAA,oBACd,SAAS,8CAAC,gBAAa,gBAAgB,CAAC,MAAc,GAAG,CAAC,KAAK;AAAA;AAAA,gBACjE;AAAA,gBACA,8CAAC,iCAAc,GAAG,KAAK,QAAQ,OAAO,SAAS,iBAAgB,OAAM,eAAe,KAAK;AAAA,gBACzF;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,QAAQ,OAAO;AAAA,oBACf,aAAa;AAAA,oBACb,KAAK,EAAE,GAAG,KAAK,aAAa,GAAG,MAAM,OAAO,MAAM;AAAA,oBAClD,WAAW,EAAE,GAAG,EAAE;AAAA;AAAA,gBACpB;AAAA,iBACF,GACF,GACF,GACF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAM;AAAA,kBAEN,wDAAC,mBAAgB,SAAkB,OAAO,eAAe,WAAW,GAClE,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,6BAAU,MAAM,gBAAgB,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GAC9E;AAAA,kEAAC,iCAAe,GAAG,MAAM,MAAM;AAAA,oBAC/B,8CAAC,yBAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,oBACnE;AAAA,sBAAC;AAAA;AAAA,wBACC,eAAe;AAAA,wBACf,OAAO;AAAA,wBACP,QAAQ;AAAA,wBACP,GAAG,MAAM;AAAA;AAAA,oBACZ;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACC,QAAQ,MAAM;AAAA,wBACd,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ;AAAA;AAAA,oBACjD;AAAA,oBACC,UAAU,OAAO,UAAU,MAAM,KAChC;AAAA,sBAAC;AAAA;AAAA,wBACC,GAAG,UAAU;AAAA,wBACb,QAAQ,OAAO;AAAA,wBACf,iBAAgB;AAAA,wBAChB,OAAO,EAAE,OAAO,UAAU,OAAO,UAAU,GAAG,CAAC,IAAI,UAAU,kBAAkB,UAAU,IAAI,MAAM,OAAO,OAAO;AAAA;AAAA,oBACnH;AAAA,oBAEF;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAQ;AAAA,wBACR,MAAK;AAAA,wBACL,QAAQ,OAAO;AAAA,wBACf,aAAa;AAAA,wBACb,MAAM,OAAO;AAAA,wBACb,aAAa;AAAA;AAAA,oBACf;AAAA,qBACF,GACF,GACF;AAAA;AAAA,cACF,GACF;AAAA,eACF;AAAA,YAID,QAAQ,YACP,+CAAC,YAAAA,SAAA,EAAK,WAAS,MAAC,SAAS,GACvB;AAAA,4DAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,aAAU,OAAM,kBAAiB,QAAQ,KAAK,IAAI,KAAK,kBAAkB,SAAS,EAAE,GACnF;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,OAAO,kBAAkB,WAAW;AAAA,kBACpC,QAAQ,KAAK,IAAI,KAAK,kBAAkB,SAAS,EAAE;AAAA,kBAEnD,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,4BAAS,MAAM,mBAAmB,QAAO,YAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,GAAG,QAAQ,EAAE,GACnG;AAAA,kEAAC,iCAAe,GAAG,MAAM,MAAM,UAAQ,MAAC,YAAY,OAAO;AAAA,oBAC3D,8CAAC,yBAAM,MAAK,UAAS,eAAe,eAAgB,GAAG,MAAM,MAAM;AAAA,oBACnE,8CAAC,yBAAM,MAAK,YAAW,SAAQ,SAAQ,OAAO,KAAM,GAAG,MAAM,MAAM,MAAM,EAAE,UAAU,MAAM,MAAM,MAAM,KAAK,KAAK,KAAK,GAAG;AAAA,oBACzH,8CAAC,2BAAQ,QAAQ,MAAM,QAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,gBAAgB,OAAK,GAAG,GAAI;AAAA,oBAC1G,8CAAC,uBAAI,SAAQ,SAAQ,MAAK,SAAQ,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,SAAS,IAC9D,4BAAkB,IAAI,OACrB,8CAAC,wBAAmB,MAAM,WAAW,EAAE,KAAK,KAAjC,EAAE,KAAkC,CAChD,GACH;AAAA,qBACF,GACF;AAAA;AAAA,cACF,GACF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,aAAU,OAAM,mBAAkB,QAAQ,KAAK,IAAI,KAAK,kBAAkB,SAAS,EAAE,GACpF;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,OAAO,UAAU,WAAW;AAAA,kBAC5B,QAAQ,KAAK,IAAI,KAAK,kBAAkB,SAAS,EAAE;AAAA,kBAEnD,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,4BAAS,MAAM,mBAAmB,QAAO,YAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,GAAG,QAAQ,EAAE,GACnG;AAAA,kEAAC,iCAAe,GAAG,MAAM,MAAM,UAAQ,MAAC,YAAY,OAAO;AAAA,oBAC3D,8CAAC,yBAAM,MAAK,UAAS,eAAe,YAAa,GAAG,MAAM,MAAM;AAAA,oBAChE,8CAAC,yBAAM,MAAK,YAAW,SAAQ,SAAQ,OAAO,KAAM,GAAG,MAAM,MAAM,MAAM,EAAE,UAAU,MAAM,MAAM,MAAM,KAAK,KAAK,KAAK,GAAG;AAAA,oBACzH,8CAAC,2BAAQ,QAAQ,MAAM,QAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,gBAAgB,OAAK,GAAG,GAAI;AAAA,oBAC1G,8CAAC,0BAAQ,GAAG,MAAM,QAAQ;AAAA,oBAC1B,8CAAC,uBAAI,SAAQ,gBAAe,MAAK,SAAQ,MAAM,OAAO,OAAO,SAAQ,KAAI,SAAS,IAAI;AAAA,oBACtF,8CAAC,uBAAI,SAAQ,oBAAmB,MAAK,UAAS,MAAM,OAAO,QAAQ,SAAQ,KAAI,SAAS,IAAI,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG;AAAA,qBACpH,GACF;AAAA;AAAA,cACF,GACF,GACF;AAAA,cAEA,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IACb,wDAAC,uBAAAC,SAAA,EAAe,WAAW,cAAAC,SAAO,SAAQ,YAAW,IAAI,EAAE,cAAc,EAAE,GACzE,yDAAC,cAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,8DAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAAV,SAAA,EACC;AAAA,gEAAC,kBAAAC,SAAA,EAAU,mBAAK;AAAA,kBAChB,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,mBAAK;AAAA,kBAC9B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,sBAAQ;AAAA,kBACjC,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,qBAAO;AAAA,kBAChC,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,oBAAM;AAAA,kBAC/B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,mBAAK;AAAA,kBAC9B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,oBAAM;AAAA,kBAC/B,8CAAC,kBAAAA,SAAA,EAAU,IAAI,EAAE,OAAO,IAAI,GAAG,0BAAY;AAAA,mBAC7C,GACF;AAAA,gBACA,8CAAC,kBAAAU,SAAA,EACE,0BAAgB,GACnB;AAAA,iBACF,GACF,GACF;AAAA,eACF;AAAA,YAID,QAAQ,UACP,+CAAC,YAAAL,SAAA,EAAK,WAAS,MAAC,SAAS,GACrB;AAAA,0BAAW,gBAAgB,SAAS,MACpC,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IACb,wDAAC,aAAU,OAAM,gBAAe,QAAQ,KAAK,IAAI,KAAK,gBAAgB,SAAS,EAAE,GAC/E;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA,OAAO,gBAAgB,WAAW;AAAA,kBAClC,QAAQ,KAAK,IAAI,KAAK,gBAAgB,SAAS,EAAE;AAAA,kBAEjD,wDAAC,uCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,4BAAS,MAAM,iBAAiB,QAAO,YAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,IAAI,MAAM,GAAG,QAAQ,EAAE,GACjG;AAAA,kEAAC,iCAAe,GAAG,MAAM,MAAM,UAAQ,MAAC,YAAY,OAAO;AAAA,oBAC3D,8CAAC,yBAAM,MAAK,UAAS,eAAe,eAAgB,GAAG,MAAM,MAAM;AAAA,oBACnE,8CAAC,yBAAM,MAAK,YAAW,SAAQ,YAAW,OAAO,KAAM,GAAG,MAAM,MAAM,MAAM,EAAE,UAAU,MAAM,MAAM,MAAM,KAAK,KAAK,KAAK,GAAG;AAAA,oBAC5H,8CAAC,2BAAQ,QAAQ,MAAM,QAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,gBAAgB,OAAK,GAAG,GAAI;AAAA,oBAC1G,8CAAC,uBAAI,SAAQ,SAAQ,MAAK,SAAQ,MAAM,OAAO,OAAO,QAAQ,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,SAAS,IAAI;AAAA,qBAC3F,GACF;AAAA;AAAA,cACF,GACF,GACF;AAAA,cAGF,8CAAC,YAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IACb,wDAAC,uBAAAC,SAAA,EAAe,WAAW,cAAAC,SAAO,SAAQ,YAAW,IAAI,EAAE,cAAc,EAAE,GACzE,yDAAC,cAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,8DAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAAV,SAAA,EACC;AAAA,gEAAC,kBAAAC,SAAA,EAAU,iBAAG;AAAA,kBACd,8CAAC,kBAAAA,SAAA,EAAU,oBAAM;AAAA,kBACjB,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,mBAAK;AAAA,kBAC9B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,sBAAQ;AAAA,kBACjC,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,oBAAM;AAAA,kBAC/B,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,oBAAM;AAAA,kBAC/B,8CAAC,kBAAAA,SAAA,EAAU,IAAI,EAAE,OAAO,IAAI,GAAG,0BAAY;AAAA,mBAC7C,GACF;AAAA,gBACA,8CAAC,kBAAAU,SAAA,EACE,wBAAc,GACjB;AAAA,iBACF,GACF,GACF;AAAA,eACF;AAAA;AAAA;AAAA,MAEJ;AAAA,IAEJ;AAAA;AAAA;;;AChuBO,SAAS,qBAAqB,OAAyB;AAC5D,MAAI,OAAO,UAAU,UAAU;AAC7B,WAAO,UAAU;AAAA,EACnB;AACA,MAAI,iBAAiB,UAAU;AAC7B,UAAM,OAAO,MAAM;AACnB,WACE,MAAM,WAAW,OACjB,CAAC,CAAC,QACF,OAAO,SAAS,YAChB,KAAK,UAAU;AAAA,EAEnB;AACA,MAAI,iBAAiB,OAAO;AAC1B,WAAO,MAAM,YAAY;AAAA,EAC3B;AACA,SAAO;AACT;AA8BO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA,SAAS;AACX,GAAuC;AACrC,MAAI,SAAS;AACX,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAEA,MAAI,OAAO;AACT,QAAI,qBAAqB,KAAK,GAAG;AAC/B,aAAO,EAAE,MAAM,gBAAgB;AAAA,IACjC;AACA,WAAO,EAAE,MAAM,SAAS,SAAS,sBAAsB;AAAA,EACzD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,kBAAkB,eAAe,QAAQ,eAAe;AAAA,EAC1D;AACF;AA/FA,IAYa,uBACA,mBAEP;AAfN;AAAA;AAAA;AAUA;AAEO,IAAM,wBAAwB;AAC9B,IAAM,oBAAoB;AAEjC,IAAM,gCAAgC;AAAA;AAAA;;;ACG/B,SAAS,eAAe,MAAwB,OAAsB;AAC3E,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAW,aAAO,MAAM,QAAQ,QAAQ;AAAA,IAC7C,KAAK;AAAW,aAAO,MAAM,QAAQ,QAAQ;AAAA,IAC7C,KAAK;AAAU,aAAO,MAAM,QAAQ,MAAM;AAAA,IAC1C,KAAK;AAAQ,aAAO,MAAM,QAAQ,KAAK;AAAA,IACvC;AAAS,aAAO,MAAM,QAAQ,QAAQ;AAAA,EACxC;AACF;AA1BA,IAOAC,cACAC,eACAC,qBACAC,gBAEAC,yBAwBQC,sBAPK,WA4EA,aAuBA,cAyBA,iBAeA;AAxKb;AAAA;AAAA;AAOA,IAAAL,eAAgB;AAChB,IAAAC,gBAAkB;AAClB,IAAAC,sBAAuB;AACvB,IAAAC,iBAAgC;AAEhC,IAAAC,0BAAqB;AACrB;AACA;AACA;AAqBQ,IAAAC,uBAAA;AAPD,IAAM,YAAwC,CAAC,EAAE,MAAM,MAAM;AAClE,YAAM,OAAOC,YAAW,MAAM,GAAG;AACjC,YAAM,MAAM,KAAK,MAAM,MAAM,GAAG;AAChC,YAAM,UAAU,MAAM,cAAc,UAAa,MAAM,SAAS,MAAM;AACtE,aACE,+CAAC,cAAAC,SAAA,EAAM,SAAQ,YAAW,IAAI,EAAE,IAAI,KAAK,IAAI,MAAM,cAAc,IAAI,GACnE;AAAA,uDAAC,aAAAC,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,YAAY,gBAAgB,iBAAiB,KAAK,IAAI,GAC5F;AAAA,yDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,GAC9B;AAAA;AAAA,cAAC,oBAAAC;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,IAAI,EAAE,YAAY,KAAK,UAAU,UAAU,cAAc,YAAY,YAAY,SAAS;AAAA,gBAC1F,OAAO,MAAM,WAAW,GAAG,MAAM,KAAK,SAAM,MAAM,QAAQ,KAAK,MAAM;AAAA,gBAEpE,gBAAM;AAAA;AAAA,YACT;AAAA,YACC,MAAM,YACL;AAAA,cAAC,oBAAAA;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,OAAM;AAAA,gBACN,IAAI;AAAA,kBACF,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,SAAS;AAAA,kBACT,UAAU;AAAA,kBACV,cAAc;AAAA,kBACd,YAAY;AAAA,gBACd;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,aAEJ;AAAA,UACC,MAAM,SACL,+CAAC,oBAAAA,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,YAAY,KAAK,oBAAoB,gBAAgB,YAAY,SAAS,GACzG;AAAA;AAAA,YAAI;AAAA,aACP,IAEA,+CAAC,oBAAAA,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,YAAY,KAAK,oBAAoB,gBAAgB,YAAY,SAAS,GACzG;AAAA,mBAAO,MAAM,KAAK;AAAA,YACnB,+CAAC,aAAAD,SAAA,EAAI,WAAU,QAAO,OAAM,kBAAiB,IAAI,EAAE,YAAY,IAAI,GAChE;AAAA;AAAA,cACA,OAAO,MAAM,MAAM;AAAA,eACtB;AAAA,aACF;AAAA,WAEJ;AAAA,QACA,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,SAAM,OAAO,MAAM,KAAK,MAAY,QAAQ,GAAG,GAClD;AAAA,QACA;AAAA,UAAC,aAAAA;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,SAAS;AAAA,cACT,gBAAgB;AAAA,cAChB,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,IAAI;AAAA,YACN;AAAA,YAEA;AAAA,4DAAC,oBAAAC,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GAC3F,gBAAM,SACL,+EAAE,6BAAe,IAEjB,gFAAG;AAAA;AAAA,gBAAI;AAAA,gBAAY,WAAW;AAAA,iBAAwB,GAE1D;AAAA,cACA,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBACjC,4BAAkB,MAAM,cAAc,IACnC,UAAU,kBAAkB,MAAM,cAAc,CAAC,KACjD,gBACN;AAAA;AAAA;AAAA,QACF;AAAA,SACF;AAAA,IAEJ;AAGO,IAAM,cAA0C,CAAC,EAAE,MAAM,MAAM;AACpE,YAAM,YAAQ,yBAAS;AACvB,YAAM,OAAOH,YAAW,MAAM,GAAG;AACjC,aACE,+CAAC,aAAAE,SAAA,EACC;AAAA;AAAA,UAAC,oBAAAC;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,eAAe;AAAA,cACf,eAAe;AAAA,cACf,OAAO,SAAS,WAAW,MAAM,QAAQ,KAAK,YAAY,eAAe,MAAM,KAAK;AAAA,cACpF,IAAI;AAAA,YACN;AAAA,YAEC,gBAAM;AAAA;AAAA,QACT;AAAA,QACA,8CAAC,aAAU,OAAc;AAAA,SAC3B;AAAA,IAEJ;AAGO,IAAM,eAAqE,CAAC;AAAA,MACjF;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,OAAO,SAAS,IAAI,KAAK,qBAAqB,QAAQ,IAAI,MAAM,EAAE;AACxE,UAAI,CAAC,MAAM;AACT,eACE,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBACjC,gBACH;AAAA,MAEJ;AACA,aACE,+CAAC,gCAAK,IAAI,MAAM,SAAQ,WACrB;AAAA;AAAA,QAAK;AAAA,SACR;AAAA,IAEJ;AAOO,IAAM,kBAKR,CAAC,EAAE,QAAQ,iBAAiB,GAAG,SAAS,MAC3C,+CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,KAAK,GAC5D;AAAA,aAAO,IAAI,WACV,8CAAC,eAAmE,SAAlD,GAAG,MAAM,IAAI,IAAI,MAAM,YAAY,MAAM,KAAK,EAAkB,CACnF;AAAA,MACA,iBAAiB,KAAK,8CAAC,gBAAa,OAAO,gBAAgB,MAAM,UAAU;AAAA,OAC9E;AAIK,IAAM,iBAA8C,CAAC,EAAE,SAAS,MACrE;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,IAAI,YAAU;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,cAAc;AAAA,UACd,aAAS,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,QACxF;AAAA,QAEC;AAAA;AAAA,IACH;AAAA;AAAA;;;AC7KK,SAAS,cAAc,SAAiD;AAC7E,MAAI,YAAY,QAAW;AACzB,WAAO;AAAA,EACT;AACA,SAAO,GAAG,OAAO;AACnB;AAVA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAwBAE,eACAC,6BACAC,eACAC,cACAC,qBACAC,kBACA,iBACAC,oBACAC,wBACAC,gBAuEIC,sBAXE,YA8DA,gBAiBA,qBAWA,eAqBA,UA2DA,aA0BO;AAjSb;AAAA;AAAA;AAwBA,IAAAT,gBAAwD;AACxD,IAAAC,8BAA4B;AAC5B,IAAAC,gBAAkB;AAClB,IAAAC,eAAgB;AAChB,IAAAC,sBAAuB;AACvB,IAAAC,mBAAqB;AACrB,sBAAqB;AACrB,IAAAC,qBAAuB;AACvB,IAAAC,yBAA2B;AAC3B,IAAAC,iBAAsB;AACtB;AAEA;AACA;AACA;AAMA;AAOA;AACA;AAoDI,IAAAC,uBAAA;AAXJ,IAAM,aAAkC,CAAC;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MACE,+CAAC,aAAAC,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,KAAK,IAAI,GAEnC;AAAA,qDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,YAAY,UAAU,OAAO,IAAI,YAAY,EAAE,GAClG;AAAA;AAAA,UAAC,aAAAA;AAAA,UAAA;AAAA,YACC,IAAI,YAAU;AAAA,cACZ,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,cAAc;AAAA,cACd,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,gBAAgB;AAAA,cAChB,aAAS,sBAAM,eAAe,MAAM,KAAK,GAAG,IAAI;AAAA,cAChD,OAAO,eAAe,MAAM,KAAK;AAAA,cACjC,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACA;AAAA,UAAC,aAAAA;AAAA,UAAA;AAAA,YACC,IAAI,YAAU;AAAA,cACZ,MAAM;AAAA,cACN,OAAO;AAAA,cACP,WAAW;AAAA,cACX,SAAS,SAAS,oBAAgB,sBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,YAC1E;AAAA;AAAA,QACF;AAAA,SACF;AAAA,MAEA,+CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,SAAS,IAAI,EAAE,GAClD;AAAA,uDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,YAAY,KAAK,GAAG,UAAU,QAAQ,IAAI,KAAK,GACrF;AAAA;AAAA,YAAC,oBAAAC;AAAA,YAAA;AAAA,cACC,IAAI,YAAU;AAAA,gBACZ,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,eAAe;AAAA,gBACf,eAAe;AAAA,gBACf,OAAO,eAAe,MAAM,KAAK;AAAA,cACnC;AAAA,cAEC;AAAA;AAAA,UACH;AAAA,UACA,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,UAAU,KAAK,GACvE,mBACH;AAAA,UACC,QAAQ,8CAAC,cAAW,OAAO,MAAM,MAAK,WAAU,KAAK,OAAO,IAAI,EAAE,IAAI,OAAO,GAAG;AAAA,WACnF;AAAA,QACA,8CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GAAI,UAAS;AAAA,SAC3E;AAAA,OACF;AAGF,IAAM,iBAA8C,CAAC,EAAE,SAAS,MAC9D;AAAA,MAAC,cAAAE;AAAA,MAAA;AAAA,QACC,SAAQ;AAAA,QACR,IAAI,YAAU;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,cAAc;AAAA,UACd,aAAS,sBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,KAAK;AAAA,QACzF;AAAA,QAEA,wDAAC,oBAAAD,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,UAAU,GAAG,GACnE,UACH;AAAA;AAAA,IACF;AAIF,IAAM,sBAA2D;AAAA,MAC/D,KAAK;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,IACR;AAOA,IAAM,gBAA6C,CAAC,EAAE,UAAU,MAC9D;AAAA,MAAC,aAAAD;AAAA,MAAA;AAAA,QACC,IAAI,YAAU;AAAA,UACZ,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,cAAc;AAAA,UACd,QAAQ;AAAA,UACR,iBAAa,sBAAM,MAAM,QAAQ,KAAK,SAAS,IAAI;AAAA,QACrD;AAAA,QAEA,yDAAC,oBAAAC,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,SAAQ,SAC3D;AAAA,wDAAC,OAAE,oBAAM;AAAA,UAAI;AAAA,UAGZ,aACC;AAAA,WACJ;AAAA;AAAA,IACF;AAIF,IAAM,WAA8D,CAAC,EAAE,SAAS,SAAS,MAAM;AAC7F,YAAM,kBAAkB,QAAQ,KAAK,SAAS,QAAQ,qBAAqB;AAC3E,aACE,gFACE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAM,kBAAkB,SAAY;AAAA,YAEnC;AAAA,eAAC,mBACA,8CAAC,kBAAe,+DAAiD;AAAA,cAElE,QAAQ,KAAK,IAAI,OAChB,8CAAC,aAAsC,OAAO,KAA9B,EAAE,YAAY,EAAE,KAAiB,CAClD;AAAA,cACA,QAAQ,qBAAqB,KAAK,YACjC,8CAAC,gBAAa,OAAO,QAAQ,oBAAoB,MAAM,UAAU;AAAA;AAAA;AAAA,QAErE;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YAEJ,kBAAQ,OACP,8CAAC,aAAU,OAAO,QAAQ,MAAM,IAEhC,8CAAC,kBAAe,wDAA0C;AAAA;AAAA,QAE9D;AAAA,QAEA,8CAAC,cAAW,MAAM,GAAG,MAAK,QAAO,SAAQ,8CACtC,kBAAQ,MAAM,SAAS,IACpB,QAAQ,MAAM,IAAI,OAChB,8CAAC,aAAsC,OAAO,KAA9B,EAAE,YAAY,EAAE,KAAiB,CAClD,IAED,8CAAC,kBAAe,iDAAmC,GAEzD;AAAA,QAEA,8CAAC,cAAW,MAAM,GAAG,MAAK,UAAS,SAAQ,oCAAmC,QAAM,MAClF,wDAAC,kBAAe,+JAGhB,GACF;AAAA,QAEA,8CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,iBAAc,WAAS,MAAC,GAC3B;AAAA,SACF;AAAA,IAEJ;AAGA,IAAM,cAAiE,CAAC,EAAE,SAAS,SAAS,MAAM;AAChG,YAAM,EAAE,MAAM,IAAI,eAAe,OAAO;AACxC,UAAI,UAAU,GAAG;AACf,eACE,8CAAC,oBAAAC,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,UAAU,GAAG,GAAG,sDAEzE;AAAA,MAEJ;AACA,aACE,+CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,KAAK,GAC7D;AAAA,sDAAC,iBAAc;AAAA,QACd,QAAQ,KAAK,IAAI,OAChB,8CAAC,eAAwC,OAAO,KAA9B,EAAE,YAAY,EAAE,KAAiB,CACpD;AAAA,QACA,QAAQ,qBAAqB,KAAK,YACjC,8CAAC,gBAAa,OAAO,QAAQ,oBAAoB,MAAM,UAAU;AAAA,QAElE,QAAQ,QAAQ,8CAAC,eAAY,OAAO,QAAQ,MAAM;AAAA,QAClD,QAAQ,MAAM,IAAI,OACjB,8CAAC,eAAwC,OAAO,KAA9B,EAAE,YAAY,EAAE,KAAiB,CACpD;AAAA,SACH;AAAA,IAEJ;AAEO,IAAM,sBAAoD,CAAC;AAAA,MAChE,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,MACV,cAAc;AAAA,MACd,kBAAkB;AAAA,MAClB;AAAA,MACA,UAAU;AAAA,MACV,OAAO;AAAA,MACP,MAAM;AAAA,IACR,MAAM;AACJ,YAAM,EAAE,UAAU,cAAc,OAAO,WAAW,MAAM,UAAU,SAAS,MAAM,IAAI,kBAAkB;AACvG,YAAM,qBAAiB,yCAAY,YAAY;AAC/C,YAAM,WAAW,cAAc,iBAAiB,CAAC;AACjD,YAAM,CAAC,UAAU,WAAW,QAAI,wBAAS,eAAe;AACxD,YAAM,2BAAuB,qBAAM;AAGnC,YAAM,OAAO,iBAAiB,SAAY,eAAe;AACzD,YAAM,QAAQ,cAAc,SAAY,YAAY;AACpD,YAAM,OAAO,aAAa,SAAY,WAAW;AAEjD,YAAM,gBAAY;AAAA,QAChB,MAAM,gBAAgB;AAAA,UACpB;AAAA,UACA;AAAA,UACA,UAAU;AAAA,UACV,YAAY;AAAA;AAAA,UACZ,UAAU,MAAM,UAAU,KAAK;AAAA,QACjC,CAAC;AAAA,QACD,CAAC,SAAS,OAAO,MAAM,IAAI;AAAA,MAC7B;AAEA,YAAM,cAAU;AAAA,QACd,MAAM,mBAAmB,MAAM,OAAO,MAAM,OAAO;AAAA,QACnD,CAAC,MAAM,OAAO,MAAM,OAAO;AAAA,MAC7B;AACA,YAAM,eAAW,uBAAQ,MAAM,eAAe,OAAO,GAAG,CAAC,OAAO,CAAC;AAEjE,YAAM,aAAa,GAAG,SAAS,KAAK,SAAS,SAAS,UAAU,IAAI,KAAK,GAAG;AAC5E,YAAM,cACJ,SAAS,YAAY,OACjB,KACA,kBAAe,oBAAoB,SAAS,QAAQ,IAAI,CAAC,IAAI,KAAK;AAAA,QAChE,SAAS,QAAQ;AAAA,MACnB,CAAC;AACP,YAAM,cACJ,SAAS,UAAU,IAAI,oBAAoB,GAAG,UAAU,GAAG,WAAW;AAExE,YAAM,OACJ,gFACG;AAAA,kBAAU,SAAS,aAClB,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,WAAW,IAAI,GACvB,WAAC,GAAG,GAAG,GAAG,CAAC,EAAE,IAAI,OAChB,+CAAC,aAAAA,SAAA,EAAY,IAAI,EAAE,SAAS,QAAQ,KAAK,GAAG,IAAI,EAAE,GAChD;AAAA,wDAAC,iBAAAG,SAAA,EAAS,SAAQ,eAAc,OAAO,IAAI,QAAQ,IAAI,IAAI,EAAE,YAAY,GAAG,IAAI,IAAI,GAAG;AAAA,UACvF,+CAAC,aAAAH,SAAA,EAAI,IAAI,EAAE,MAAM,EAAE,GACjB;AAAA,0DAAC,iBAAAG,SAAA,EAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI,IAAI,EAAE,IAAI,IAAI,GAAG;AAAA,YAClE,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,eAAc,OAAM,QAAO,QAAQ,GAAG,IAAI,EAAE,IAAI,IAAI,GAAG;AAAA,YACzE,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI;AAAA,aACnD;AAAA,aANQ,CAOV,CACD,GACH;AAAA,QAGD,UAAU,SAAS,WAClB,8CAAC,oBAAAF,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,IAAI,GAC9D,oBAAU,SACb;AAAA,QAGD,UAAU,SAAS,mBAClB,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,IAAI,GAC9D,6BACH;AAAA,QAGD,UAAU,SAAS,YACjB,UAAU,8CAAC,eAAY,SAAkB,UAAoB,IAAK,8CAAC,YAAS,SAAkB,UAAoB;AAAA,SACvH;AAGF,aACE,+CAAC,cAAAC,SAAA,EAAM,IAAI,EAAE,GAAG,EAAE,GACf;AAAA,sBACC;AAAA,UAAC,aAAAF;AAAA,UAAA;AAAA,YACC,SAAS,MAAM,YAAY,OAAK,CAAC,CAAC;AAAA,YAClC,IAAI;AAAA,cACF,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,KAAK;AAAA,cACL,QAAQ;AAAA,cACR,YAAY;AAAA,cACZ,IAAI,WAAW,MAAM;AAAA,YACvB;AAAA,YAEA;AAAA,6DAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,GAC9B;AAAA,8DAAC,oBAAAC,SAAA,EAAW,SAAQ,MAAK,YAAY,KAAM,iBAAM;AAAA,gBAChD,UAAU,SAAS,WAClB,8CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,IAAI,IAAI,GACjB;AAAA,kBAAC;AAAA;AAAA,oBACC,OAAO;AAAA,oBACP,MAAMI,YAAW,SAAS,SAAS,OAAO,CAAC;AAAA;AAAA,gBAC7C,GACF;AAAA,iBAEJ;AAAA,cACA;AAAA,gBAAC,mBAAAC;AAAA,gBAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAY,WAAW,2BAA2B;AAAA,kBAClD,iBAAe;AAAA,kBACf,iBAAe;AAAA,kBACf,SAAS,OAAK;AACZ,sBAAE,gBAAgB;AAClB,gCAAY,OAAK,CAAC,CAAC;AAAA,kBACrB;AAAA,kBACA,IAAI,YAAU;AAAA,oBACZ,OAAO,MAAM,QAAQ,KAAK;AAAA,oBAC1B,WAAW,WAAW,mBAAmB;AAAA,oBACzC,YAAY,MAAM,YAAY,OAAO,WAAW;AAAA,kBAClD;AAAA,kBAEA,wDAAC,qCAAW;AAAA;AAAA,cACd;AAAA;AAAA;AAAA,QACF,IAEA,+CAAC,aAAAL,SAAA,EAAI,IAAI,EAAE,IAAI,IAAI,GACjB;AAAA,wDAAC,oBAAAC,SAAA,EAAW,SAAQ,MAAK,YAAY,KAAM,iBAAM;AAAA,UACjD,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,yEAErD;AAAA,WACF;AAAA,QAGD,cACC,8CAAC,gBAAAK,SAAA,EAAS,IAAI,UAAU,eAAa,MACnC,wDAAC,aAAAN,SAAA,EAAI,IAAI,sBACN,gBACH,GACF,IAEA;AAAA,QAGD,UACC;AAAA,UAAC,aAAAA;AAAA,UAAA;AAAA,YACC,IAAI,YAAU;AAAA,cACZ,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,WAAW,aAAa,MAAM,QAAQ,OAAO;AAAA,YAC/C;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,SAEJ;AAAA,IAEJ;AAAA;AAAA;;;AClZA,SAASO,YAAW,QAAiB,QAAuB;AAC1D,MAAI,OAAQ,QAAO;AACnB,MAAI,OAAQ,QAAO;AACnB,SAAO;AACT;AAIA,SAAS,iBAAiB,OAAe,QAAwB;AAC/D,MAAI,UAAU,EAAG,QAAO;AACxB,SAAO,KAAK,IAAK,QAAQ,SAAU,KAAK,GAAG;AAC7C;AAEA,SAAS,gBAAgB,QAAiB,QAAwB;AAChE,MAAI,OAAQ,QAAO;AACnB,MAAI,SAAS,EAAG,QAAO,QAAQ,MAAM;AACrC,SAAO;AACT;AA9DA,IAAAC,gBACAC,eACAC,cACAC,qBACAC,kBACAC,iBACAC,eACAC,mBACAC,mBACAC,mBACAC,kBACAC,wBACAC,kBACAC,oBACAC,gBACAC,0BACAC,iBACAC,iBACAC,wBACAC,kBA8FUC,sBA9DJ,SAyBA,UAiTO;AA7Xb;AAAA;AAAA;AAAA,IAAApB,iBAA6B;AAC7B,IAAAC,gBAAkB;AAClB,IAAAC,eAAgB;AAChB,IAAAC,sBAAuB;AACvB,IAAAC,mBAAqB;AACrB,IAAAC,kBAAoB;AACpB,IAAAC,gBAAkB;AAClB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,IAAAC,yBAA2B;AAC3B,IAAAC,mBAAqB;AACrB,IAAAC,qBAAuB;AACvB,IAAAC,iBAAmB;AACnB,IAAAC,2BAA6B;AAC7B,IAAAC,kBAAsB;AACtB,IAAAC,kBAAuB;AACvB,IAAAC,yBAAuE;AACvE,IAAAC,mBAQO;AAEP;AAoFU,IAAAC,uBAAA;AA9DV,IAAM,UAAU,CAAC,MAAc,KAAK,KAAK,GAAG,QAAQ,CAAC,CAAC;AAyBtD,IAAM,WAA8B,CAAC,EAAE,MAAM,OAAO,cAAc,WAAW,YAAY,kBAAkB,iBAAiB,SAAS,MAAM;AACzI,YAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,KAAK;AAC9C,YAAM,QAAQ,cAAc;AAE5B,YAAM,qBAAqB,CAAC,gBAAyB;AACnD,oBAAY,WAAW;AACvB,YAAI,eAAe,UAAU;AAC3B,mBAAS,IAAI;AAAA,QACf;AAAA,MACF;AAMA,YAAM,SAAS,KAAK,kBAAkB;AACtC,YAAM,SAAS,SAAS,IAAI,KAAK,cAAc;AAC/C,YAAM,QAAQ,SAAS,IAAI,KAAK,SAAS;AACzC,YAAM,YAAY,SACd,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,KAAK,cAAc,CAAC,CAAC,IAC/C,iBAAiB,OAAO,MAAM;AAClC,YAAM,SAAS,SACX,KAAK,kBAAkB,SACvB,SAAS,KAAK,SAAS;AAC3B,YAAM,SAAS,SACX,KAAK,kBAAkB,SACvB,SAAS,KAAK,SAAS,SAAS,OAAO,CAAC;AAE5C,YAAM,YAAY,OAAO,aAAa,IAAI,QAAM,EAAE,MAAM,EAAE,MAAM,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC;AAEvF,YAAM,0BAA0B,MAAM;AAGpC,YAAI,OAAQ,QAAO;AACnB,YAAI,cAAc;AAChB,iBACE,8CAAC,aAAAC,SAAA,EAAI,SAAQ,QAAO,gBAAe,UAAS,IAAI,GAC9C,wDAAC,yBAAAC,SAAA,EAAiB,MAAM,IAAI,GAC9B;AAAA,QAEJ;AACA,YAAI,UAAU,WAAW,EAAG,QAAO;AACnC,eACE,+CAAC,aAAAD,SAAA,EAAI,IAAI,KACP;AAAA;AAAA,YAAC,oBAAAE;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,IAAI,EAAE,SAAS,SAAS,UAAU,IAAI,YAAY,KAAK,eAAe,UAAU,eAAe,aAAa,IAAI,EAAE;AAAA,cACnH;AAAA;AAAA,UAED;AAAA,UACA,8CAAC,aAAAF,SAAA,EAAI,QAAQ,KACX,wDAAC,wCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,8BAAU,MAAM,WAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,EAAE,GACzE;AAAA,0DAAC,kCAAe,GAAG,MAAM,MAAM;AAAA,YAC/B,8CAAC,0BAAM,SAAQ,QAAO,eAAe,cAAe,GAAG,MAAM,MAAM;AAAA,YACnE,8CAAC,0BAAM,eAAe,eAAe,OAAO,IAAK,GAAG,MAAM,MAAM;AAAA,YAChE;AAAA,cAAC;AAAA;AAAA,gBACC,QAAQ,MAAM;AAAA,gBACd,SAAS,8CAAC,gBAAa,gBAAgB,OAAK,IAAI,EAAE,QAAQ,CAAC,CAAC,IAAI;AAAA;AAAA,YAClE;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,QAAQ,OAAO;AAAA,gBACf,aAAa;AAAA,gBACb,MAAM,OAAO;AAAA,gBACb,aAAa;AAAA;AAAA,YACf;AAAA,aACF,GACF,GACF;AAAA,WACF;AAAA,MAEJ;AAEA,YAAM,eAAe,CAAC,UACpB;AAAA,QAAC,oBAAAE;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAM;AAAA,UACN,IAAI,EAAE,SAAS,SAAS,UAAU,IAAI,YAAY,KAAK,eAAe,UAAU,eAAe,aAAa,IAAI,EAAE;AAAA,UAEjH;AAAA;AAAA,MACH;AAGF,aACE,+CAAC,cAAAC,SAAA,EAAM,SAAQ,YAAW,IAAI,EAAE,cAAc,GAAG,GAAG,IAAI,GACtD;AAAA,uDAAC,aAAAH,SAAA,EAAI,SAAQ,QAAO,YAAW,UAAS,KAAK,KAC3C;AAAA;AAAA,YAAC,aAAAA;AAAA,YAAA;AAAA,cACC,IAAI,YAAU;AAAA,gBACZ,OAAO;AAAA,gBACP,QAAQ;AAAA,gBACR,cAAc;AAAA,gBACd,YAAY;AAAA,gBACZ,SAAS;AAAA,gBACT,YAAY;AAAA,gBACZ,gBAAgB;AAAA,gBAChB,aAAS,uBAAM,MAAM,QAAQ,QAAQ,MAAM,GAAG;AAAA,gBAC9C,OAAO,MAAM,QAAQ,QAAQ;AAAA,cAC/B;AAAA,cAEA,wDAAC,gCAAM,UAAS,SAAQ;AAAA;AAAA,UAC1B;AAAA,UACA,+CAAC,aAAAA,SAAA,EAAI,UAAU,GAAG,UAAU,GAC1B;AAAA,0DAAC,oBAAAE,SAAA,EAAW,SAAQ,aAAY,IAAI,EAAE,YAAY,KAAK,YAAY,IAAI,GACpE,eAAK,cAAc,iBACtB;AAAA,YACA;AAAA,cAAC,oBAAAA;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,OAAM;AAAA,gBACN,IAAI,EAAE,YAAY,kDAAkD,UAAU,GAAG;AAAA,gBAEhF,eAAK;AAAA;AAAA,YACR;AAAA,aACF;AAAA,UACC,UAAU,8CAAC,cAAW,OAAM,eAAc,MAAK,UAAS;AAAA,UACxD,UAAU,8CAAC,cAAW,OAAM,cAAa,MAAK,WAAU;AAAA,UACxD,aAAa,cACZ;AAAA,YAAC,eAAAE;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,SAAS,MAAM,WAAW,IAAI;AAAA,cAC9B,IAAI,EAAE,eAAe,OAAO;AAAA,cAC7B;AAAA;AAAA,UAED;AAAA,UAED,oBAAoB,mBAAmB,CAAC,aACvC,8CAAC,gBAAAC,SAAA,EAAW,OAAM,sCAChB;AAAA,YAAC,eAAAD;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,WAAW,8CAAC,2CAAiB;AAAA,cAC7B,SAAS,MAAM,gBAAgB,IAAI;AAAA,cACnC,IAAI,EAAE,eAAe,OAAO;AAAA,cAC7B;AAAA;AAAA,UAED,GACF;AAAA,UAEF;AAAA,YAAC,mBAAAE;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,mBAAmB,CAAC,QAAQ;AAAA,cAC3C,cAAY,WAAW,sBAAsB;AAAA,cAC7C,iBAAe;AAAA,cACf,IAAI,YAAU;AAAA,gBACZ,OAAO,MAAM,QAAQ,KAAK;AAAA,gBAC1B,WAAW,WAAW,mBAAmB;AAAA,gBACzC,YAAY,MAAM,YAAY,OAAO,WAAW;AAAA,cAClD;AAAA,cAEA,wDAAC,qCAAW;AAAA;AAAA,UACd;AAAA,WACF;AAAA,QAIA;AAAA,UAAC,aAAAN;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,SAAS;AAAA,cACT,qBAAqB,EAAE,IAAI,6BAA6B,IAAI,4BAA4B;AAAA,cACxF,KAAK;AAAA,cACL,IAAI;AAAA,cACJ,UAAU;AAAA,YACZ;AAAA,YAEA;AAAA,4DAAC,QAAK,OAAM,WAAU,OAAO,KAAK,oBAAoB,UAAU,UAAK;AAAA,cACrE,8CAAC,QAAK,OAAM,UAAS,OAAO,KAAK,QAAQ,SAAS,KAAK,OAAO,SAAS,OAAO;AAAA,cAC9E,8CAAC,QAAK,OAAM,UAAS,OAAO,gBAAgB,QAAQ,MAAM,GAAG;AAAA,cAC7D,8CAAC,QAAK,OAAM,SAAQ,OAAO,SAAS,WAAM,QAAQ,KAAK,GAAG;AAAA,cAC1D,8CAAC,QAAK,OAAM,OAAM,OAAO,KAAK,aAAa,KAAK,YAAY,IAAI,KAAK,UAAU,eAAe,IAAI,UAAK;AAAA,cACvG,8CAAC,QAAK,OAAM,OAAM,OAAO,KAAK,aAAa,KAAK,YAAY,IAAI,KAAK,UAAU,eAAe,IAAI,UAAK;AAAA;AAAA;AAAA,QACzG;AAAA,QAEC,UACC,+CAAC,aAAAA,SAAA,EAAI,IAAI,GAAG,UAAU,KACpB;AAAA,yDAAC,aAAAA,SAAA,EAAI,SAAQ,QAAO,gBAAe,iBAAgB,YAAW,YAAW,IAAI,MAC3E;AAAA,2DAAC,oBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GAC3F;AAAA,wBAAU,QAAQ,CAAC;AAAA,cAAE;AAAA,eACxB;AAAA,YACA,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,6BAErD;AAAA,aACF;AAAA,UACA,8CAAC,SAAM,OAAO,WAAW,MAAMxB,YAAW,QAAQ,MAAM,GAAG,QAAQ,GAAG;AAAA,UACtE,+CAAC,oBAAAwB,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,SAAS,SAAS,IAAI,KAAK,GAAG;AAAA;AAAA,YAEtF,KAAK,kBAAkB,sBAAmB,KAAK,eAAe,KAAK;AAAA,YAAG;AAAA,aACzE;AAAA,WACF;AAAA,QAGD,CAAC,UAAU,SAAS,KACnB,+CAAC,aAAAF,SAAA,EAAI,IAAI,GAAG,UAAU,KACpB;AAAA,yDAAC,aAAAA,SAAA,EAAI,SAAQ,QAAO,gBAAe,iBAAgB,YAAW,YAAW,IAAI,MAC3E;AAAA,2DAAC,oBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GAC3F;AAAA,sBAAQ,KAAK;AAAA,cAAE;AAAA,cAAK,QAAQ,MAAM;AAAA,eACrC;AAAA,YACA,+CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,oBAAoB,eAAe,GAC3F;AAAA,wBAAU,QAAQ,CAAC;AAAA,cAAE;AAAA,eACxB;AAAA,aACF;AAAA,UACA,8CAAC,SAAM,OAAO,WAAW,MAAMxB,YAAW,QAAQ,MAAM,GAAG,QAAQ,GAAG;AAAA,WACxE;AAAA,QAGF,+CAAC,iBAAA6B,SAAA,EAAS,IAAI,UAAU,eAAa,MACnC;AAAA,wDAAC,gBAAAC,SAAA,EAAQ,IAAI,EAAE,IAAI,IAAI,GAAG;AAAA,UAE1B,+CAAC,aAAAR,SAAA,EAAI,IAAI,KACN;AAAA,yBAAa,QAAQ;AAAA,YACrB,KAAK,QAAQ,SACZ,8CAAC,aAAAA,SAAA,EAAI,SAAQ,QAAO,KAAK,KAAK,UAAS,QACpC,eAAK,OAAO,IAAI,OACf,8CAAC,WAAgB,OAAO,GAAG,OAAO,KAApB,CAAuB,CACtC,GACH,IAEA,8CAAC,oBAAAE,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,gCAAkB;AAAA,aAEzE;AAAA,UAEC,wBAAwB;AAAA,UAEzB,+CAAC,aAAAF,SAAA,EACE;AAAA,yBAAa,SAAS;AAAA,YACtB,KAAK,oBAAoB,SACxB;AAAA,cAAC,uBAAAS;AAAA,cAAA;AAAA,gBACC,WAAW,cAAAN;AAAA,gBACX,SAAQ;AAAA,gBACR,IAAI,EAAE,cAAc,IAAI;AAAA,gBAExB,yDAAC,cAAAO,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,gEAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAAC,SAAA,EACC;AAAA,kEAAC,kBAAAC,SAAA,EAAU,kBAAI;AAAA,oBACf,8CAAC,kBAAAA,SAAA,EAAU,OAAM,SAAQ,kBAAI;AAAA,qBAC/B,GACF;AAAA,kBACA,8CAAC,kBAAAC,SAAA,EACE,eAAK,mBAAmB,IAAI,OAC3B,+CAAC,iBAAAF,SAAA,EACC;AAAA,kEAAC,kBAAAC,SAAA,EACE,YAAE,aACD,gFACE;AAAA,oEAAC,oBAAAX,SAAA,EAAW,SAAQ,SAAS,YAAE,YAAW;AAAA,sBAC1C;AAAA,wBAAC,oBAAAA;AAAA,wBAAA;AAAA,0BACC,SAAQ;AAAA,0BACR,OAAM;AAAA,0BACN,IAAI,EAAE,YAAY,kDAAkD,UAAU,GAAG;AAAA,0BAEhF,YAAE;AAAA;AAAA,sBACL;AAAA,uBACF,IAEA;AAAA,sBAAC,oBAAAA;AAAA,sBAAA;AAAA,wBACC,SAAQ;AAAA,wBACR,IAAI,EAAE,YAAY,iDAAiD;AAAA,wBAElE,YAAE;AAAA;AAAA,oBACL,GAEJ;AAAA,oBACA,8CAAC,kBAAAW,SAAA,EAAU,OAAM,SACf;AAAA,sBAAC;AAAA;AAAA,wBACC,OAAO,EAAE;AAAA,wBACT,MAAM,EAAE,SAAS,UAAU,WAAW;AAAA,wBACtC,KAAK;AAAA;AAAA,oBACP,GACF;AAAA,uBA5Ba,EAAE,OA6BjB,CACD,GACH;AAAA,mBACF;AAAA;AAAA,YACF,IAEA,8CAAC,oBAAAX,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,kCAAoB;AAAA,aAE3E;AAAA,WACF;AAAA,SACF;AAAA,IAEJ;AAqBO,IAAM,YAAgC,CAAC;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,MAAM;AACJ,YAAM,gBACJ,8CAAC,gBAAAG,SAAA,EAAW,OAAM,gIAChB;AAAA,QAAC,aAAAL;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,IAAI,EAAE,SAAS,eAAe,YAAY,UAAU,KAAK,KAAK,OAAO,kBAAkB,UAAU,KAAK;AAAA,UAEtG;AAAA,0DAAC,uCAAa,IAAI,EAAE,UAAU,GAAG,GAAG;AAAA,YAAE;AAAA;AAAA;AAAA,MAExC,GACF;AAEF,YAAM,eACJ,aAAa,eACX;AAAA,QAAC,eAAAI;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,OAAM;AAAA,UACN,kBAAgB;AAAA,UAChB,WAAW,8CAAC,8BAAI;AAAA,UAChB,SAAS;AAAA,UACV;AAAA;AAAA,MAED,IACE;AACN,YAAM,eAAe,WAAW,gBAAgB;AAEhD,UAAI,SAAS;AACX,eACE,+CAAC,eAAY,OAAM,SAAQ,SAAS,cAClC;AAAA,wDAAC,iBAAAW,SAAA,EAAS,SAAQ,WAAU,QAAQ,KAAK,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,UACxD,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,WAAU,QAAQ,KAAK;AAAA,WAC3C;AAAA,MAEJ;AAEA,UAAI,CAAC,MAAM,QAAQ;AACjB,eACE,8CAAC,eAAY,OAAM,SAAQ,SAAS,cAClC;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA;AAAA,QACP,GACF;AAAA,MAEJ;AAEA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,UAAU,GAAG,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG;AAAA,UAC9D,SAAS;AAAA,UAET,wDAAC,aAAAf,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GACzD,gBAAM,IAAI,UACT;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,OAAO,aAAa,KAAK,OAAO;AAAA,cAChC,cAAc,oBAAoB,KAAK,OAAO;AAAA,cAC9C;AAAA,cACA;AAAA,cACA,kBAAkB,mBAAmB,IAAI;AAAA,cACzC;AAAA,cACA,UAAU;AAAA;AAAA,YARL,KAAK;AAAA,UASZ,CACD,GACH;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA;AAAA;;;AC9aA,SAASgB,sBAAqB,OAAkB,YAAgC;AAC9E,MAAI,CAAC,cAAc,WAAW,WAAW,KAAK,WAAW,SAAS,gBAAgB,EAAG,QAAO;AAC5F,SAAO,WAAW,SAAS,MAAM,UAAU,KACzC,CAAC,CAAC,MAAM,eAAe,KAAK,WAAS,WAAW,SAAS,KAAK,CAAC;AACnE;AAEA,SAAS,gBAAgB,MAAuB;AAC9C,MAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,MAAI,SAAS,EAAG,QAAO;AACvB,MAAI,OAAO,KAAU,QAAO,KAAK,OAAO,KAAW,QAAQ,CAAC,CAAC;AAC7D,MAAI,OAAO,KAAO,QAAO,KAAK,OAAO,KAAM,QAAQ,CAAC,CAAC;AACrD,SAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AAC5B;AAEA,SAAS,UAAU,GAAoB;AACrC,MAAI,MAAM,UAAa,MAAM,KAAM,QAAO;AAC1C,MAAI,KAAK,IAAW,QAAO,IAAI,IAAI,KAAW,QAAQ,CAAC,CAAC;AACxD,MAAI,KAAK,IAAO,QAAO,IAAI,IAAI,KAAO,QAAQ,CAAC,CAAC;AAChD,SAAO,OAAO,CAAC;AACjB;AApDA,IAAAC,gBACAC,cACAC,eACAC,mBACAC,mBACAC,wBACAC,mBACAC,kBACAC,wBACAC,qBACAC,kBACA,eACA,oBACA,mBACAC,mBACAC,wBACAC,wBACA,oBACAC,iBACA,iBACAC,eAGAC,iBAmIQC,sBA3HF,kBAuBO;AAtDb;AAAA;AAAA;AAAA,IAAAjB,iBAAmD;AACnD,IAAAC,eAAgB;AAChB,IAAAC,gBAAkB;AAClB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,yBAA2B;AAC3B,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,IAAAC,yBAA2B;AAC3B,IAAAC,sBAAuB;AACvB,IAAAC,mBAAqB;AACrB,oBAAmB;AACnB,yBAAwB;AACxB,wBAAuB;AACvB,IAAAC,oBAAsB;AACtB,IAAAC,yBAA2B;AAC3B,IAAAC,yBAAuB;AACvB,yBAA4B;AAC5B,IAAAC,kBAAoB;AACpB,sBAAqB;AACrB,IAAAC,gBAAkB;AAElB;AACA,IAAAC,kBAAgC;AAmIxB,IAAAC,uBAAA;AA3HR,IAAM,mBAAmB;AAuBlB,IAAM,cAAoC,CAAC,EAAE,WAAW,OAAO,QAAQ,MAAM;AAClF,YAAM,YAAQ,0BAAS;AACvB,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAiB,EAAE;AAC/D,YAAM,CAAC,YAAY,aAAa,QAAI,yBAAiB,EAAE;AACvD,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAAS,KAAK;AAC1D,YAAM,CAAC,SAAS,UAAU,QAAI,yBAA8H,YAAY;AACxK,YAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAyB,KAAK;AAExE,YAAM,mBAAe;AAAA,QACnB,MAAM,MAAM,KAAK,OAAK,EAAE,YAAY,cAAc,KAAK;AAAA,QACvD,CAAC,OAAO,cAAc;AAAA,MACxB;AAEA,YAAM,iBAAa,wBAAQ,MAAM;AAC/B,YAAI,CAAC,aAAc,QAAO,CAAC;AAC3B,eAAO,UAAU,OAAO,WAASlB,sBAAqB,OAAO,aAAa,MAAM,CAAC;AAAA,MACnF,GAAG,CAAC,WAAW,YAAY,CAAC;AAE5B,YAAM,qBAAiB,wBAAQ,MAAM;AACnC,cAAM,IAAI,WAAW,KAAK,EAAE,YAAY;AACxC,YAAI,SAAS;AACb,YAAI,GAAG;AACL,mBAAS,WAAW;AAAA,YAAO,WACzB,MAAM,WAAW,YAAY,EAAE,SAAS,CAAC,MACxC,MAAM,iBAAiB,CAAC,GAAG,KAAK,WAAS,MAAM,YAAY,EAAE,SAAS,CAAC,CAAC;AAAA,UAC3E;AAAA,QACF;AACA,eAAO,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM;AAChC,cAAI;AACJ,cAAI;AACJ,kBAAQ,SAAS;AAAA,YACf,KAAK;AACH,qBAAO,EAAE;AACT,qBAAO,EAAE;AACT;AAAA,YACF,KAAK;AACH,qBAAO,EAAE;AACT,qBAAO,EAAE;AACT;AAAA,YACF,KAAK;AACH,qBAAO,EAAE,wBAAwB;AACjC,qBAAO,EAAE,wBAAwB;AACjC;AAAA,YACF,KAAK;AACH,qBAAO,EAAE,yBAAyB;AAClC,qBAAO,EAAE,yBAAyB;AAClC;AAAA,YACF,KAAK;AACH,qBAAO,EAAE,oBAAoB;AAC7B,qBAAO,EAAE,oBAAoB;AAC7B;AAAA,YACF,KAAK;AACH,qBAAO,EAAE,qBAAqB;AAC9B,qBAAO,EAAE,qBAAqB;AAC9B;AAAA,YACF;AACE,qBAAO;AAAA,UACX;AACA,cAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,cAAI,SAAS,UAAa,SAAS,KAAM,QAAO;AAChD,cAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AACxD,mBAAO,kBAAkB,QAAQ,KAAK,cAAc,IAAI,IAAI,KAAK,cAAc,IAAI;AAAA,UACrF;AACA,iBAAO,kBAAkB,QAAS,OAAmB,OAAmB,OAAmB;AAAA,QAC7F,CAAC;AAAA,MACH,GAAG,CAAC,YAAY,YAAY,SAAS,aAAa,CAAC;AAEnD,YAAM,wBAAoB,4BAAY,CAAC,YAAoB;AACzD,kBAAU,UAAU,UAAU,OAAO,EAAE,KAAK,MAAM,kBAAkB,IAAI,CAAC;AAAA,MAC3E,GAAG,CAAC,CAAC;AAEL,YAAM,iBAAa,4BAAY,CAAC,QAAwB;AACtD,YAAI,YAAY,KAAK;AACnB,2BAAiB,UAAQ,SAAS,QAAQ,SAAS,KAAK;AAAA,QAC1D,OAAO;AACL,qBAAW,GAAG;AACd,2BAAiB,KAAK;AAAA,QACxB;AAAA,MACF,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAM,YAAY,CAAC,SAAyB;AAC1C,gBAAQ,MAAM;AAAA,UACZ,KAAK;AAAQ,mBAAO,MAAM,QAAQ,KAAK;AAAA,UACvC,KAAK;AAAa,mBAAO,MAAM,QAAQ,QAAQ;AAAA,UAC/C,KAAK;AAAc,mBAAO,MAAM,QAAQ,QAAQ;AAAA,UAChD,KAAK;AAAS,mBAAO,MAAM,QAAQ,QAAQ;AAAA,UAC3C;AAAS,mBAAO,MAAM,QAAQ,KAAK;AAAA,QACrC;AAAA,MACF;AAEA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,UACE,eACI,GAAG,eAAe,MAAM,GAAG,WAAW,KAAK,IAAI,OAAO,WAAW,MAAM,KAAK,EAAE,SAAS,eAAe,WAAW,IAAI,KAAK,GAAG,KAC7H;AAAA,UAGN;AAAA,2DAAC,aAAAmB,SAAA,EAAI,IAAI,EAAE,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,SAAS,QAAQ,KAAK,GAAG,UAAU,OAAO,GAC5E;AAAA,6DAAC,mBAAAC,SAAA,EAAY,MAAK,SAAQ,IAAI,EAAE,UAAU,KAAK,IAAI,EAAE,GACnD;AAAA,8DAAC,kBAAAC,SAAA,EAAW,IAAG,qBAAoB,kBAAI;AAAA,gBACvC;AAAA,kBAAC,cAAAC;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAO;AAAA,oBACP,OAAM;AAAA,oBACN,UAAU,OAAK,kBAAkB,EAAE,OAAO,KAAK;AAAA,oBAE9C,gBAAM,IAAI,OACT,8CAAC,iBAAAC,SAAA,EAAyB,OAAO,EAAE,SAChC,YAAE,cAAc,EAAE,WADN,EAAE,OAEjB,CACD;AAAA;AAAA,gBACH;AAAA,iBACF;AAAA,cACA;AAAA,gBAAC,kBAAAC;AAAA,gBAAA;AAAA,kBACC,OAAM;AAAA,kBACN,MAAK;AAAA,kBACL,OAAO;AAAA,kBACP,UAAU,OAAK,cAAc,EAAE,OAAO,KAAK;AAAA,kBAC3C,UAAU,CAAC;AAAA,kBACX,IAAI,EAAE,UAAU,KAAK,IAAI,EAAE;AAAA,kBAC3B,YAAY;AAAA,oBACV,gBACE,8CAAC,uBAAAC,SAAA,EAAe,UAAS,SACvB,wDAAC,iCAAO,UAAS,SAAQ,GAC3B;AAAA,kBAEJ;AAAA;AAAA,cACF;AAAA,eACF;AAAA,YAEC,WACC,8CAAC,cAAW,SAAQ,wBAAkB;AAAA,YAGvC,CAAC,WAAW,CAAC,kBACZ;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA;AAAA,YACP;AAAA,YAGD,CAAC,WAAW,kBAAkB,WAAW,WAAW,KACnD;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAM,UAAU,WAAW,IAAI,2CAA2C;AAAA;AAAA,YAC5E;AAAA,YAGD,CAAC,WAAW,kBAAkB,WAAW,SAAS,KAAK,eAAe,WAAW,KAChF;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA;AAAA,YACP;AAAA,YAGD,CAAC,WAAW,eAAe,SAAS,KACnC,8CAAC,uBAAAC,SAAA,EACC,yDAAC,cAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,4DAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAAC,SAAA,EACC;AAAA,8DAAC,kBAAAC,SAAA,EAAU,eAAe,YAAY,eAAe,gBAAgB,OACnE,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,cAAc,WAAW,YAAY,eAAe,gBAAgB,OAAO,SAAS,MAAM,WAAW,YAAY,GAAG,sBAAQ,GAClK;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,eAAe,YAAY,SAAS,gBAAgB,OAC7D,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,QAAQ,WAAW,YAAY,SAAS,gBAAgB,OAAO,SAAS,MAAM,WAAW,MAAM,GAAG,kBAAI,GAC5I;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,OAAM,SAAQ,eAAe,YAAY,yBAAyB,gBAAgB,OAC3F,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,wBAAwB,WAAW,YAAY,yBAAyB,gBAAgB,OAAO,SAAS,MAAM,WAAW,sBAAsB,GAAG,wBAAU,GAClM;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,OAAM,SAAQ,eAAe,YAAY,0BAA0B,gBAAgB,OAC5F,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,yBAAyB,WAAW,YAAY,0BAA0B,gBAAgB,OAAO,SAAS,MAAM,WAAW,uBAAuB,GAAG,yBAAW,GACtM;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,OAAM,SAAQ,eAAe,YAAY,qBAAqB,gBAAgB,OACvF,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,oBAAoB,WAAW,YAAY,qBAAqB,gBAAgB,OAAO,SAAS,MAAM,WAAW,kBAAkB,GAAG,uBAAS,GACrL;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,OAAM,SAAQ,eAAe,YAAY,sBAAsB,gBAAgB,OACxF,wDAAC,uBAAAC,SAAA,EAAe,QAAQ,YAAY,qBAAqB,WAAW,YAAY,sBAAsB,gBAAgB,OAAO,SAAS,MAAM,WAAW,mBAAmB,GAAG,wBAAU,GACzL;AAAA,gBACA,8CAAC,kBAAAD,SAAA,EAAU,0BAAY;AAAA,iBACzB,GACF;AAAA,cACA,8CAAC,kBAAAE,SAAA,EACE,yBAAe,IAAI,OAClB,+CAAC,iBAAAH,SAAA,EAA4B,OAAK,MAChC;AAAA,8DAAC,kBAAAC,SAAA,EACC,yDAAC,aAAAX,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,IAAI,GACzD;AAAA,gEAAC,gBAAAc,SAAA,EAAQ,OAAO,EAAE,YAAY,WAAU,OACtC;AAAA,oBAAC;AAAA;AAAA,sBACC,MAAK;AAAA,sBACL,UAAU;AAAA,sBACV,cAAW;AAAA,sBACX,SAAS,MAAM,kBAAkB,EAAE,UAAU;AAAA,sBAC7C,WAAW,OAAK,EAAE,QAAQ,WAAW,kBAAkB,EAAE,UAAU;AAAA,sBACnE,OAAO,EAAE,QAAQ,WAAW,SAAS,cAAc;AAAA,sBAEnD,wDAAC,WAAQ,OAAO,EAAE,YAAY,OAAM,iBAAgB;AAAA;AAAA,kBACtD,GACF;AAAA,kBACA,8CAAC,gBAAAA,SAAA,EAAQ,OAAM,iBACb;AAAA,oBAAC,aAAAd;AAAA,oBAAA;AAAA,sBACC,WAAU;AAAA,sBACV,MAAK;AAAA,sBACL,UAAU;AAAA,sBACV,SAAS,MAAM,kBAAkB,EAAE,UAAU;AAAA,sBAC7C,WAAW,OAAK,EAAE,QAAQ,WAAW,kBAAkB,EAAE,UAAU;AAAA,sBACnE,IAAI,kBAAkB,QAAQ;AAAA,sBAC9B,OAAO,EAAE,QAAQ,WAAW,SAAS,cAAc;AAAA,sBAEnD,wDAAC,mBAAAe,SAAA,EAAgB,IAAI,EAAE,UAAU,GAAG,GAAG;AAAA;AAAA,kBACzC,GACF;AAAA,mBACF,GACF;AAAA,gBACA,8CAAC,kBAAAJ,SAAA,EACC;AAAA,kBAAC,aAAAX;AAAA,kBAAA;AAAA,oBACC,WAAU;AAAA,oBACV,IAAI;AAAA,sBACF,SAAS;AAAA,sBACT,IAAI;AAAA,sBACJ,IAAI;AAAA,sBACJ,cAAc;AAAA,sBACd,UAAU;AAAA,sBACV,YAAY;AAAA,sBACZ,eAAe;AAAA,sBACf,aAAS,uBAAM,UAAU,EAAE,IAAI,GAAG,GAAG;AAAA,sBACrC,OAAO,UAAU,EAAE,IAAI;AAAA,oBACzB;AAAA,oBAEC,YAAE;AAAA;AAAA,gBACL,GACF;AAAA,gBACA,8CAAC,kBAAAW,SAAA,EAAU,OAAM,SACf,wDAAC,oBAAAK,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,oBAAoB,eAAe,GAClE,0BAAgB,EAAE,oBAAoB,GACzC,GACF;AAAA,gBACA,8CAAC,kBAAAL,SAAA,EAAU,OAAM,SACf,wDAAC,oBAAAK,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,oBAAoB,eAAe,GAClE,0BAAgB,EAAE,qBAAqB,GAC1C,GACF;AAAA,gBACA,8CAAC,kBAAAL,SAAA,EAAU,OAAM,SACf,wDAAC,oBAAAK,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,oBAAoB,eAAe,GAClE,oBAAU,EAAE,gBAAgB,GAC/B,GACF;AAAA,gBACA,8CAAC,kBAAAL,SAAA,EAAU,OAAM,SACf,wDAAC,oBAAAK,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,oBAAoB,eAAe,GAClE,oBAAU,EAAE,iBAAiB,GAChC,GACF;AAAA,gBACA,8CAAC,kBAAAL,SAAA,EACC,yDAAC,aAAAX,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,KAAK,KAAK,UAAU,OAAO,GACpD;AAAA,oBAAE,6BACD,8CAAC,WAAQ,OAAM,MAAK,OAAM,oBAAmB;AAAA,kBAE9C,EAAE,mBACD,8CAAC,WAAQ,OAAM,aAAK,OAAM,UAAS;AAAA,mBAEvC,GACF;AAAA,mBA7Ea,EAAE,UA8EjB,CACD,GACH;AAAA,eACF,GACF;AAAA,YAGF;AAAA,cAAC,gBAAAiB;AAAA,cAAA;AAAA,gBACC,MAAM;AAAA,gBACN,kBAAkB;AAAA,gBAClB,SAAS,MAAM,kBAAkB,KAAK;AAAA,gBACtC,cAAc,EAAE,UAAU,UAAU,YAAY,SAAS;AAAA,gBAEzD,wDAAC,cAAAC,SAAA,EAAM,UAAS,WAAU,SAAQ,UAAS,IAAI,EAAE,UAAU,GAAG,GAAG,0CAEjE;AAAA;AAAA,YACF;AAAA;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA;AAAA;;;AC7SA,SAAS,WAAW,QAAuB;AACzC,MAAI,CAAC,OAAQ,QAAO;AACpB,aAAW,CAAC,KAAK,IAAI,KAAK,OAAO,QAAQ,YAAY,GAAG;AACtD,QAAI,OAAO,YAAY,EAAE,SAAS,GAAG,EAAG,QAAO;AAAA,EACjD;AACA,SAAO;AACT;AAWA,SAAS,gBAAgB,MAA8B;AACrD,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,aAAa,IAAI,KAAK;AAC/B;AAEA,SAAS,eAAe,KAAqB;AAC3C,MAAI;AACF,WAAO,IAAI,KAAK,GAAG,EAAE,eAAe;AAAA,EACtC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA4GA,SAAS,mBAAmB,SAAkB,SAA0B;AACtE,MAAI,SAAS;AACX,WACE,8CAAC,iBAAAC,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,IAAI,EAAE,IAAI,EAAE,GACjC,wDAAC,iBAAAC,SAAA,EAAS,SAAQ,WAAU,QAAQ,KAAK,GAC3C,GACF;AAAA,EAEJ;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,WACE,8CAAC,iBAAAF,SAAA,EACC,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAClB;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA;AAAA,IACP,GACF,GACF;AAAA,EAEJ;AACA,SAAO,QAAQ,IAAI,WAAS,8CAAC,aAAyB,SAAV,MAAM,EAAkB,CAAE;AACxE;AAlMA,IAAAE,gBACAC,cACAC,qBACAC,eACAC,mBACAC,mBACAC,wBACAC,mBACAC,kBACA,wBACAC,mBACAC,kBACAC,kBACAC,kBACAC,oBACAC,eACAC,iBACAC,wBACA,kBAoDIC,sBA3CE,cAiBA,cAqBA,WAmIO;AApMb;AAAA;AAAA;AAAA,IAAAjB,iBAAsC;AACtC,IAAAC,eAAgB;AAChB,IAAAC,sBAAuB;AACvB,IAAAC,gBAAkB;AAClB,IAAAC,oBAAsB;AACtB,IAAAC,oBAAsB;AACtB,IAAAC,yBAA2B;AAC3B,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,6BAA4B;AAC5B,IAAAC,oBAAsB;AACtB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqB;AACrB,IAAAC,qBAAuB;AACvB,IAAAC,gBAAkB;AAClB,IAAAC,kBAAsB;AACtB,IAAAC,yBAAkC;AAClC,uBAAyB;AAGzB;AAiDI,IAAAC,uBAAA;AA3CJ,IAAM,eAAqC;AAAA,MACzC,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AAWA,IAAM,eAAuC;AAAA,MAC3C,2BAA2B;AAAA,MAC3B,mBAAmB;AAAA,MACnB,wBAAwB;AAAA,MACxB,+BAA+B;AAAA,MAC/B,mBAAmB;AAAA,IACrB;AAeA,IAAM,YAA0C,CAAC,EAAE,MAAM,MAAM;AAC7D,YAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,KAAK;AACtC,YAAM,YAAY,MAAM,gBAAgB,MAAM;AAE9C,aACE,gFACE;AAAA,uDAAC,iBAAApB,SAAA,EACC;AAAA,wDAAC,kBAAAC,SAAA,EAAU,IAAI,EAAE,OAAO,IAAI,IAAI,EAAE,GAC/B,uBACC;AAAA,YAAC,mBAAAoB;AAAA,YAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,QAAQ,OAAK,CAAC,CAAC;AAAA,cAC9B,cAAY,OAAO,iBAAiB;AAAA,cACpC,iBAAe;AAAA,cACf,IAAI,YAAU;AAAA,gBACZ,OAAO,MAAM,QAAQ,KAAK;AAAA,gBAC1B,WAAW,OAAO,mBAAmB;AAAA,gBACrC,YAAY,MAAM,YAAY,OAAO,WAAW;AAAA,cAClD;AAAA,cAEA,wDAAC,4CAAkB,UAAS,SAAQ;AAAA;AAAA,UACtC,GAEJ;AAAA,UACA,8CAAC,kBAAApB,SAAA,EAAU,IAAI,EAAE,YAAY,SAAS,GACpC,wDAAC,oBAAAqB,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAkB,yBAAe,MAAM,UAAU,GAAE,GACvF;AAAA,UACA,8CAAC,kBAAArB,SAAA,EACE,gBAAM,UAAU,8CAAC,cAAW,OAAO,MAAM,QAAQ,MAAM,WAAW,MAAM,MAAM,GAAG,GACpF;AAAA,UACA,8CAAC,kBAAAA,SAAA,EACC,wDAAC,oBAAAqB,SAAA,EAAW,SAAQ,SAAS,0BAAgB,MAAM,UAAU,GAAE,GACjE;AAAA,UACA,8CAAC,kBAAArB,SAAA,EACC;AAAA,YAAC,oBAAAqB;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,OAAM;AAAA,cACN,OAAO,MAAM,aAAa;AAAA,cAC1B,IAAI,EAAE,YAAY,kDAAkD,UAAU,GAAG;AAAA,cAEhF,gBAAM,YAAY,MAAM,UAAU,MAAM,GAAG,EAAE,KAAK,MAAM,UAAU,SAAS,KAAK,WAAM,MAAM;AAAA;AAAA,UAC/F,GACF;AAAA,UACA,8CAAC,kBAAArB,SAAA,EAAW,gBAAM,cAAc,UAAI;AAAA,WACtC;AAAA,QAKC,aACC,8CAAC,iBAAAD,SAAA,EAAS,IAAI,EAAE,YAAY,EAAE,SAAS,cAAc,EAAE,GACrD,wDAAC,kBAAAC,SAAA,EAAU,SAAS,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,QAAQ,EAAE,EAAE,GACtD,wDAAC,iBAAAsB,SAAA,EAAS,IAAI,MAAM,eAAa,MAC/B;AAAA,UAAC,aAAAC;AAAA,UAAA;AAAA,YACC,SAAQ;AAAA,YACR,KAAK;AAAA,YACL,UAAS;AAAA,YACT,IAAI,YAAU;AAAA,cACZ,GAAG;AAAA,cACH,IAAI;AAAA,cACJ,cAAc;AAAA,cACd,aAAS,uBAAM,MAAM,QAAQ,KAAK,SAAS,MAAM,QAAQ,SAAS,SAAS,OAAO,IAAI;AAAA,YACxF;AAAA,YAEC;AAAA,oBAAM,gBACL,+CAAC,aAAAA,SAAA,EAAI,MAAM,GAAG,UAAU,KACtB;AAAA;AAAA,kBAAC,oBAAAF;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,SAAQ;AAAA,oBACR,IAAI;AAAA,oBACJ,IAAI,EAAE,UAAU,MAAM,YAAY,KAAK,eAAe,UAAU,eAAe,YAAY;AAAA,oBAC5F;AAAA;AAAA,gBAED;AAAA,gBACA,8CAAC,oBAAAA,SAAA,EAAW,WAAU,OAAM,SAAQ,WAAU,IAAI,EAAE,YAAY,kDAAkD,YAAY,YAAY,WAAW,aAAa,GAAG,EAAE,GACpK,eAAK,UAAU,MAAM,cAAc,MAAM,CAAC,GAC7C;AAAA,iBACF;AAAA,cAED,MAAM,kBACL,+CAAC,aAAAE,SAAA,EAAI,MAAM,GAAG,UAAU,KACtB;AAAA;AAAA,kBAAC,oBAAAF;AAAA,kBAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,OAAM;AAAA,oBACN,SAAQ;AAAA,oBACR,IAAI;AAAA,oBACJ,IAAI,EAAE,UAAU,MAAM,YAAY,KAAK,eAAe,UAAU,eAAe,YAAY;AAAA,oBAC5F;AAAA;AAAA,gBAED;AAAA,gBACA,8CAAC,oBAAAA,SAAA,EAAW,WAAU,OAAM,SAAQ,WAAU,IAAI,EAAE,YAAY,kDAAkD,YAAY,YAAY,WAAW,aAAa,GAAG,EAAE,GACpK,eAAK,UAAU,MAAM,gBAAgB,MAAM,CAAC,GAC/C;AAAA,iBACF;AAAA;AAAA;AAAA,QAEJ,GACF,GACF,GACF;AAAA,SAEJ;AAAA,IAEJ;AA2BO,IAAM,WAA8B,CAAC,EAAE,IAAI,MAAM;AACtD,YAAM,CAAC,MAAM,OAAO,QAAI,yBAAS,CAAC;AAClC,YAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,EAAE;AAC3C,YAAM,CAAC,SAAS,UAAU,QAAI,yBAAwE,CAAC,CAAC;AAExG,YAAM,kBAA+B;AAAA,QACnC,OAAO,EAAE,MAAM,OAAO,GAAG,WAAW,UAAU,GAAG,QAAQ;AAAA,QACzD,CAAC,MAAM,UAAU,OAAO;AAAA,MAC1B;AAEA,YAAM,EAAE,OAAO,SAAS,MAAM,QAAI;AAAA,QAChC,MAAM,IAAI,aAAa,WAAW;AAAA,QAClC,CAAC,KAAK,WAAW;AAAA,MACnB;AAEA,YAAM,UAA2B,OAAO,cAAc,CAAC;AACvD,YAAM,QAAQ,OAAO,SAAS;AAE9B,aACE;AAAA,QAAC;AAAA;AAAA,UACC,OAAM;AAAA,UACN,UAAU,UAAU,kBAAa,GAAG,MAAM,eAAe,CAAC,SAAS,UAAU,IAAI,KAAK,GAAG;AAAA,UACzF,OAAK;AAAA,UACL,SACE,gFACE;AAAA;AAAA,cAAC,kBAAAG;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,QAAM;AAAA,gBACN,OAAO,QAAQ,UAAU;AAAA,gBACzB,UAAU,OAAK;AAAE,6BAAW,QAAM,EAAE,GAAG,GAAG,QAAQ,EAAE,OAAO,SAAS,OAAU,EAAE;AAAG,0BAAQ,CAAC;AAAA,gBAAG;AAAA,gBAC/F,IAAI,EAAE,UAAU,IAAI;AAAA,gBAEpB;AAAA,gEAAC,iBAAAC,SAAA,EAAS,OAAM,IAAG,yBAAW;AAAA,kBAC9B,8CAAC,iBAAAA,SAAA,EAAS,OAAM,WAAU,qBAAO;AAAA,kBACjC,8CAAC,iBAAAA,SAAA,EAAS,OAAM,WAAU,qBAAO;AAAA,kBACjC,8CAAC,iBAAAA,SAAA,EAAS,OAAM,WAAU,qBAAO;AAAA,kBACjC,8CAAC,iBAAAA,SAAA,EAAS,OAAM,WAAU,qBAAO;AAAA;AAAA;AAAA,YACnC;AAAA,YACA;AAAA,cAAC,kBAAAD;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,QAAM;AAAA,gBACN,OAAO,QAAQ,cAAc;AAAA,gBAC7B,UAAU,OAAK;AAAE,6BAAW,QAAM,EAAE,GAAG,GAAG,YAAY,EAAE,OAAO,SAAS,OAAU,EAAE;AAAG,0BAAQ,CAAC;AAAA,gBAAG;AAAA,gBACnG,IAAI,EAAE,UAAU,IAAI;AAAA,gBAEpB;AAAA,gEAAC,iBAAAC,SAAA,EAAS,OAAM,IAAG,wBAAU;AAAA,kBAC7B,8CAAC,iBAAAA,SAAA,EAAS,OAAM,6BAA4B,iBAAG;AAAA,kBAC/C,8CAAC,iBAAAA,SAAA,EAAS,OAAM,qBAAoB,kBAAI;AAAA,kBACxC,8CAAC,iBAAAA,SAAA,EAAS,OAAM,0BAAyB,yBAAW;AAAA,kBACpD,8CAAC,iBAAAA,SAAA,EAAS,OAAM,iCAAgC,oCAAsB;AAAA,kBACtE,8CAAC,iBAAAA,SAAA,EAAS,OAAM,qBAAoB,kBAAI;AAAA;AAAA;AAAA,YAC1C;AAAA,YACA;AAAA,cAAC,kBAAAD;AAAA,cAAA;AAAA,gBACC,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,OAAO,QAAQ,cAAc;AAAA,gBAC7B,UAAU,OAAK;AAAE,6BAAW,QAAM,EAAE,GAAG,GAAG,YAAY,EAAE,OAAO,SAAS,OAAU,EAAE;AAAG,0BAAQ,CAAC;AAAA,gBAAG;AAAA,gBACnG,IAAI,EAAE,UAAU,IAAI;AAAA;AAAA,YACtB;AAAA,aACF;AAAA,UAGD;AAAA,qBACC,8CAAC,aAAAD,SAAA,EAAI,IAAI,KAAK,IAAI,GAChB,wDAAC,cAAAG,SAAA,EAAM,UAAS,SAAS,gBAAM,SAAQ,GACzC;AAAA,YAGF,8CAAC,uBAAAC,SAAA,EACC,yDAAC,cAAAC,SAAA,EAAM,MAAK,SAAQ,IAAI,aACtB;AAAA,4DAAC,kBAAAC,SAAA,EACC,yDAAC,iBAAA9B,SAAA,EACC;AAAA,8DAAC,kBAAAC,SAAA,EAAU,IAAI,EAAE,OAAO,GAAG,GAAG;AAAA,gBAC9B,8CAAC,kBAAAA,SAAA,EAAU,kBAAI;AAAA,gBACf,8CAAC,kBAAAA,SAAA,EAAU,oBAAM;AAAA,gBACjB,8CAAC,kBAAAA,SAAA,EAAU,mBAAK;AAAA,gBAChB,8CAAC,kBAAAA,SAAA,EAAU,uBAAS;AAAA,gBACpB,8CAAC,kBAAAA,SAAA,EAAU,wBAAU;AAAA,iBACvB,GACF;AAAA,cACA,8CAAC,kBAAA8B,SAAA,EACE,6BAAmB,SAAS,OAAO,GACtC;AAAA,eACF,GACF;AAAA,YAEA;AAAA,cAAC,uBAAAC;AAAA,cAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,gBACP;AAAA,gBACA,cAAc,CAAC,GAAG,MAAM,QAAQ,CAAC;AAAA,gBACjC,aAAa;AAAA,gBACb,qBAAqB,OAAK;AAAE,8BAAY,OAAO,EAAE,OAAO,KAAK,CAAC;AAAG,0BAAQ,CAAC;AAAA,gBAAG;AAAA,gBAC7E,oBAAoB,CAAC,IAAI,IAAI,EAAE;AAAA,gBAC/B,IAAI,YAAU,EAAE,WAAW,aAAa,MAAM,QAAQ,OAAO,GAAG;AAAA;AAAA,YAClE;AAAA;AAAA;AAAA,MACF;AAAA,IAEJ;AAAA;AAAA;;;ACnSO,SAAS,WAAW,GAAiB;AAC1C,QAAM,OAAO,EAAE,YAAY;AAC3B,QAAM,QAAQ,OAAO,EAAE,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AACtD,QAAM,MAAM,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAC/C,SAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAChC;AAMO,SAAS,iBAAiB,MAAY,oBAAI,KAAK,GAA2C;AAC/F,QAAM,QAAQ,IAAI,KAAK,IAAI,YAAY,GAAG,IAAI,SAAS,GAAG,CAAC;AAC3D,SAAO;AAAA,IACL,WAAW,WAAW,KAAK;AAAA,IAC3B,SAAS,WAAW,GAAG;AAAA,EACzB;AACF;AAtBA;AAAA;AAAA;AAAA;AAAA;;;ACuCO,SAAS,SAAS,MAAkB,UAAwC;AACjF,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,EAAE,SAAS,8BAA8B,UAAU,UAAU;AAAA,IACtE,KAAK;AACH,aAAO,EAAE,SAAS,2BAA2B,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE7E,KAAK;AACH,aAAO,EAAE,SAAS,4BAA4B,UAAU,UAAU;AAAA,IACpE,KAAK;AACH,aAAO,EAAE,SAAS,yBAAyB,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE3E,KAAK;AACH,aAAO,EAAE,SAAS,gEAA2D,UAAU,UAAU;AAAA,IACnG,KAAK;AACH,aAAO,EAAE,SAAS,wBAAwB,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE1E,KAAK;AACH,aAAO,EAAE,SAAS,iBAAiB,UAAU,UAAU;AAAA,IACzD,KAAK;AACH,aAAO,EAAE,SAAS,0BAA0B,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE5E,KAAK;AACH,aAAO,EAAE,SAAS,6BAA6B,UAAU,UAAU;AAAA,IACrE,KAAK;AACH,aAAO,EAAE,SAAS,0BAA0B,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE5E,KAAK;AACH,aAAO,EAAE,SAAS,4BAA4B,UAAU,UAAU;AAAA,IACpE,KAAK;AACH,aAAO,EAAE,SAAS,yBAAyB,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAC3E,KAAK;AACH,aAAO,EAAE,SAAS,2BAA2B,UAAU,UAAU;AAAA,IAEnE,KAAK;AACH,aAAO,EAAE,SAAS,uBAAuB,UAAU,UAAU;AAAA,IAC/D,KAAK;AACH,aAAO,EAAE,SAAS,+CAA+C,UAAU,UAAU;AAAA,IACvF,KAAK;AACH,aAAO,EAAE,SAAS,iCAAiC,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAEnF,KAAK;AACH,aAAO,EAAE,SAAS,cAAc,UAAU,UAAU;AAAA,IACtD,KAAK;AACH,aAAO,EAAE,SAAS,wBAAwB,QAAQ,IAAI,UAAU,QAAQ;AAAA,IAE1E,KAAK;AACH,aAAO,EAAE,SAAS,2BAA2B,UAAU,UAAU;AAAA,IAEnE,KAAK;AACH,aAAO,EAAE,SAAS,uBAAuB,UAAU,UAAU;AAAA,IAE/D;AACE,aAAO;AAAA,EACX;AACF;AA9FA;AAAA;AAAA;AAAA;AAAA;;;ACSO,SAAS,oBACd,MACA,QACA,oBACA,UACS;AACT,MAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,sBAAsB,mBAAmB,WAAW,KAAK,UAAU;AAC1F,WAAO;AAAA,EACT;AACA,SAAO,KAAK,oBAAoB,KAAK,OAAK,EAAE,YAAY,UAAU,mBAAmB,SAAS,EAAE,IAAI,CAAC,KAAK;AAC5G;AAnBA;AAAA;AAAA;AAAA;AAAA;;;ACIO,SAAS,wBAAgC;AAC9C,SAAO;AACT;AAEO,SAAS,wBAAwB,gBAAiC;AACvE,QAAM,UAAU,gBAAgB,KAAK;AACrC,MAAI,SAAS;AACX,WAAO,WAAW,OAAO;AAAA,EAC3B;AACA,SAAO;AACT;AAEO,SAAS,uBAA+B;AAC7C,SAAO;AACT;AAEO,SAAS,yBAAiC;AAC/C,SAAO;AACT;AAtBA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAqDA,SAAS,gBAA2B;AAClC,MAAI,SAAS;AACb,MAAI;AAAE,aAAS,aAAa,QAAQC,cAAa,KAAK;AAAA,EAAM,QAAQ;AAAA,EAAe;AACnF,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,oBAAI,KAAK;AACvB,MAAI,WAAW,QAAS,OAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AAAA,WACxC,WAAW,MAAO,OAAM,SAAS,MAAM,SAAS,IAAI,EAAE;AAAA,WACtD,WAAW,MAAO,OAAM,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAAA,MACxD,OAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC;AACtC,SAAO,EAAE,OAAO,IAAI;AACtB;AA/DA,IAAAC,gBACAC,cACAC,eACAC,gBACAC,qBACAC,cACAC,aACAC,cACAC,mBACAC,0BACAC,0BACA,mBACA,yBACAC,mBACAC,yBACAC,yBACAC,iCAYAC,yCAiXWC,sBAhWLjB,gBAIA,WACA,WAeO;AAjEb;AAAA;AAAA;AAAA,IAAAC,iBAA8D;AAC9D,IAAAC,eAAgB;AAChB,IAAAC,gBAAkB;AAClB,IAAAC,iBAAmB;AACnB,IAAAC,sBAAuB;AACvB,IAAAC,eAAiB;AACjB,IAAAC,cAAgB;AAChB,IAAAC,eAAiB;AACjB,IAAAC,oBAAsB;AACtB,IAAAC,2BAA6B;AAC7B,IAAAC,2BAA6B;AAC7B,wBAA2B;AAC3B,8BAAgC;AAChC,IAAAC,oBAAwC;AACxC,IAAAC,0BAAoC;AACpC,IAAAC,0BAAkC;AAClC,IAAAC,kCAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAAC,0CAMO;AAEP;AACA;AACA;AAuWW,IAAAC,uBAAA;AAhWX,IAAMjB,iBAAgB;AAItB,IAAM,YAAgC,CAAC,YAAY,QAAQ,SAAS,UAAU,OAAO;AACrF,IAAM,YAAY,CAAC,MACjB,CAAC,CAAC,KAAM,UAAgC,SAAS,CAAC;AAc7C,IAAM,cAAkB,MAAM;AACnC,YAAM,UAAM,gCAAO,aAAa;AAChC,YAAM,eAAW,gCAAO,mCAAW;AAEnC,YAAM,CAAC,WAAW,YAAY,QAAI,yBAAoB,aAAa;AACnE,YAAM,CAAC,eAAe,gBAAgB,QAAI,yBAAqB,MAAM;AACnE,YAAI;AAAE,iBAAQ,aAAa,QAAQA,cAAa,KAAoB;AAAA,QAAM,QAAQ;AAAE,iBAAO;AAAA,QAAM;AAAA,MACnG,CAAC;AACD,YAAM,CAAC,cAAc,eAAe,QAAI,yCAAgB;AACxD,YAAM,CAAC,WAAW,YAAY,QAAI,yBAAkB,MAAM;AACxD,cAAM,IAAI,aAAa,IAAI,KAAK;AAChC,eAAO,UAAU,CAAC,IAAI,IAAI;AAAA,MAC5B,CAAC;AACD,YAAM,CAAC,QAAQ,SAAS,QAAI,yBAA6C,MAAM;AAC7E,cAAM,IAAI,aAAa,IAAI,QAAQ;AACnC,eAAO,MAAM,aAAa,MAAM,aAAa,IAAI;AAAA,MACnD,CAAC;AAKD,YAAM,CAAC,oBAAoB,qBAAqB,QAAI;AAAA,QAClD,MAAM,aAAa,IAAI,UAAU,MAAM;AAAA,MACzC;AACA,oCAAU,MAAM;AACd,YAAI,aAAa,IAAI,UAAU,MAAM,IAAK;AAC1C,8BAAsB,IAAI;AAC1B;AAAA,UACE,UAAQ;AACN,kBAAM,OAAO,IAAI,gBAAgB,IAAI;AACrC,iBAAK,OAAO,UAAU;AACtB,mBAAO;AAAA,UACT;AAAA,UACA,EAAE,SAAS,KAAK;AAAA,QAClB;AAAA,MACF,GAAG,CAAC,cAAc,eAAe,CAAC;AAKlC,YAAM,gBAAY;AAAA,QAChB,CAAC,QAAiB;AAChB,uBAAa,GAAG;AAChB;AAAA,YACE,UAAQ;AACN,oBAAM,OAAO,IAAI,gBAAgB,IAAI;AACrC,mBAAK,IAAI,OAAO,GAAG;AACnB,qBAAO;AAAA,YACT;AAAA,YACA,EAAE,SAAS,KAAK;AAAA,UAClB;AAAA,QACF;AAAA,QACA,CAAC,eAAe;AAAA,MAClB;AAGA,YAAM,uBAAmB;AAAA,QACvB,CAAC,MAA8B;AAC7B,uBAAa,MAAM;AACnB,oBAAU,CAAC;AACX;AAAA,YACE,UAAQ;AACN,oBAAM,OAAO,IAAI,gBAAgB,IAAI;AACrC,mBAAK,IAAI,OAAO,MAAM;AACtB,mBAAK,IAAI,UAAU,CAAC;AACpB,qBAAO;AAAA,YACT;AAAA,YACA,EAAE,SAAS,KAAK;AAAA,UAClB;AAAA,QACF;AAAA,QACA,CAAC,eAAe;AAAA,MAClB;AAGA,YAAM,kBAAc,4BAAY,MAAM;AACpC,kBAAU,MAAS;AACnB;AAAA,UACE,UAAQ;AACN,kBAAM,OAAO,IAAI,gBAAgB,IAAI;AACrC,iBAAK,OAAO,QAAQ;AACpB,mBAAO;AAAA,UACT;AAAA,UACA,EAAE,SAAS,KAAK;AAAA,QAClB;AAAA,MACF,GAAG,CAAC,eAAe,CAAC;AAEpB,YAAM,CAAC,YAAY,aAAa,QAAI,yBAA0E,IAAI;AAElH,YAAM,CAAC,WAAW,YAAY,QAAI,yBAA4B,IAAI;AAClE,YAAM,cAAc,sBAAsB,CAAC,CAAC;AAG5C,YAAM,CAAC,gBAAgB,iBAAiB,QAAI,yBAA8C,CAAC,CAAC;AAC5F,YAAM,CAAC,kBAAkB,mBAAmB,QAAI,yBAAkC,CAAC,CAAC;AAEpF,YAAM,EAAE,OAAO,UAAU,SAAS,aAAa,OAAO,UAAU,QAAI;AAAA,QAClE,MAAM,IAAI,YAAY;AAAA,QACtB,CAAC,GAAG;AAAA,MACN;AAEA,YAAM,EAAE,OAAO,MAAM,SAAS,aAAa,OAAO,WAAW,OAAO,YAAY,QAAI;AAAA,QAClF,MAAM,IAAI,SAAS;AAAA,QACnB,CAAC,GAAG;AAAA,MACN;AAEA,YAAM,EAAE,OAAO,WAAW,SAAS,eAAe,OAAO,aAAa,OAAO,cAAc,QAAI;AAAA,QAC7F,MAAM,IAAI,WAAW;AAAA,QACrB,CAAC,GAAG;AAAA,MACN;AAEA,YAAM,EAAE,OAAO,UAAU,SAAS,cAAc,OAAO,YAAY,OAAO,aAAa,QAAI;AAAA,QACzF,MAAM,IAAI,SAAS;AAAA,QACnB,CAAC,GAAG;AAAA,MACN;AAEA,YAAM,EAAE,OAAO,cAAc,QAAI,4BAAS,MAAM,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC;AAItE,YAAM,EAAE,OAAO,aAAa,QAAI;AAAA,QAC9B,YACE,eAAe,gBAAgB,UAC3B,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAC,CAAC,IACpC,CAAC;AAAA,QACP,CAAC,KAAK,aAAa;AAAA,MACrB;AAEA,YAAM,EAAE,SAAS,cAAc,QAAI,+CAAc,EAAE,YAAY,oEAA4B,CAAC;AAC5F,YAAM,EAAE,SAAS,cAAc,QAAI,+CAAc,EAAE,YAAY,oEAA4B,CAAC;AAC5F,YAAM,EAAE,SAAS,iBAAiB,QAAI,+CAAc,EAAE,YAAY,2EAAmC,CAAC;AACtG,YAAM,EAAE,SAAS,wBAAwB,QAAI,+CAAc,EAAE,YAAY,iFAAyC,CAAC;AACnH,YAAM,EAAE,SAAS,oBAAoB,QAAI,+CAAc,EAAE,YAAY,uEAA+B,CAAC;AACrG,YAAM,kBAAkB,eAAe,gBAAgB,WAAW;AAClE,YAAM,qBAAqB,eAAe,gBAAgB,4BAA4B;AAEtF,YAAM,EAAE,OAAO,aAAa,QAAI;AAAA,QAC9B,YACE,qBAAqB,IAAI,gBAAgB,EAAE,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC;AAAA,QAChE,CAAC,KAAK,kBAAkB;AAAA,MAC1B;AACA,YAAM,EAAE,OAAO,WAAW,QAAI;AAAA,QAC5B,YACE,qBAAqB,IAAI,cAAc,EAAE,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC;AAAA,QAC9D,CAAC,KAAK,kBAAkB;AAAA,MAC1B;AAGA,YAAM,YAAQ,wBAAQ,MAAM;AAC1B,YAAI,CAAC,UAAU,OAAQ,QAAO,CAAC;AAC/B,YAAI,CAAC,SAAU,QAAO;AACtB,cAAM,SAAS,SAAS;AACxB,cAAM,WAAW,SAAS;AAC1B,YAAI,UAAU,QAAQ;AACpB,iBAAO,SAAS,OAAO,OAAK,SAAS,SAAS,EAAE,OAAO,CAAC;AAAA,QAC1D;AAGA,eAAO,SAAS;AAAA,UAAO,OACrB,EAAE,oBAAoB,KAAK,OAAK,EAAE,YAAY,MAAM;AAAA,QACtD;AAAA,MACF,GAAG,CAAC,UAAU,QAAQ,CAAC;AAEvB,YAAM,EAAE,OAAO,OAAO,SAAS,cAAc,OAAO,YAAY,OAAO,aAAa,QAAI,iCAAc,YAAY;AAChH,cAAM,YAAY,WAAW,UAAU,KAAK;AAC5C,cAAM,UAAU,WAAW,UAAU,GAAG;AACxC,eAAO,IAAI,SAAS,WAAW,OAAO;AAAA,MACxC,GAAG,CAAC,KAAK,SAAS,CAAC;AAGnB,YAAM,4BAAwB,4BAAY,CAAC,OAAkB,WAAwB;AACnF,qBAAa,KAAK;AAClB,YAAI,QAAQ;AACV,2BAAiB,MAAM;AAAA,QACzB;AACA,0BAAkB,CAAC,CAAC;AACpB,4BAAoB,CAAC,CAAC;AAAA,MACxB,GAAG,CAAC,cAAc,gBAAgB,CAAC;AAGnC,YAAM,oBAAgB,4BAAY,OAAO,WAAmB;AAC1D,YAAI,eAAe,MAAM,MAAM,UAAa,iBAAiB,MAAM,EAAG;AACtE,4BAAoB,WAAS,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE;AACzD,YAAI;AACF,gBAAM,YAAY,WAAW,UAAU,KAAK;AAC5C,gBAAM,UAAU,WAAW,UAAU,GAAG;AACxC,gBAAM,OAAO,MAAM,IAAI,aAAa,QAAQ,WAAW,OAAO;AAC9D,4BAAkB,WAAS,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE;AAAA,QACzD,QAAQ;AACN,4BAAkB,WAAS,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE;AAAA,QACzD,UAAE;AACA,8BAAoB,WAAS,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE;AAAA,QAC5D;AAAA,MACF,GAAG,CAAC,KAAK,WAAW,gBAAgB,gBAAgB,CAAC;AAOrD,YAAM,oBAAgB,wBAAQ,MAAM;AAClC,YAAI,CAAC,WAAW,OAAQ,QAAO,CAAC;AAChC,cAAM,aAAa,UAAU;AAC7B,cAAM,aAAa,OAAO,QAAQ,OAAK,EAAE,UAAU,CAAC,CAAC;AACrD,cAAM,qBAAqB,cAAc,WAAW,SAAS;AAC7D,cAAM,qBAAqB,cAAc,WAAW,SAAS;AAC7D,YAAI,CAAC,sBAAsB,CAAC,mBAAoB,QAAO;AACvD,cAAM,UAAU,oBAAI,IAAI;AAAA,UACtB,GAAI,qBAAqB,aAAc,UAAU,IAAI,OAAK,EAAE,UAAU;AAAA,UACtE,GAAI,qBAAqB,aAAc,CAAC;AAAA,QAC1C,CAAC;AACD,eAAO,UAAU,OAAO,OAAK,QAAQ,IAAI,EAAE,UAAU,CAAC;AAAA,MACxD,GAAG,CAAC,WAAW,UAAU,KAAK,CAAC;AAE/B,YAAM,gBAAY,4BAAY,MAAM,IAAI,UAAU,GAAG,CAAC,GAAG,CAAC;AAE1D,YAAM,wBAAoB;AAAA,QACxB,OAAO,YAA8D;AACnE,cAAI;AACF,kBAAM,WAAW,MAAM,IAAI,YAAY,OAAO;AAC9C,kBAAM,QAAQ,SAAS,iBAAiB;AACxC,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AACZ,mBAAO;AAAA,UACT,SAAS,GAAQ;AAEf,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,sBAAkB;AAAA,QACtB,OAAO,OAAe,YAA8B;AAClD,cAAI;AACF,kBAAM,IAAI,UAAU,OAAO,OAAO;AAClC,kBAAM,QAAQ,SAAS,eAAe;AACtC,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AAEf,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,qBAAiB;AAAA,QACrB,OAAO,UAAkB;AACvB,cAAI;AACF,kBAAM,IAAI,SAAS,KAAK;AACxB,kBAAM,QAAQ,SAAS,cAAc;AACrC,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AACf,kBAAM,QAAQ,SAAS,cAAc,EAAE,OAAO;AAC9C,gBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,uBAAmB;AAAA,QACvB,OAAO,UAAkB;AACvB,cAAI;AACF,kBAAM,IAAI,WAAW,KAAK;AAC1B,kBAAM,QAAQ,SAAS,gBAAgB;AACvC,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AACf,kBAAM,QAAQ,SAAS,gBAAgB,EAAE,OAAO;AAChD,gBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,0BAAsB;AAAA,QAC1B,OAAO,UAAkB;AACvB,cAAI;AACF,kBAAM,IAAI,cAAc,KAAK;AAC7B,kBAAM,QAAQ,SAAS,mBAAmB;AAC1C,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AAEf,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,sBAAkB;AAAA,QACtB,OAAO,UAAkB;AACvB,cAAI;AACF,kBAAM,IAAI,UAAU,KAAK;AACzB,kBAAM,QAAQ,SAAS,eAAe;AACtC,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AACf,gBAAI,EAAE,MAAM,YAAY,EAAE,MAAM,SAAS,SAAS,iBAAiB,KAAK,EAAE,MAAM,SAAS,SAAS,eAAe,IAAI;AACnH,oBAAMkB,SAAQ,SAAS,sBAAsB;AAC7C,kBAAIA,OAAO,UAAS,KAAKA,MAAK;AAC9B,0BAAY;AACZ;AAAA,YACF;AACA,kBAAM,QAAQ,SAAS,eAAe,EAAE,OAAO;AAC/C,gBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,UAChC;AAAA,QACF;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,6BAAyB;AAAA,QAC7B,YAAY;AACV,cAAI;AACF,kBAAM,SAAS,MAAM,IAAI,iBAAiB;AAC1C,kBAAM,OAAO,OAAO,SAAS,IAAI,iBAAiB;AAClD,kBAAM,QAAQ,SAAS,IAAI;AAC3B,gBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,wBAAY;AAAA,UACd,SAAS,GAAQ;AACf,kBAAM,QAAQ,SAAS,cAAc,EAAE,OAAO;AAC9C,gBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,UAChC;AACA,iBAAO,EAAE,QAAQ,GAAG,QAAQ,EAAE;AAAA,QAChC;AAAA,QACA,CAAC,KAAK,aAAa,QAAQ;AAAA,MAC7B;AAEA,YAAM,mBAAmB,eAAe,CAAC;AAEzC,UAAI,kBAAkB;AACpB,eAAO,8CAAC,oCAAS;AAAA,MACnB;AAGA,UAAI,aAAa,CAAC,UAAU;AAC1B,cAAM,OAAQ,WAAmB,MAAM;AACvC,eACE,8CAAC,aAAAC,SAAA,EAAI,IAAI,EAAE,GAAG,GAAG,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GAChE;AAAA,UAAC,aAAAA;AAAA,UAAA;AAAA,YACC,IAAI;AAAA,cACF,UAAU;AAAA,cACV,IAAI;AAAA,cACJ,IAAI;AAAA,cACJ,WAAW;AAAA,cACX,SAAS;AAAA,cACT,eAAe;AAAA,cACf,YAAY;AAAA,cACZ,KAAK;AAAA,YACP;AAAA,YAEA;AAAA,4DAAC,oBAAAC,SAAA,EAAW,SAAQ,MAAK,IAAI,EAAE,YAAY,IAAI,GAC5C,gCAAsB,GACzB;AAAA,cACA,8CAAC,oBAAAA,SAAA,EAAW,OAAM,kBACf,kBAAQ,wBAAwB,eAAe,cAAc,GAChE;AAAA,cACA,+CAAC,kBAAAC,SAAA,EAAU,IAAI,EAAE,OAAO,QAAQ,UAAU,KAAK,IAAI,EAAE,GACnD;AAAA,8DAAC,yBAAAC,SAAA,EAAiB,YAAY,8CAAC,kBAAAC,SAAA,EAAe,GAC5C,wDAAC,oBAAAH,SAAA,EAAW,SAAQ,SAAQ,IAAI,EAAE,YAAY,IAAI,GAC/C,+BAAqB,GACxB,GACF;AAAA,gBACA,8CAAC,yBAAAI,SAAA,EACC,wDAAC,oBAAAJ,SAAA,EAAW,SAAQ,WAAU,OAAM,kBACjC,iCAAuB,GAC1B,GACF;AAAA,iBACF;AAAA;AAAA;AAAA,QACF,GACF;AAAA,MAEJ;AAEA,YAAM,WACJ;AAAA,QAAC,aAAAK;AAAA,QAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,CAAC,GAAG,MAAM,UAAU,CAAY;AAAA,UAC1C,SAAQ;AAAA,UACR,eAAc;AAAA,UAGd,IAAI;AAAA,YACF,WAAW;AAAA,YACX,kCAAkC,EAAE,QAAQ,GAAG,cAAc,cAAc;AAAA,YAC3E,4BAA4B,EAAE,WAAW,IAAI,eAAe,QAAQ,UAAU,GAAG;AAAA,UACnF;AAAA,UAEA;AAAA,0DAAC,YAAAC,SAAA,EAAI,OAAM,YAAW,OAAM,YAAW;AAAA,YACvC,8CAAC,YAAAA,SAAA,EAAI,OAAM,QAAO,OAAM,QAAO;AAAA,YAC/B,8CAAC,YAAAA,SAAA,EAAI,OAAM,SAAQ,OAAM,SAAQ;AAAA,YACjC,8CAAC,YAAAA,SAAA,EAAI,OAAM,UAAS,OAAM,UAAS;AAAA,YAClC,SAAS,kBAAkB,8CAAC,YAAAA,SAAA,EAAI,OAAM,aAAY,OAAM,SAAQ;AAAA;AAAA;AAAA,MACnE;AAGF,aACE,+CAAC,aAAAP,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,EAAE,GAC1D;AAAA,sDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,GACtB;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA,OAAO,SAAS,CAAC;AAAA,YACjB,MAAM,QAAQ,CAAC;AAAA,YACf,SAAS,eAAe;AAAA,YACxB;AAAA,YACA,oBAAoB,MAAM,sBAAsB,IAAI;AAAA,YACpD,oBAAoB;AAAA,YACpB,MAAM;AAAA;AAAA,QACR,GACF;AAAA,QAEA,+CAAC,mCACE;AAAA,wBAAc,eAAe,MAAM;AAEpC,gBAAI,CAAC,eAAe,CAAC,aAAa,MAAM,WAAW,GAAG;AACpD,qBACE,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,KAAK,IAAI,QAAQ,IAAI,EAAE,GAC1C;AAAA,gBAAC,aAAAA;AAAA,gBAAA;AAAA,kBACC,IAAI;AAAA,oBACF,WAAW;AAAA,oBACX,IAAI;AAAA,oBACJ,SAAS;AAAA,oBACT,eAAe;AAAA,oBACf,YAAY;AAAA,oBACZ,KAAK;AAAA,kBACP;AAAA,kBAEA;AAAA,kEAAC,oBAAAC,SAAA,EAAW,SAAQ,MAAK,IAAI,EAAE,YAAY,IAAI,GAAG,uCAElD;AAAA,oBACA;AAAA,sBAAC,aAAAD;AAAA,sBAAA;AAAA,wBACC,WAAU;AAAA,wBACV,IAAI;AAAA,0BACF,WAAW;AAAA,0BACX,IAAI;AAAA,0BACJ,SAAS;AAAA,0BACT,eAAe;AAAA,0BACf,KAAK;AAAA,0BACL,QAAQ,EAAE,OAAO,iBAAiB;AAAA,wBACpC;AAAA,wBAEA;AAAA,wEAAC,QAAG,4BAAc;AAAA,0BAClB,8CAAC,QAAG,+BAAiB;AAAA,0BACrB,8CAAC,QAAG,yBAAW;AAAA;AAAA;AAAA,oBACjB;AAAA,oBACA;AAAA,sBAAC,eAAAQ;AAAA,sBAAA;AAAA,wBACC,SAAQ;AAAA,wBACR,OAAM;AAAA,wBACN,SAAS,MAAM,sBAAsB,IAAI;AAAA,wBAC1C;AAAA;AAAA,oBAED;AAAA;AAAA;AAAA,cACF,GACF;AAAA,YAEJ;AAEA,mBACE,+CAAC,aAAAC,SAAA,EAAK,WAAS,MAAC,SAAS,GAAG,YAAW,cACrC;AAAA,4DAAC,aAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB;AAAA,gBAAC;AAAA;AAAA,kBACC,OAAO,SAAS;AAAA,kBAChB;AAAA,kBACA,cAAc;AAAA,kBACd,QAAQ,aAAa,CAAC;AAAA,kBACtB;AAAA,kBACA;AAAA,kBACA,mBAAmB;AAAA,kBACnB,SAAS;AAAA,kBACT;AAAA;AAAA,cACF,GACF;AAAA,cACA,8CAAC,aAAAA,SAAA,EAAK,MAAI,MAAC,IAAI,IAAI,IAAI,GACrB,wDAAC,uBAAoB,SAAO,MAAC,aAAW,MAAC,UAAU,YAAY,MAAM,OAAc,MAAM,QAAQ,CAAC,GAAG,GACvG;AAAA,eACF;AAAA,UAEJ,GAAG;AAAA,UAEF,cAAc,WAAW,MAAM;AAC9B,gBAAI,WAAW;AACb,qBACE,+CAAC,cAAAC,SAAA,EAAM,UAAS,SAAQ;AAAA;AAAA,gBACC,UAAkB,WAAW;AAAA,gBACpD,8CAAC,aAAAV,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,eAAAQ,SAAA,EAAO,MAAK,SAAQ,SAAS,aAAa,mBAAK,GAClD;AAAA,iBACF;AAAA,YAEJ;AACA,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,QAAQ,CAAC;AAAA,gBACf,SAAS,eAAe;AAAA,gBACxB,oBAAoB,MAAM,sBAAsB,IAAI;AAAA,gBACpD,WAAW;AAAA,gBACX,YAAY;AAAA,gBACZ,cAAc;AAAA,gBACd,aAAa;AAAA,gBACb,oBAAoB;AAAA,gBACpB;AAAA,gBACA,eAAe;AAAA;AAAA,YACjB;AAAA,UAEJ,GAAG;AAAA,UAEF,cAAc,YAAY,MAAM;AAC/B,gBAAI,YAAY;AACd,qBACE,+CAAC,cAAAE,SAAA,EAAM,UAAS,SAAQ;AAAA;AAAA,gBACE,WAAmB,WAAW;AAAA,gBACtD,8CAAC,aAAAV,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,eAAAQ,SAAA,EAAO,MAAK,SAAQ,SAAS,cAAc,mBAAK,GACnD;AAAA,iBACF;AAAA,YAEJ;AAGA,kBAAM,YAAY,oBAAI,IAAsB;AAC5C,uBAAW,KAAK,gBAAgB,CAAC,EAAG,WAAU,IAAI,EAAE,SAAS,CAAC;AAC9D,uBAAW,KAAK,SAAS,CAAC,EAAG,WAAU,IAAI,EAAE,SAAS,CAAC;AACvD,kBAAM,eAAe,MAAM,KAAK,UAAU,OAAO,CAAC;AAClD,kBAAM,WAAW,eAAe,gBAAgB,YAAY;AAC5D,kBAAM,qBAAqB,eAAe,gBAAgB,sBAAsB,CAAC;AAEjF,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,gBACP,SAAS;AAAA,gBACT,cAAc,YAAU,eAAe,MAAM,KAAK;AAAA,gBAClD,qBAAqB,YAAU,iBAAiB,MAAM,KAAK;AAAA,gBAC3D,WAAW,mBAAmB,iBAAiB,CAAC;AAAA,gBAChD,YAAY,OAAK,cAAc,EAAE,MAAM,QAAQ,MAAM,EAAE,CAAC;AAAA,gBACxD,WAAW,mBAAmB,iBAAiB,CAAC;AAAA,gBAChD,cAAc,MAAM,cAAc,EAAE,MAAM,SAAS,CAAC;AAAA,gBACpD,kBAAkB,OAChB,mBACA,oBACA,oBAAoB,GAAG,UAAU,SAAS,oBAAoB,QAAQ;AAAA,gBAExE,iBAAiB,OAAK,cAAc,EAAE,MAAM,WAAW,MAAM,EAAE,CAAC;AAAA,gBAChE;AAAA,gBACA,cAAc,UAAQ,cAAc,KAAK,OAAO;AAAA;AAAA,YAClD;AAAA,UAEJ,GAAG;AAAA,UAEF,cAAc,aAAa,MAAM;AAChC,gBAAI,aAAa;AACf,qBACE,+CAAC,cAAAE,SAAA,EAAM,UAAS,SAAQ;AAAA;AAAA,gBACG,YAAoB,WAAW;AAAA,gBACxD,8CAAC,aAAAV,SAAA,EAAI,IAAI,EAAE,IAAI,EAAE,GACf,wDAAC,eAAAQ,SAAA,EAAO,MAAK,SAAQ,SAAS,eAAe,mBAAK,GACpD;AAAA,iBACF;AAAA,YAEJ;AACA,mBACE;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,aAAa,CAAC;AAAA,gBACzB,OAAO,SAAS,CAAC;AAAA,gBACjB,SAAS;AAAA;AAAA,YACX;AAAA,UAEJ,GAAG;AAAA,UAEF,cAAc,WAAW,SAAS,kBAAkB,8CAAC,YAAS,KAAU;AAAA,WACzE;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM;AAAA,YACN,SAAS,MAAM;AACb,oCAAsB,KAAK;AAC3B,2BAAa,IAAI;AAAA,YACnB;AAAA,YACA,MAAM,YAAY,SAAS;AAAA,YAC3B;AAAA,YACA,MAAM,QAAQ,CAAC;AAAA,YACf,QAAQ;AAAA,YACR;AAAA,YACA,eAAe;AAAA,YACf,OAAO,SAAS,CAAC;AAAA,YACjB,UAAU,SAAS;AAAA,YACnB,uBAAuB,eAAe;AAAA,YACtC,aAAa;AAAA,YACb,aAAa;AAAA,YACb,iBAAiB;AAAA,YACjB,aAAa;AAAA;AAAA,QACf;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,CAAC,CAAC;AAAA,YACR,SAAS,MAAM,cAAc,IAAI;AAAA,YACjC,MAAM,YAAY,SAAS,YAAY,SAAU,YAAY,QAAQ;AAAA,YACrE,MAAM,YAAY;AAAA,YAClB,WAAW,aAAa,CAAC;AAAA,YACzB,QAAQ;AAAA,YACR,aAAa,YAAY,SAAS;AAAA,YAClC,eAAe,UAAU;AAAA,YACzB,oBAAoB,eAAe,gBAAgB;AAAA,YACnD,UAAU,OAAO,SAAS,mBAAmB;AAC3C,kBAAI;AACF,oBAAI,YAAY,SAAS,UAAU,WAAW,MAAM;AAClD,wBAAM,WAAW,WAAW,KAAK,UAAU;AAC3C,wBAAM,IAAI,WAAW,WAAW,KAAK,SAAS;AAAA,oBAC5C,GAAI;AAAA;AAAA,oBAEJ,GAAI,OAAO,aAAa,WAAW,EAAE,sBAAsB,SAAS,IAAI,CAAC;AAAA,kBAC3E,CAAC;AAAA,gBACH,OAAO;AACL,wBAAM,UAAU,MAAM,IAAI,WAAW,OAA4B;AAGjE,wBAAM,SAAmB,CAAC;AAC1B,6BAAW,KAAK,kBAAkB,CAAC,GAAG;AACpC,wBAAI;AACF,4BAAM,IAAI,cAAc,QAAQ,SAAS,CAAC;AAAA,oBAC5C,SAAS,GAAQ;AACf,6BAAO,KAAK,GAAG,EAAE,aAAa,KAAK,EAAE,OAAO,GAAG;AAAA,oBACjD;AAAA,kBACF;AACA,sBAAI,OAAO,QAAQ;AACjB,6BAAS,KAAK;AAAA,sBACZ,SAAS,sDAAsD,OAAO,KAAK,IAAI,CAAC;AAAA,sBAChF,UAAU;AAAA,oBACZ,CAAC;AACD,iCAAa;AACb;AAAA,kBACF;AAAA,gBACF;AACA,sBAAM,QAAQ,SAAS,iBAAiB;AACxC,oBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,6BAAa;AAAA,cACf,SAAS,GAAQ;AACf,sBAAM,QAAQ,SAAS,iBAAiB,EAAE,OAAO;AACjD,oBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,cAChC;AAAA,YACF;AAAA,YACA,kBAAkB,mBAAmB,oBAAoB,CAAC,eAAe,gBAAgB;AAAA,YACzF,aAAa,OAAO,eAAe,oBAAoB;AACrD,kBAAI,CAAC,YAAY,KAAM;AACvB,oBAAM,UAAU,MAAM,IAAI,cAAc,WAAW,KAAK,SAAS;AAAA,gBAC/D;AAAA,gBACA,GAAI,kBAAkB,EAAE,gBAAgB,IAAI,CAAC;AAAA,cAC/C,CAAC;AACD,4BAAc,OAAM,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,QAAQ,IAAI,CAAE;AAC9D,2BAAa;AAAA,YACf;AAAA,YACA,gBAAgB,OAAM,kBAAiB;AACrC,kBAAI,CAAC,YAAY,KAAM;AACvB,oBAAM,UAAU,MAAM,IAAI;AAAA,gBACxB,WAAW,KAAK;AAAA,gBAChB;AAAA,cACF;AACA,4BAAc,OAAM,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,QAAQ,IAAI,CAAE;AAC9D,2BAAa;AAAA,YACf;AAAA,YACA,yBACE,mBAAmB,sBAAsB;AAAA,YAE3C,cAAc,gBAAgB,CAAC;AAAA,YAC/B,sBAAsB,OAAM,mBAAkB;AAC5C,kBAAI,CAAC,YAAY,KAAM;AACvB,kBAAI;AACF,sBAAM,UAAU,MAAM,IAAI;AAAA,kBACxB,WAAW,KAAK;AAAA,kBAChB;AAAA,gBACF;AACA,8BAAc,OAAM,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,QAAQ,IAAI,CAAE;AAC9D,sBAAM,QAAQ,SAAS,sBAAsB;AAC7C,oBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,6BAAa;AAAA,cACf,SAAS,GAAQ;AACf,sBAAM,QAAQ,SAAS,iBAAiB,EAAE,OAAO;AACjD,oBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,cAChC;AAAA,YACF;AAAA,YACA,qBACE,mBAAmB,sBAAsB;AAAA,YAE3C,YAAY,cAAc,CAAC;AAAA,YAC3B,kBAAkB,OAAM,iBAAgB;AACtC,kBAAI,CAAC,YAAY,KAAM;AACvB,kBAAI;AACF,sBAAM,UAAU,MAAM,IAAI;AAAA,kBACxB,WAAW,KAAK;AAAA,kBAChB;AAAA,gBACF;AACA,8BAAc,OAAM,KAAK,EAAE,OAAO,EAAE,GAAG,GAAG,MAAM,QAAQ,IAAI,CAAE;AAC9D,sBAAM,QAAQ,SAAS,kBAAkB;AACzC,oBAAI,MAAO,UAAS,KAAK,KAAK;AAC9B,6BAAa;AAAA,cACf,SAAS,GAAQ;AACf,sBAAM,QAAQ,SAAS,iBAAiB,EAAE,OAAO;AACjD,oBAAI,MAAO,UAAS,KAAK,KAAK;AAAA,cAChC;AAAA,YACF;AAAA;AAAA,QACF;AAAA,SAEF;AAAA,IAEJ;AAAA;AAAA;;;ACjwBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAG,0BAA6C;AAC7C,IAAAC,8BAMO;AACP;AACA;AAeU,IAAAC,uBAAA;AAbV,IAAM,aAAa,yCAAa,KAAK;AAAA,EACnC,QAAQ,kBACN,aAAa;AAAA,IACX,KAAK;AAAA,IACL,MAAM,EAAE,UAAU,yCAAa,cAAc,4CAAgB;AAAA,IAC7D,SAAS,CAAC,EAAE,UAAU,aAAa,MAAM,IAAI,WAAW,UAAU,YAAY;AAAA,EAChF,CAAC;AACL,CAAC;AAED,IAAM,cAAc,0CAAc,KAAK;AAAA,EACrC,QAAQ;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM,8CAAC,wBAAAC,YAAA,EAAe;AAAA,IACtB,UAAU;AAAA,IACV,QAAQ,YAAY;AAClB,YAAM,EAAE,aAAAC,aAAY,IAAI,MAAM;AAC9B,aAAO,8CAACA,cAAA,EAAY;AAAA,IACtB;AAAA,EACF;AACF,CAAC;AAEM,IAAM,oBAAgB,kDAAqB;AAAA,EAChD,UAAU;AAAA,EACV,QAAQ;AAAA,IACN,MAAM;AAAA,EACR;AAAA,EACA,YAAY,CAAC,YAAY,WAAW;AACtC,CAAC;;;ADtCD;AACA;AACA;AACA;AACA;;;AELA,IAAAC,iBAA8D;AAC9D,IAAAC,gBAAkB;AAClB,IAAAC,eAAgB;AAChB,IAAAC,sBAAuB;AACvB,IAAAC,sBAAwB;AACxB,IAAAC,iBAAmB;AACnB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqE;AACrE,IAAAC,0BAAuB;AACvB,IAAAC,8BAA4B;AAC5B,IAAAC,0BAAqB;AACrB;AACA;AACA;AAEA;AACA;AACA;AACA;;;ACnBA;AACA;AACA;AAOO,SAAS,aAAa,UAAkB,QAAwB;AACrE,SAAO,GAAG,aAAa,QAAQ,CAAC,WAAM,aAAa,MAAM,CAAC;AAC5D;AAOO,SAAS,WAAW,MAAY,oBAAI,KAAK,GAAW;AACzD,QAAM,OAAO,IAAI,YAAY;AAC7B,QAAM,QAAQ,IAAI,SAAS;AAC3B,QAAM,MAAM,IAAI,QAAQ;AACxB,QAAM,WAAW,GAAG,IAAI,IAAI,OAAO,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAC9D,QAAM,SAAS,GAAG,IAAI,IAAI,OAAO,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,GAAG,EAAE,SAAS,GAAG,GAAG,CAAC;AAC5F,SAAO,aAAa,UAAU,MAAM;AACtC;AAOO,SAAS,mBAAmB,QAAwD;AACzF,MAAI,CAAC,UAAU,OAAO,WAAW,GAAG;AAClC,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACxD,QAAM,WAAW,OAAO;AAAA,IACtB,CAAC,KAAK,MAAO,EAAE,QAAQ,IAAI,QAAQ,IAAI;AAAA,IACvC,OAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAAW,OAAO;AACxB,QAAM,WAAW,aAAa,SAAS,IAAI;AAE3C,SAAO,oBAAoB,QAAQ,OAAO,aAAa,IAAI,KAAK,GAAG,WAAW,OAAO,KAAK,CAAC,UAAU,OAAO,SAAS,KAAK,CAAC,OAAO,QAAQ;AAC5I;AAWO,SAAS,WACd,QACA,MAAY,oBAAI,KAAK,GACb;AACR,QAAM,MAAM,WAAW,GAAG;AAC1B,SAAO,OAAO,KAAK,OAAK,EAAE,SAAS,GAAG,GAAG,SAAS;AACpD;AAMO,SAAS,aAAa,OAAgD;AAC3E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,OAAO,MAAM,eAAe,CAAC;AAC3C,QAAM,UAAU,WAAW,MAAM,iBAAiB,CAAC;AACnD,QAAM,WAAW,WAAW,MAAM,qBAAqB,CAAC;AAExD,SAAO,GAAG,KAAK,eAAY,OAAO,YAAS,QAAQ;AACrD;;;AD2CkB,IAAAC,uBAAA;AAtFlB,SAAS,kBAAkB,QAAgD;AACzE,QAAM,MAAM,oBAAI,KAAK;AACrB,QAAM,QAAQ,oBAAI,KAAK;AACvB,MAAI,WAAW,SAAS;AACtB,UAAM,SAAS,GAAG,GAAG,GAAG,CAAC;AAAA,EAC3B,WAAW,WAAW,MAAM;AAC1B,UAAM,QAAQ,MAAM,QAAQ,IAAI,CAAC;AAAA,EACnC,OAAO;AACL,UAAM,QAAQ,MAAM,QAAQ,IAAI,EAAE;AAAA,EACpC;AACA,SAAO,EAAE,OAAO,IAAI;AACtB;AAGO,IAAM,oBAAgD,CAAC;AAAA,EAC5D,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,OAAO;AACT,MAAM;AACJ,QAAM,UAAM,gCAAO,aAAa;AAChC,QAAM,qBAAiB,yCAAY,YAAY;AAC/C,QAAM,EAAE,UAAU,MAAM,SAAS,gBAAgB,OAAO,aAAa,IAAI,kBAAkB;AAC3F,QAAM,CAAC,QAAQ,SAAS,QAAI,yBAAqB,aAAa;AAC9D,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAkB,IAAI;AAC1D,QAAM,CAAC,OAAO,QAAQ,QAAI,yBAA8B,IAAI;AAE5D,gCAAU,MAAM;AACd,QAAI,YAAY;AAChB,oBAAgB,IAAI;AACpB,kBAAc,IAAI;AAElB,UAAM,EAAE,OAAAC,QAAO,KAAAC,KAAI,IAAI,kBAAkB,MAAM;AAC/C,UAAMC,aAAY,WAAWF,MAAK;AAClC,UAAMG,WAAU,WAAWF,IAAG;AAE9B,QAAI,SAASC,YAAWC,QAAO,EAC5B,KAAK,CAAC,gBAAgB;AACrB,UAAI,UAAW;AACf,eAAS,WAAW;AACpB,sBAAgB,KAAK;AAAA,IACvB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAI,CAAC,WAAW;AACd,sBAAc,GAAG;AACjB,iBAAS,IAAI;AACb,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,KAAK,MAAM,CAAC;AAEhB,QAAM,gBAAY;AAAA,IAChB,MAAM,gBAAgB;AAAA,MACpB,SAAS,kBAAkB;AAAA,MAC3B,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,UAAU,MAAM,UAAU,KAAK;AAAA,IACjC,CAAC;AAAA,IACD,CAAC,gBAAgB,cAAc,cAAc,UAAU,YAAY,IAAI;AAAA,EACzE;AAEA,QAAM,UAAuB,OAAO,aAAAC,UAAM,cAAAC;AAC1C,QAAM,iBAAiB,CAAC,gBAAgB,cAAc;AAEtD,QAAM,aAAa,OAAO,eAAe,CAAC,GAAG,IAAI,QAAM;AAAA,IACrD,MAAM,EAAE;AAAA,IACR,OAAO,EAAE;AAAA,EACX,EAAE;AAEF,QAAM,eAAe,UAAU,SAAS;AAExC,QAAM,EAAE,OAAO,IAAI,IAAI,kBAAkB,MAAM;AAC/C,QAAM,YAAY,WAAW,KAAK;AAClC,QAAM,UAAU,WAAW,GAAG;AAC9B,QAAM,mBAAmB,aAAa,WAAW,OAAO;AACxD,QAAM,yBAAyB,mBAAmB,SAAS;AAE3D,SACE,+CAAC,WAAQ,IAAI,OAAO,EAAE,QAAQ,OAAO,IAAI,EAAE,GAAG,GAAG,QAAQ,OAAO,GAE9D;AAAA,mDAAC,aAAAD,SAAA,EAAI,SAAQ,QAAO,gBAAgB,OAAO,aAAa,iBAAiB,YAAW,UAAS,IAAI,KAC9F;AAAA,OAAC,QAAQ,8CAAC,oBAAAE,SAAA,EAAW,SAAQ,MAAM,iBAAM;AAAA,MAC1C,8CAAC,oBAAAC,SAAA,EAAY,MAAK,SAAQ,IAAI,EAAE,UAAU,GAAG,GAC3C;AAAA,QAAC,eAAAC;AAAA,QAAA;AAAA,UACC,OAAO;AAAA,UACP,UAAU,OAAK,UAAU,EAAE,OAAO,KAAmB;AAAA,UACrD,cAAY;AAAA,UACZ,YAAY,EAAE,cAAc,eAAe;AAAA,UAE3C;AAAA,0DAAC,iBAAAC,SAAA,EAAS,OAAM,SAAQ,mBAAK;AAAA,YAC7B,8CAAC,iBAAAA,SAAA,EAAS,OAAM,MAAK,gBAAE;AAAA,YACvB,8CAAC,iBAAAA,SAAA,EAAS,OAAM,OAAM,iBAAG;AAAA;AAAA;AAAA,MAC3B,GACF;AAAA,OACF;AAAA,IAGC,UAAU,SAAS,aAClB,+CAAC,aAAAL,SAAA,EAAI,IAAI,EAAE,WAAW,IAAI,GACxB;AAAA,oDAAC,iBAAAM,SAAA,EAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,MAChE,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,eAAc,OAAM,QAAO,QAAQ,KAAK;AAAA,OAC5D;AAAA,IAID,UAAU,SAAS,WAClB,8CAAC,oBAAAJ,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAC5D,oBAAU,SACb;AAAA,IAID,UAAU,SAAS,mBAClB,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,EAAE,GAC5D,6BACH;AAAA,IAID,UAAU,SAAS,WAAW,kBAC7B,8CAAC,aAAAF,SAAA,EAAI,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,GAAG,GAAG,iBAAiB,gBAAgB,cAAc,EAAE,GAC9E,wDAAC,oBAAAE,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAC/B,iCACH,GACF;AAAA,IAGD,UAAU,SAAS,WAClB,gFAEE;AAAA;AAAA,QAAC,oBAAAA;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,IAAI;AAAA,YACF,YAAY;AAAA,YACZ,IAAI,eAAe,MAAM;AAAA,YACzB,OAAO,UAAU,mBAAmB,mBAAmB;AAAA,UACzD;AAAA,UAEC,oBAAU,mBAAmB,wBAAwB,aAAa,KAAK;AAAA;AAAA,MAC1E;AAAA,MAGC,gBAAgB,CAAC,UAAU,oBAC1B,gFACE;AAAA;AAAA,UAAC,aAAAF;AAAA,UAAA;AAAA,YACC,QAAQ;AAAA,YACR,MAAK;AAAA,YACL,cAAY;AAAA,YACZ,IAAI,EAAE,IAAI,IAAI;AAAA,YAEd,wDAAC,wCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,8BAAU,MAAM,WAAW,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE,GACzE;AAAA,4DAAC,0BAAM,SAAQ,QAAO,MAAI,MAAC;AAAA,cAC3B,8CAAC,4BAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,GAAI;AAAA,cAC5D;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,QAAQ,OAAO;AAAA,kBACf,MAAM,OAAO;AAAA,kBACb,aAAa;AAAA,kBACb,KAAK;AAAA,kBACL,mBAAmB;AAAA;AAAA,cACrB;AAAA,eACF,GACF;AAAA;AAAA,QACF;AAAA,QACA,+CAAC,oBAAAE,SAAA,EAAW,SAAQ,WAAU,OAAM,kBAAiB,IAAI,EAAE,SAAS,SAAS,IAAI,EAAE,GAAG;AAAA;AAAA,UACtE;AAAA,UAAiB;AAAA,WACjC;AAAA,SACF;AAAA,MAID,iBAAiB,KAChB,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,WAAU,IAAI,EAAE,IAAI,GAAG,SAAS,QAAQ,GAC1D,wDAAC,gCAAK,IAAI,eAAe,GAAG,OAAM,WAAU,iCAE5C,GACF;AAAA,OAEJ;AAAA,KAEJ;AAEJ;;;AF3NA;;;AI4BA,IAAAK,iBAA6F;AAC7F,IAAAC,8BAA4B;AAC5B,IAAAC,iBAAkB;AAClB,IAAAC,eAAgB;AAChB,IAAAC,iBAAmB;AACnB,IAAAC,sBAAuB;AACvB,IAAAC,mBAAqB;AACrB,IAAAC,mBAAqB;AACrB,IAAAC,kBAAyB;AACzB,2BAA0B;AAC1B,IAAAC,0BAA2B;AAC3B,IAAAC,mBAAoF;AACpF,IAAAC,0BAAuB;AACvB,IAAAC,0BAAqB;AACrB;AACA;AAEA;AACA;;;AC5CO,IAAM,eAAgC,CAAC,UAAU,YAAY;AAU7D,SAAS,YAAY,MAKuB;AACjD,QAAM,QAAQ,KAAK,QAAQ,cAAc;AAAA,IAAI,SAC3C,OAAO,QAAQ,WAAW,EAAE,MAAM,IAAI,IAAI;AAAA,EAC5C;AACA,QAAM,cAAc,KAAK,UAAU,SAAS;AAC5C,QAAM,MAAM,KAAK,OAAO,SAAO;AAC7B,QAAI,IAAI,SAAS,UAAW,QAAO;AACnC,QAAI,IAAI,SAAS,aAAc,QAAO,KAAK,aAAa;AACxD,WAAO;AAAA,EACT,CAAC;AACD,MACE,KAAK,SAAS,UACd,CAAC,KAAK,WACN,eACA,CAAC,IAAI,KAAK,OAAK,EAAE,SAAS,SAAS,GACnC;AACA,QAAI,QAAQ,EAAE,MAAM,UAAU,CAAC;AAAA,EACjC;AACA,SAAO;AACT;;;ADYA;AACA;AACA;AACA;AACA;AAUA;AAoFE,IAAAC,uBAAA;AAjCF,IAAM,QAAqE;AAAA,EACzE,KAAK,EAAE,MAAM,OAAO,MAAM,qBAAqB;AAAA,EAC/C,MAAM,EAAE,MAAM,QAAQ,MAAM,qBAAqB;AAAA,EACjD,MAAM,EAAE,MAAM,QAAQ,MAAM,iBAAiB;AAC/C;AAEA,IAAM,aAA4C;AAAA,EAChD,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,cAAc;AAChB;AAGA,SAAS,YAAY,GAAmB;AACtC,QAAM,IAAI,KAAK;AACf,MAAI,KAAK,OAAO,OAAO,UAAU,CAAC,EAAG,QAAO,IAAI,CAAC;AACjD,SAAO,OAAO,CAAC;AACjB;AAGA,SAAS,aAAa,OAA4B;AAChD,MAAI,MAAM,OAAQ,QAAO;AACzB,SAAO,GAAG,YAAY,MAAM,KAAK,CAAC,MAAM,YAAY,MAAM,MAAM,CAAC;AACnE;AAGA,SAAS,WAAW,OAA4B;AAC9C,QAAMC,UAAS,kBAAkB,MAAM,cAAc;AACrD,SAAOA,UAAS,UAAUA,OAAM,KAAK;AACvC;AAGA,IAAM,MAAgE,CAAC,EAAE,UAAU,MAAM,MAAM,MAC7F;AAAA,EAAC,oBAAAC;AAAA,EAAA;AAAA,IACC;AAAA,IACA,IAAI,YAAU;AAAA,MACZ,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,eAAe;AAAA,MACf,YAAY;AAAA,MACZ,OAAO,OAAO,UAAU,OAAO,IAAI,IAAI,MAAM,QAAQ,KAAK;AAAA,MAC1D,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,IAEC;AAAA;AACH;AAQF,IAAM,aAMD,CAAC,EAAE,OAAO,OAAO,MAAM,OAAO,UAAU,MAAM,MACjD,+CAAC,aAAAC,SAAA,EAAI,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,GAC9B;AAAA,iDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,OAAO,UAAU,EAAE,GACxE;AAAA;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,IAAI,YAAU;AAAA,UACZ,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,SAAS,UAAU,OAAO,IAAI;AAAA,UAC9B,YAAY;AAAA,QACd;AAAA;AAAA,IACF;AAAA,IACA,8CAAC,OAAK,iBAAM;AAAA,KACd;AAAA,EACA;AAAA,IAAC,oBAAAD;AAAA,IAAA;AAAA,MACC;AAAA,MACA,IAAI;AAAA,QACF,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,YAAY;AAAA,QACZ,IAAI;AAAA,QACJ,oBAAoB;AAAA,QACpB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,cAAc;AAAA,MAChB;AAAA,MAEC;AAAA;AAAA,EACH;AAAA,EAEA;AAAA,IAAC,oBAAAA;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,OAAM;AAAA,MACN,IAAI;AAAA,QACF,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,cAAc;AAAA,MAChB;AAAA,MAEC,kBAAQ;AAAA;AAAA,EACX;AAAA,GACF;AASF,IAAM,WAAwE,CAAC;AAAA,EAC7E;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,MAAM,KAAK,IAAI,MAAM,MAAM,IAAI;AACvC,QAAM,QAAQ,MAAM;AACpB,QAAM,OAAO,QAAQE,YAAW,MAAM,GAAG,IAAI;AAC7C,QAAM,QAAQ,MAAM,SAAS,QAAQ,KAAK,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI;AACpE,QAAM,UAAU,QAAQ,SAAS,MAAM,MAAM,GAAG;AAQhD,QAAM,UAAU,MAAiB;AAC/B,QAAI,QAAS,QAAO;AACpB,QAAI,QAAQ,KAAK,UAAU;AACzB,aACE;AAAA,QAAC,oBAAAF;AAAA,QAAA;AAAA,UACC,WAAW;AAAA,UACX,IAAI;AAAA,UACJ,SAAQ;AAAA,UACR,IAAI;AAAA,YACF,UAAU;AAAA,YACV,OAAO;AAAA,YACP,gBAAgB;AAAA,YAChB,WAAW,EAAE,gBAAgB,YAAY;AAAA,UAC3C;AAAA,UACD;AAAA;AAAA,YACG;AAAA,YAAM;AAAA;AAAA;AAAA,MACV;AAAA,IAEJ;AACA,WAAO,OAAO,YAAY;AAAA,EAC5B;AAEA,QAAM,iBAAiB,QACnB,GAAG,IAAI,iBAAiB,KAAK,MAAM,MAAM,GAAG,CAAC,MAC7C,GAAG,IAAI;AAEX,SACE;AAAA,IAAC,aAAAC;AAAA,IAAA;AAAA,MACC,IAAI;AAAA,QACF,SAAS;AAAA,QACT,qBAAqB;AAAA,QACrB,YAAY;AAAA,QACZ,KAAK;AAAA,QACL,IAAI;AAAA,QACJ,UAAU;AAAA,MACZ;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,OAAO,OAAO;AAAA,YACrB;AAAA,YACA;AAAA,YACA,OAAO,QAAQ,GAAG,KAAK,MAAM,MAAM,GAAG,CAAC,MAAM;AAAA,YAC7C,WAAW;AAAA;AAAA,QACb;AAAA,QAEA,+CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,UAAU,EAAE,GAGrB;AAAA,wDAAC,OAAI,MAAM,SAAS,aAAa,SAAS,WAAW,OAAO,QAAY,gBAAK;AAAA,UAC5E,QACC,gFACE;AAAA;AAAA,cAAC,oBAAAD;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,OAAO,MAAM,WAAW,GAAG,MAAM,KAAK,SAAM,MAAM,QAAQ,KAAK,MAAM;AAAA,gBACrE,IAAI;AAAA,kBACF,SAAS;AAAA,kBACT,UAAU;AAAA,kBACV,YAAY;AAAA,kBACZ,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,cAAc;AAAA,kBACd,YAAY;AAAA,gBACd;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,YACA;AAAA,cAAC,oBAAAA;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,OAAO,UAAU,UAAU;AAAA,gBAC3B,IAAI;AAAA,kBACF,SAAS;AAAA,kBACT,UAAU;AAAA,kBACV,YAAY,UAAU,MAAM;AAAA,kBAC5B,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,cAAc;AAAA,kBACd,YAAY;AAAA,gBACd;AAAA,gBAEC,kBAAQ;AAAA;AAAA,YACX;AAAA,aACF,IAEA;AAAA,YAAC,oBAAAA;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,IAAI;AAAA,gBACF,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,YAAY;AAAA,cACd;AAAA,cAEC;AAAA;AAAA,UACH;AAAA,WAEJ;AAAA,QAEA,+CAAC,aAAAC,SAAA,EAAI,IAAI,EAAE,UAAU,GAAG,WAAW,QAAQ,GACzC;AAAA;AAAA,YAAC,oBAAAD;AAAA,YAAA;AAAA,cACC,OAAO,QAAQ,GAAG,OAAO,MAAM,KAAK,CAAC,OAAO,OAAO,MAAM,MAAM,CAAC,KAAK;AAAA,cACrE,IAAI;AAAA,gBACF,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,oBAAoB;AAAA,gBACpB,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,OAAO,QAAQ,SAAY;AAAA,cAC7B;AAAA,cAEG,wBAAc,KAAK;AAAA;AAAA,UACtB;AAAA,UACF;AAAA,YAAC,oBAAAA;AAAA,YAAA;AAAA,cACC,SAAQ;AAAA,cACR,OAAM;AAAA,cACN,IAAI;AAAA,gBACF,SAAS;AAAA,gBACT,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,cAChB;AAAA,cAEC,qBAAW,KAAK;AAAA;AAAA,UACnB;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAGA,SAAS,cAAc,OAA6B;AAClD,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,SAAS,GAAG,KAAK,MAAM,MAAM,GAAG,CAAC,MAAM,aAAa,KAAK;AACxE;AAGA,SAAS,WAAW,OAA6B;AAC/C,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,SAAS,oBAAoB,WAAW,KAAK;AAC5D;AAYA,IAAM,aAOD,CAAC,EAAE,MAAM,UAAU,SAAS,QAAQ,mBAAmB,OAAO,UAAU,MAAM;AACjF,QAAM,aAAa,MAAM;AACvB,QAAI,SAAS;AACX,aAAO,8CAAC,iBAAAG,SAAA,EAAS,SAAQ,eAAc,OAAM,QAAO,QAAO,QAAO;AAAA,IACpE;AACA,QAAI,KAAK,WAAW,GAAG;AACrB,aACE;AAAA,QAAC,aAAAF;AAAA,QAAA;AAAA,UACC,SAAQ;AAAA,UACR,gBAAe;AAAA,UACf,YAAW;AAAA,UACX,QAAO;AAAA,UACP,IAAI,YAAU,EAAE,OAAO,MAAM,QAAQ,KAAK,WAAW,UAAU,GAAG;AAAA,UACnE;AAAA;AAAA,MAED;AAAA,IAEJ;AACA,WACE,8CAAC,wCAAoB,OAAM,QAAO,QAAO,QACvC,yDAAC,8BAAU,MAAY,QAAQ,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE,GACpE;AAAA,oDAAC,0BAAM,SAAQ,QAAO,MAAI,MAAC;AAAA,MAC3B,8CAAC,4BAAQ,SAAS,8CAAC,gBAAa,gBAAgB,QAAQ,GAAI;AAAA,MAC3D,cAAc,UACb;AAAA,QAAC;AAAA;AAAA,UACC,GAAG;AAAA,UACH,QAAQ,OAAO;AAAA,UACf,iBAAgB;AAAA,UAChB,aAAa;AAAA;AAAA,MACf;AAAA,MAEF;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,MAAK;AAAA,UACL,QAAQ,OAAO;AAAA,UACf,aAAa;AAAA,UACb,MAAM,OAAO;AAAA,UACb,aAAa;AAAA,UACb,KAAK;AAAA,UACL,mBAAmB;AAAA;AAAA,MACrB;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,QAAM,WAAW,MAAM;AACrB,QAAI,QAAS,QAAO;AACpB,QAAI,iBAAkB,QAAO;AAC7B,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,WAAO,WAAW;AAAA,EACpB,GAAG;AAEH,SACE,+CAAC,aAAAA,SAAA,EAAI,MAAK,OAAM,cAAY,mBAAmB,IAAI,GAAG,IAAI,EAAE,UAAU,EAAE,GACtE;AAAA,kDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,QAAQ,OAAO,OAAO,GAAI,qBAAW,GAAE;AAAA,IAClD;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,IAAI;AAAA,UACF,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,gBAAgB;AAAA,UAChB,KAAK;AAAA,UACL,IAAI;AAAA,UACJ,UAAU;AAAA,QACZ;AAAA,QAEA;AAAA,yDAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,YAAY,KAAK,MAAM,UAAU,EAAE,GACzE;AAAA,0DAAC,OAAI,yBAAW;AAAA,YAChB;AAAA,cAAC,oBAAAD;AAAA,cAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,OAAM;AAAA,gBACN,IAAI,EAAE,UAAU,MAAM,UAAU,UAAU,cAAc,YAAY,YAAY,SAAS;AAAA,gBAExF;AAAA;AAAA,YACH;AAAA,aACF;AAAA,UACA;AAAA,YAAC,oBAAAA;AAAA,YAAA;AAAA,cACC,OAAO,WAAW,mBAAmB,SAAY,GAAG,OAAO,QAAQ,CAAC;AAAA,cACpE,IAAI;AAAA,gBACF,UAAU;AAAA,gBACV,YAAY;AAAA,gBACZ,oBAAoB;AAAA,gBACpB,YAAY;AAAA,cACd;AAAA,cAEC,qBAAW,mBAAmB,WAAM,OAAO,QAAQ;AAAA;AAAA,UACtD;AAAA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;AAGA,SAAS,UAAU,SAAkB,aAAsB,OAAuB;AAChF,MAAI,QAAS,QAAO;AACpB,MAAI,YAAa,QAAO;AACxB,SAAO;AACT;AAGA,SAAS,SAAS,SAAkB,aAAsB,MAAmC;AAC3F,MAAI,QAAS,QAAO;AACpB,MAAI,YAAa,QAAO;AACxB,SAAO;AACT;AAEO,IAAM,sBAAoD,CAAC;AAAA,EAChE,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP,MAAM;AACR,MAAM;AACJ,QAAM,UAAM,gCAAO,aAAa;AAChC,QAAM,YAAQ,0BAAS;AACvB,QAAM,oBAAgB,qBAAAI,SAAc,MAAM,YAAY,KAAK,IAAI,CAAC;AAChE,QAAM,YAAY,gBAAgB,KAAK,IAAI,IAAI,IAAI,IAAI;AACvD,QAAM,uBAAmB,sBAAM;AAC/B,QAAM,qBAAiB,yCAAY,YAAY;AAC/C,QAAM,aAAa,kBAAkB,iBAAiB;AACtD,QAAM,EAAE,UAAU,cAAc,OAAO,WAAW,MAAM,UAAU,SAAS,gBAAgB,OAAO,aAAa,IAAI,kBAAkB;AACrI,QAAM,CAAC,cAAc,eAAe,QAAI,yBAAS,IAAI;AACrD,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAwB,IAAI;AAChE,QAAM,CAAC,YAAY,aAAa,QAAI,yBAAuB,CAAC,CAAC;AAC7D,QAAM,CAAC,UAAU,WAAW,QAAI,yBAAS,CAAC;AAG1C,QAAM,OAAO,iBAAiB,SAAY,eAAe;AACzD,QAAM,QAAQ,cAAc,SAAY,YAAY;AACpD,QAAM,OAAO,aAAa,SAAY,WAAW;AAGjD,QAAM,UAAU,iBAAiB,SAAY,iBAAiB;AAC9D,QAAM,QAAQ,iBAAiB,SAAY,eAAe;AAE1D,QAAM,eAAe,aAAa;AAClC,QAAM,CAAC,sBAAsB,uBAAuB,QAAI,yBAAS,eAAe;AAChF,QAAM,aAAa,eAAe,WAAY;AAE9C,QAAM,qBAAiB,4BAAY,MAAM;AACvC,UAAM,OAAO,CAAC;AACd,QAAI,CAAC,aAAc,yBAAwB,IAAI;AAC/C,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,cAAc,YAAY,gBAAgB,CAAC;AAE/C,QAAM,cAAc,aAAa,aAAa,GAAG,UAAU,cAAc;AAEzE,gCAAU,MAAM;AACd,QAAI,YAAY;AAChB,oBAAgB,IAAI;AACpB,kBAAc,IAAI;AAElB,UAAM,EAAE,WAAW,QAAQ,IAAI,iBAAiB;AAChD,QAAI,SAAS,WAAW,OAAO,EAC5B,KAAK,CAAC,gBAAgB;AACrB,UAAI,UAAW;AAGf,YAAM,QAAQ,YAAY,eAAe,CAAC;AAC1C;AAAA,QACE,MAAM,IAAI,QAAM;AAAA,UACd,MAAM,EAAE;AAAA,UACR,OAAO,EAAE,SAAS;AAAA,QACpB,EAAE;AAAA,MACJ;AACA,kBAAY,YAAY,eAAe,CAAC;AACxC,sBAAgB,KAAK;AAAA,IACvB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,UAAI,CAAC,WAAW;AACd,sBAAc,KAAK,WAAW,2BAA2B;AACzD,sBAAc,CAAC,CAAC;AAChB,oBAAY,CAAC;AACb,wBAAgB,KAAK;AAAA,MACvB;AAAA,IACF,CAAC;AACH,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAIR,QAAM,cAAU;AAAA,IACd,MAAM,mBAAmB,MAAM,OAAO,MAAM,KAAK,MAAM;AAAA,IACvD,CAAC,MAAM,OAAO,IAAI;AAAA,EACpB;AACA,QAAM,aAAS,wBAAQ,MAAM,kBAAkB,OAAO,GAAG,CAAC,OAAO,CAAC;AAClE,QAAM,eAAW,wBAAQ,MAAM,eAAe,OAAO,GAAG,CAAC,OAAO,CAAC;AAIjE,QAAM,sBAAkB;AAAA,IACtB,MAAM,mBAAmB,MAAM,OAAO,MAAM,eAAe;AAAA,IAC3D,CAAC,MAAM,OAAO,MAAM,eAAe;AAAA,EACrC;AACA,QAAM,qBAAiB;AAAA,IACrB,MAAM,gBAAgB,eAAe;AAAA,IACrC,CAAC,eAAe;AAAA,EAClB;AAGA,QAAM,gBAAY;AAAA,IAChB,MAAM,gBAAgB;AAAA,MACpB;AAAA,MACA,OAAO;AAAA,MACP,UAAU;AAAA,MACV;AAAA,MACA,UAAU,MAAM,UAAU,KAAK;AAAA,IACjC,CAAC;AAAA,IACD,CAAC,SAAS,cAAc,MAAM,YAAY,IAAI;AAAA,EAChD;AAIA,QAAM,QAAQ,oBAAI,KAAK;AACvB,QAAM,aAAa,WAAW,YAAY,KAAK;AAC/C,QAAM,YAAY,IAAI,KAAK,KAAK;AAChC,YAAU,QAAQ,UAAU,QAAQ,IAAI,CAAC;AAGzC,QAAM,iBAAiB,WAAW,KAAK,OAAK,EAAE,SAAS,WAAW,SAAS,CAAC,IACxE,WAAW,YAAY,SAAS,IAChC;AACJ,QAAM,YAAY,mBAAmB,OAAO,SAAY,MAAM,OAAO,cAAc,CAAC;AAEpF,QAAM,cACJ,SAAS,UAAU,IACf,oBACA,GAAG,SAAS,KAAK,SAAS,SAAS,UAAU,IAAI,KAAK,GAAG;AAE/D,QAAM,mBAAe,wBAAqD,MAAM;AAC9E,WAAO,YAAY;AAAA,MACjB;AAAA,MACA,UAAU,MAAM,UAAU,KAAK;AAAA,MAC/B;AAAA,MACA,YAAY,SAAS;AAAA,IACvB,CAAC;AAAA,EACH,GAAG,CAAC,MAAM,MAAM,QAAQ,WAAW,SAAS,KAAK,CAAC;AAElD,QAAM,YAAY,CAAC,KAA8C,UAAkB;AACjF,UAAM,QAAQ,IAAI,SAAS,WAAW,IAAI,IAAI;AAC9C,UAAM,MAAM,GAAG,IAAI,IAAI,IAAI,KAAK;AAChC,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AAIH,YAAI,CAAC,eAAe,CAAC,WAAY,QAAO;AACxC,eAAO,cACL,8CAAC,qBAA4B,MAAK,SAAQ,OAAc,SAAS,eAAzC,GAAsD,IAE9E,8CAAC,qBAA4B,MAAK,SAAQ,OAAc,IAAI,GAAG,UAAU,iBAAjD,GAAgE;AAAA,MAE5F,KAAK;AAEH,YAAI,CAAC,WAAY,QAAO;AACxB,eACE,8CAAC,eAAAC,SAAA,EAAiB,MAAK,SAAQ,SAAQ,QAAO,WAAW,8BAAM,IAAI,YAChE,mBADU,GAEb;AAAA,MAEJ,KAAK;AACH,eACE;AAAA,UAAC,eAAAA;AAAA,UAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,SAAS;AAAA,YACT,iBAAe;AAAA,YACf,iBAAe;AAAA,YACf,SACE;AAAA,cAAC;AAAA;AAAA,gBACC,IAAI,eAAa;AAAA,kBACf,WAAW,aAAa,mBAAmB;AAAA,kBAC3C,YAAY,SAAS,YAAY,OAAO,WAAW;AAAA,gBACrD;AAAA;AAAA,YACF;AAAA,YAGD;AAAA;AAAA,UAfI;AAAA,QAgBP;AAAA;AAAA,MAGJ;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAEA,QAAM,YAAY,aAAa,SAAS,KAAK,CAAC,CAAC;AAE/C,QAAM,UAAuB,OAAO,aAAAJ,UAAM,eAAAK;AAE1C,SACE,+CAAC,WAAQ,IAAI,OAAO,EAAE,QAAQ,OAAO,IAAI,EAAE,GAAG,GAAG,QAAQ,OAAO,GAC9D;AAAA,mDAAC,aAAAL,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,GAAG,IAAI,KAAK,UAAU,GAAG,gBAAgB,OAAO,aAAa,OAAU,GAC3H;AAAA,OAAC,QACA,8CAAC,oBAAAD,SAAA,EAAW,SAAQ,MAAK,YAAY,KAAK,IAAI,EAAE,UAAU,GAAG,MAAM,EAAE,GAClE,iBACH;AAAA,MAED,CAAC,WAAW,CAAC,SACZ;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,MAAME,YAAW,SAAS,SAAS,OAAO,CAAC;AAAA,UAC3C,KAAK,SAAS,QAAQ;AAAA;AAAA,MACxB;AAAA,OAEJ;AAAA,IAEC,UAAU,SAAS,aAClB,8CAAC,aAAAD,SAAA,EAAI,IAAI,EAAE,SAAS,QAAQ,eAAe,UAAU,KAAK,MAAM,WAAW,KAAK,GAC7E,WAAC,GAAG,GAAG,CAAC,EAAE,IAAI,OACb,+CAAC,aAAAA,SAAA,EAAY,IAAI,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,KAAK,GAClE;AAAA,oDAAC,iBAAAE,SAAA,EAAS,SAAQ,YAAW,OAAO,MAAM,QAAQ,MAAM;AAAA,MACxD,+CAAC,aAAAF,SAAA,EAAI,IAAI,EAAE,MAAM,EAAE,GACjB;AAAA,sDAAC,iBAAAE,SAAA,EAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI,IAAI,EAAE,IAAI,KAAK,GAAG;AAAA,QACnE,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI;AAAA,SACnD;AAAA,MACA,8CAAC,iBAAAA,SAAA,EAAS,SAAQ,QAAO,OAAO,IAAI,QAAQ,IAAI;AAAA,SANxC,CAOV,CACD,GACH;AAAA,IAGD,UAAU,SAAS,WAClB,8CAAC,oBAAAH,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,IAAI,GAC9D,oBAAU,SACb;AAAA,IAGD,UAAU,SAAS,mBAClB,8CAAC,oBAAAA,SAAA,EAAW,SAAQ,SAAQ,OAAM,kBAAiB,IAAI,EAAE,IAAI,IAAI,GAC9D,6BACH;AAAA,IAGD,UAAU,SAAS,WAClB,gFAEE;AAAA;AAAA,QAAC,aAAAC;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,YACF,SAAS;AAAA,YACT,YAAY;AAAA,YACZ,KAAK;AAAA,YACL,IAAI;AAAA,YACJ,UAAU;AAAA,UACZ;AAAA,UAEA;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,MAAK;AAAA,gBACL,OAAO,UAAU,cAAc,UAAU,kBAAkB,OAAO,UAAU,CAAC;AAAA,gBAC7E,MAAM,SAAS,cAAc,UAAU,kBAAkB,SAAS;AAAA,gBAClE,OAAO,gBAAgB,UAAU,mBAAmB,SAAY;AAAA;AAAA,YAClE;AAAA,YACA,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,OAAO,OAAO,SAAS,WAAW,YAAY,EAAE,GAAG;AAAA,YAC9D;AAAA,cAAC;AAAA;AAAA,gBACC,OAAM;AAAA,gBACN,OAAO,UAAU,cAAc,UAAU,kBAAkB,OAAO,QAAQ,CAAC;AAAA,gBAC3E,MAAM,SAAS,cAAc,UAAU,kBAAkB,WAAW,CAAC;AAAA,gBACrE,OAAO,gBAAgB,UAAU,mBAAmB,SAAY;AAAA;AAAA,YAClE;AAAA;AAAA;AAAA,MACF;AAAA,MAGA,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,WAAW,aAAa,aAAa,UAAU,GACvD,iBAAO,IAAI,CAAC,OAAO,MAClB;AAAA,QAAC,aAAAA;AAAA,QAAA;AAAA,UAEC,IAAI,MAAM,IAAI,SAAY,EAAE,WAAW,aAAa,aAAa,UAAU;AAAA,UAE3E,wDAAC,YAAS,OAAc,MAAM,WAAW,UAAU,aAAa;AAAA;AAAA,QAH3D,MAAM;AAAA,MAIb,CACD,GACH;AAAA,MAEA,8CAAC,aAAAA,SAAA,EAAI,IAAI,EAAE,IAAI,KAAK,GAClB;AAAA,QAAC;AAAA;AAAA,UACC,MAAM;AAAA,UACN;AAAA,UACA,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,kBAAkB,UAAU;AAAA,UAC5B,WAAW,MAAM,cAAc;AAAA;AAAA,MACjC,GACF;AAAA,MAEA,8CAAC,iBAAAM,SAAA,EAAS,IAAI,YAAY,eAAa,MACrC;AAAA,QAAC,aAAAN;AAAA,QAAA;AAAA,UACC,IAAI;AAAA,UACJ,IAAI;AAAA,YACF,IAAI;AAAA;AAAA;AAAA,YAGJ,WAAW;AAAA,YACX,WAAW;AAAA,UACb;AAAA,UAEA,wDAAC,kBACC;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,cACR,gBAAgB,gBAAgB;AAAA,cAChC,UAAU;AAAA;AAAA,UACZ,GACF;AAAA;AAAA,MACF,GACF;AAAA,OACF;AAAA,IAGD,aACC;AAAA,MAAC,aAAAA;AAAA,MAAA;AAAA,QACC,IAAI,eAAa;AAAA,UACf,IAAI;AAAA,UACJ,IAAI;AAAA,UACJ,WAAW,aAAa,SAAS,QAAQ,OAAO;AAAA,UAChD,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,UAAU;AAAA,QACZ;AAAA,QAEC;AAAA,uBAAa,IAAI,SAAS;AAAA,UAC1B;AAAA;AAAA;AAAA,IACH;AAAA,KAEJ;AAEJ;;;AJ10BA;AAEA;AAEA;AACA;AACA,IAAAO,0CAMO;",
|
|
6
|
+
"names": ["import_frontend_plugin_api", "Paper", "Typography", "Box", "import_Box", "import_styles", "import_jsx_runtime", "Box", "Box", "ButtonBase", "import_Box", "import_Paper", "import_Typography", "import_styles", "import_jsx_runtime", "Paper", "Typography", "import_Box", "import_styles", "import_jsx_runtime", "Box", "import_Box", "import_Typography", "import_styles", "import_jsx_runtime", "Box", "Typography", "import_jsx_runtime", "Button", "import_Box", "import_Typography", "import_Paper", "import_ButtonBase", "import_styles", "import_jsx_runtime", "Box", "Typography", "ButtonBase", "Paper", "Skeleton", "Divider", "import_react", "import_core_plugin_api", "import_react", "import_core_plugin_api", "Typography", "CircularProgress", "Box", "import_react", "import_Button", "import_Box", "import_Typography", "import_Skeleton", "import_styles", "import_icons_material", "import_jsx_runtime", "TableRow", "TableCell", "Skeleton", "Tooltip", "IconButton", "TextField", "InputAdornment", "Button", "Chip", "TableContainer", "Table", "TableHead", "TableSortLabel", "TableBody", "Dialog", "DialogTitle", "DialogContent", "DialogActions", "import_backstage_plugin_litellm_common", "import_react", "import_Box", "import_Typography", "import_IconButton", "import_Tooltip", "import_icons_material", "import_jsx_runtime", "Box", "Tabs", "Tab", "Typography", "Tooltip", "IconButton", "import_react", "import_Box", "import_Typography", "import_Dialog", "import_DialogTitle", "import_DialogContent", "import_DialogActions", "import_TextField", "import_Button", "import_IconButton", "import_CircularProgress", "import_Tooltip", "import_InputAdornment", "import_Chip", "import_icons_material", "import_plugin_permission_react", "import_backstage_plugin_litellm_common", "import_jsx_runtime", "Box", "Chip", "Typography", "Autocomplete", "TextField", "Button", "CircularProgress", "Dialog", "DialogTitle", "DialogContent", "Alert", "Tooltip", "IconButton", "FormControlLabel", "Checkbox", "InputAdornment", "MenuItem", "Accordion", "AccordionSummary", "AccordionDetails", "DialogActions", "import_react", "import_Dialog", "import_DialogTitle", "import_DialogContent", "import_DialogActions", "import_TextField", "import_Button", "import_Alert", "import_Checkbox", "import_FormControlLabel", "import_Autocomplete", "import_CircularProgress", "import_MenuItem", "import_Box", "import_Divider", "import_Typography", "import_IconButton", "import_Tooltip", "import_Paper", "import_Table", "import_TableBody", "import_TableCell", "import_TableContainer", "import_TableHead", "import_TableRow", "import_icons_material", "import_core_plugin_api", "import_jsx_runtime", "Dialog", "DialogTitle", "DialogContent", "Alert", "Box", "Typography", "TextField", "Autocomplete", "MenuItem", "FormControlLabel", "Checkbox", "TableContainer", "Paper", "Table", "TableHead", "TableRow", "TableCell", "TableBody", "Tooltip", "IconButton", "DeleteIcon", "CircularProgress", "Button", "Divider", "DialogActions", "budgetTone", "resetLabel", "import_backstage_plugin_litellm_common", "import_react", "import_Paper", "import_Box", "import_Typography", "import_TextField", "import_MenuItem", "import_Alert", "import_Button", "import_Table", "import_TableBody", "import_TableCell", "import_TableContainer", "import_TableHead", "import_TableRow", "import_Skeleton", "import_jsx_runtime", "Skeleton", "Typography", "Box", "TableRow", "TableCell", "TextField", "MenuItem", "Alert", "Button", "Grid", "TableContainer", "Paper", "Table", "TableHead", "TableBody", "import_Box", "import_Paper", "import_Typography", "import_styles", "import_core_components", "import_jsx_runtime", "budgetTone", "Paper", "Box", "Typography", "import_react", "import_frontend_plugin_api", "import_Paper", "import_Box", "import_Typography", "import_Skeleton", "import_IconButton", "import_icons_material", "import_styles", "import_jsx_runtime", "Box", "Typography", "Paper", "Skeleton", "budgetTone", "IconButton", "Collapse", "budgetTone", "import_react", "import_Paper", "import_Box", "import_Typography", "import_Skeleton", "import_Divider", "import_Table", "import_TableBody", "import_TableCell", "import_TableHead", "import_TableRow", "import_TableContainer", "import_Collapse", "import_IconButton", "import_Button", "import_CircularProgress", "import_styles", "import_Tooltip", "import_icons_material", "import_recharts", "import_jsx_runtime", "Box", "CircularProgress", "Typography", "Paper", "Button", "MuiTooltip", "IconButton", "Collapse", "Divider", "TableContainer", "Table", "TableHead", "TableRow", "TableCell", "TableBody", "Skeleton", "isModelAllowedByTeam", "import_react", "import_Box", "import_Table", "import_TableBody", "import_TableCell", "import_TableContainer", "import_TableHead", "import_TableRow", "import_TableSortLabel", "import_Typography", "import_MenuItem", "import_TextField", "import_InputAdornment", "import_icons_material", "import_Tooltip", "import_Alert", "import_styles", "import_jsx_runtime", "Box", "FormControl", "InputLabel", "Select", "MenuItem", "TextField", "InputAdornment", "TableContainer", "Table", "TableHead", "TableRow", "TableCell", "TableSortLabel", "TableBody", "Tooltip", "ContentCopyIcon", "Typography", "Snackbar", "Alert", "TableRow", "TableCell", "Skeleton", "import_react", "import_Box", "import_Typography", "import_Table", "import_TableBody", "import_TableCell", "import_TableContainer", "import_TableHead", "import_TableRow", "import_TextField", "import_MenuItem", "import_Skeleton", "import_Collapse", "import_IconButton", "import_Alert", "import_styles", "import_icons_material", "import_jsx_runtime", "IconButton", "Typography", "Collapse", "Box", "TextField", "MenuItem", "Alert", "TableContainer", "Table", "TableHead", "TableBody", "TablePagination", "PERIOD_LS_KEY", "import_react", "import_Box", "import_Alert", "import_Button", "import_Typography", "import_Tabs", "import_Tab", "import_Grid", "import_Accordion", "import_AccordionSummary", "import_AccordionDetails", "import_react_use", "import_core_plugin_api", "import_core_components", "import_plugin_permission_react", "import_backstage_plugin_litellm_common", "import_jsx_runtime", "alert", "Box", "Typography", "Accordion", "AccordionSummary", "ExpandMoreIcon", "AccordionDetails", "Tabs", "Tab", "Button", "Grid", "Alert", "import_icons_material", "import_frontend_plugin_api", "import_jsx_runtime", "TrendingUpIcon", "LiteLLMPage", "import_react", "import_Paper", "import_Box", "import_Typography", "import_FormControl", "import_Select", "import_MenuItem", "import_Skeleton", "import_recharts", "import_core_plugin_api", "import_frontend_plugin_api", "import_core_components", "import_jsx_runtime", "start", "end", "startDate", "endDate", "Box", "Paper", "Typography", "FormControl", "Select", "MenuItem", "Skeleton", "import_react", "import_frontend_plugin_api", "import_Paper", "import_Box", "import_Button", "import_Typography", "import_Skeleton", "import_Collapse", "import_styles", "import_icons_material", "import_recharts", "import_core_plugin_api", "import_core_components", "import_jsx_runtime", "window", "Typography", "Box", "budgetTone", "Skeleton", "useMediaQuery", "Button", "Paper", "Collapse", "import_backstage_plugin_litellm_common"]
|
|
7
7
|
}
|