3d77f2846d
The old Repairs module had grown ticketing-system features (status lifecycle, comments, assignee, notes) that duplicate what the external ticketing tool already owns. Vector only needs to track whether maintenance is open or closed. - Rename RepairJob -> Fm (OPEN/CLOSED only), drop RepairComment, assignee, notes - New Repair table: persistent log of physical part swaps, with ingest on unknown broken MPN via partModels.upsertByMpn - New custody model: PENDING_DROP_IN_CUSTODY / PENDING_DESTRUCTION_IN_CUSTODY states + Part.custodianId, with a "My Custody" page for drop-off - PartModel.destroyOnFail routes broken parts to the destruction path - Host lookup on /fms and /repairs accepts hostId XOR assetId - Wire the dormant webhook emitter: fm.opened, fm.closed, repair.logged - Single fresh Prisma migration (dev DB was wiped, no backfill) Tests: 60 passing (custody transitions in parts.test.ts; new fms.test.ts, repairs.test.ts, custody.test.ts covering happy paths, validation failures, webhook emissions, and ingest-on-unknown-MPN). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
99 lines
3.6 KiB
TypeScript
99 lines
3.6 KiB
TypeScript
// Hierarchical query keys for TanStack Query. Consumers should import this factory rather than
|
|
// hard-coding tuples inline so invalidations can be surgical (e.g. invalidate everything under
|
|
// `parts.list()` without touching `parts.detail(id)`).
|
|
|
|
export const queryKeys = {
|
|
auth: {
|
|
all: ['auth'] as const,
|
|
me: () => [...queryKeys.auth.all, 'me'] as const,
|
|
},
|
|
parts: {
|
|
all: ['parts'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.parts.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.parts.all, 'detail', id] as const,
|
|
events: (id: string, filters?: Record<string, unknown>) =>
|
|
[...queryKeys.parts.all, 'events', id, filters ?? {}] as const,
|
|
},
|
|
manufacturers: {
|
|
all: ['manufacturers'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.manufacturers.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.manufacturers.all, 'detail', id] as const,
|
|
},
|
|
sites: {
|
|
all: ['sites'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.sites.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.sites.all, 'detail', id] as const,
|
|
},
|
|
rooms: {
|
|
all: ['rooms'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.rooms.all, 'list', filters ?? {}] as const,
|
|
},
|
|
bins: {
|
|
all: ['bins'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.bins.all, 'list', filters ?? {}] as const,
|
|
},
|
|
users: {
|
|
all: ['users'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.users.all, 'list', filters ?? {}] as const,
|
|
},
|
|
hosts: {
|
|
all: ['hosts'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.hosts.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.hosts.all, 'detail', id] as const,
|
|
deployedParts: (id: string) => [...queryKeys.hosts.all, 'deployed-parts', id] as const,
|
|
},
|
|
fms: {
|
|
all: ['fms'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.fms.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.fms.all, 'detail', id] as const,
|
|
},
|
|
repairs: {
|
|
all: ['repairs'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.repairs.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.repairs.all, 'detail', id] as const,
|
|
},
|
|
custody: {
|
|
all: ['custody'] as const,
|
|
mine: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.custody.all, 'mine', filters ?? {}] as const,
|
|
},
|
|
partModels: {
|
|
all: ['part-models'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.partModels.all, 'list', filters ?? {}] as const,
|
|
detail: (id: string) => [...queryKeys.partModels.all, 'detail', id] as const,
|
|
},
|
|
tags: {
|
|
all: ['tags'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.tags.all, 'list', filters ?? {}] as const,
|
|
},
|
|
categories: {
|
|
all: ['categories'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.categories.all, 'list', filters ?? {}] as const,
|
|
},
|
|
webhooks: {
|
|
all: ['webhooks'] as const,
|
|
list: (filters?: Record<string, unknown>) =>
|
|
[...queryKeys.webhooks.all, 'list', filters ?? {}] as const,
|
|
},
|
|
savedViews: {
|
|
all: ['savedViews'] as const,
|
|
list: (resource: string) => [...queryKeys.savedViews.all, resource] as const,
|
|
},
|
|
analytics: {
|
|
all: ['analytics'] as const,
|
|
dashboard: () => [...queryKeys.analytics.all, 'dashboard'] as const,
|
|
},
|
|
} as const;
|