import { provisioningStates, type ProvisioningAction } from './provisioning.js'; import type { ProvisioningDeployment } from './provisioning-detail.js'; import type { ProvisioningSource } from './provisioning-detail.js'; export const provisioningListStatuses = [ ...provisioningStates, // Retain the combined filter for existing links and API clients. 'pending', 'attention' ] as const; export const provisioningListSources = [ 'manual', 'campaign', 'beta', 'maintenance', 'recovery', 'autoscaling', 'rebalance', 'system' ] as const; export type ProvisioningListSource = (typeof provisioningListSources)[number]; export const provisioningSourceLabels: Record = { manual: 'Manual', campaign: 'Campaign', beta: 'Beta', maintenance: 'Maintenance', recovery: 'Recovery', autoscaling: 'Autoscaling', rebalance: 'Rebalance', system: 'System' }; export const provisioningSourceKinds = { campaign: ['campaign'], beta: ['beta'], maintenance: ['maintenance'], recovery: ['watchdog'], autoscaling: ['autoscaling'], rebalance: ['rebalance'] } as const satisfies Record< Exclude, readonly ProvisioningSource['kind'][] >; /** Record titles and incident summaries belong in expanded details, not the source column. */ export function provisioningSourceLabel( row: Pick ): string { const kind = row.sources?.[0]?.kind; return provisioningSourceLabels[ kind === 'watchdog' ? 'recovery' : (kind ?? (row.triggered_by === 'ui' ? 'manual' : 'system')) ]; } export function provisioningMatchesSource( row: Pick, source: ProvisioningListSource ): boolean { const sources = row.sources ?? []; if (source === 'manual' || source === 'system') return ( !sources.length && (source === 'manual' ? row.triggered_by === 'ui' : row.triggered_by !== 'ui') ); const kinds: readonly ProvisioningSource['kind'][] = provisioningSourceKinds[source]; return sources.some((item) => kinds.includes(item.kind)); } export type ProvisioningListRow = Pick< ProvisioningDeployment, | 'id' | 'server' | 'server_deleted_at' | 'action' | 'state' | 'stage' | 'started_at' | 'finished_at' | 'triggered_by' | 'requested_by' | 'error' | 'warnings' | 'server_exists' > & { canCancelRemoval: number; canCancel?: number; sources?: ProvisioningSource[]; phase?: string | null; phaseStartedAt?: string | null; waitCode?: string | null; waitMessage?: string | null; }; export interface ProvisioningListOptions { view?: 'active' | 'history' | 'all'; action?: ProvisioningAction; status?: (typeof provisioningListStatuses)[number]; source?: ProvisioningListSource; server?: string; limit?: number; offset?: number; } export interface ProvisioningListPage { deployments: ProvisioningListRow[]; total: number; needsReview: number; limit: number; offset: number; } export function provisioningPageSize(value: number): number { return Number.isFinite(value) ? Math.min(100, Math.max(1, Math.floor(value) || 25)) : 25; } export function provisioningPageOffset(value: number): number { return Number.isFinite(value) ? Math.min(1_000_000, Math.max(0, Math.floor(value))) : 0; }