feat(part-models): detail page with fleet insights
Adds /part-models/:id mirroring host/part detail pattern: KPIs for units, spend, avg price, failure counts, and FMs implicating the model, a state-breakdown bar chart, and the parts-of-this-model table. New GET /part-models/:id/insights aggregates via part.groupBy + aggregate and repair/fm counts. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
CreatePartModelRequest,
|
||||
PartModelInsights,
|
||||
UpdatePartModelRequest,
|
||||
} from '@vector/shared';
|
||||
import { api } from './client.js';
|
||||
@@ -40,3 +41,8 @@ export async function updatePartModel(
|
||||
export async function deletePartModel(id: string): Promise<void> {
|
||||
await api.delete(`/part-models/${id}`);
|
||||
}
|
||||
|
||||
export async function getPartModelInsights(id: string): Promise<PartModelInsights> {
|
||||
const res = await api.get<PartModelInsights>(`/part-models/${id}/insights`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ export type PartListFilters = {
|
||||
state?: string;
|
||||
manufacturerId?: string;
|
||||
categoryId?: string;
|
||||
partModelId?: string;
|
||||
binId?: string;
|
||||
tagId?: string;
|
||||
eolOnly?: boolean;
|
||||
|
||||
@@ -73,6 +73,7 @@ export const queryKeys = {
|
||||
list: (filters?: Record<string, unknown>) =>
|
||||
[...queryKeys.partModels.all, 'list', filters ?? {}] as const,
|
||||
detail: (id: string) => [...queryKeys.partModels.all, 'detail', id] as const,
|
||||
insights: (id: string) => [...queryKeys.partModels.all, 'insights', id] as const,
|
||||
},
|
||||
tags: {
|
||||
all: ['tags'] as const,
|
||||
|
||||
Reference in New Issue
Block a user