feat: host detail page + FM host context
Add /hosts/:id detail page with unified timeline (HostEvents + FMs + Repairs + part arrivals/departures) and a deployed-parts table. Hosts list rows now link to the page. FM list + detail surface inline State/Stack badges next to the asset ID, with the asset ID linking to the host page. HostEvent audit model added; create/update in the hosts service now diff and log state, stack, and field changes the same way parts.ts does. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "HostEvent" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"hostId" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"type" TEXT NOT NULL,
|
||||
"field" TEXT,
|
||||
"oldValue" TEXT,
|
||||
"newValue" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "HostEvent_hostId_fkey" FOREIGN KEY ("hostId") REFERENCES "Host" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "HostEvent_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "HostEvent_hostId_createdAt_idx" ON "HostEvent"("hostId", "createdAt" DESC);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "HostEvent_userId_idx" ON "HostEvent"("userId");
|
||||
@@ -24,6 +24,7 @@ model User {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
partEvents PartEvent[]
|
||||
hostEvents HostEvent[]
|
||||
refreshTokens RefreshToken[]
|
||||
custodyParts Part[] @relation("Custody")
|
||||
repairs Repair[]
|
||||
@@ -198,11 +199,28 @@ model Host {
|
||||
parts Part[]
|
||||
fms Fm[]
|
||||
repairs Repair[]
|
||||
events HostEvent[]
|
||||
|
||||
@@index([state])
|
||||
@@index([stack])
|
||||
}
|
||||
|
||||
model HostEvent {
|
||||
id String @id @default(uuid())
|
||||
hostId String
|
||||
host Host @relation(fields: [hostId], references: [id], onDelete: Cascade)
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
type String
|
||||
field String?
|
||||
oldValue String?
|
||||
newValue String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([hostId, createdAt(sort: Desc)])
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Fm {
|
||||
id String @id @default(uuid())
|
||||
hostId String
|
||||
|
||||
@@ -33,6 +33,14 @@ export const PartEventType = z.enum([
|
||||
]);
|
||||
export type PartEventType = z.infer<typeof PartEventType>;
|
||||
|
||||
export const HostEventType = z.enum([
|
||||
'CREATED',
|
||||
'STATE_CHANGED',
|
||||
'STACK_CHANGED',
|
||||
'FIELD_UPDATED',
|
||||
]);
|
||||
export type HostEventType = z.infer<typeof HostEventType>;
|
||||
|
||||
export const FmStatus = z.enum(['OPEN', 'CLOSED']);
|
||||
export type FmStatus = z.infer<typeof FmStatus>;
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { z } from 'zod';
|
||||
import { PaginationQuery } from './pagination.js';
|
||||
|
||||
export const HostTimelineQuery = PaginationQuery;
|
||||
export type HostTimelineQuery = z.infer<typeof HostTimelineQuery>;
|
||||
@@ -8,6 +8,7 @@ export * from './parts.js';
|
||||
export * from './env.js';
|
||||
export * from './pagination.js';
|
||||
export * from './hosts.js';
|
||||
export * from './host-events.js';
|
||||
export * from './fms.js';
|
||||
export * from './repairs.js';
|
||||
export * from './custody.js';
|
||||
|
||||
Reference in New Issue
Block a user