Files
leocrm/frontend/src/api/dashboards.ts
T
Agent Zero 26948fdb51 feat(M3): Dashboard-Builder — Edit-Modus, Drag&Drop, Palette, Tabs (#361)
- DashboardBuilder: @dnd-kit 12-Spalten-Flow-Grid (seed-konsistent), View/Edit-Schalter, Resize, Tab-Verwaltung, Dashboard-CRUD + Set-Default, Dirty-Save
- MiniAppHost ersetzt DashboardWidgetLoader (lazy Registry + settings-Props); Palette nur renderbare Apps (component-Filter)
- WidgetSettingsForm generisch aus settings_schema; Bestands-Widgets settings-fähig (RecentContacts: limit)
- api/miniapps.ts + api/dashboards.ts (TanStack-Query-Hooks, documents.ts-Muster)
- Dashboard.tsx = Builder-Host (StatCards/SystemMetrics bleiben bis M4); Legacy-Grid/Loader gelöscht, Geister-Test ersetzt
- Tests: Builder 13/13, Page 11/11, i18n de/en, tsc clean, build OK
2026-08-30 21:28:40 +02:00

98 lines
2.5 KiB
TypeScript

/**
* Personal dashboards API hooks (Phase M2/M3).
*
* Layout shape (validated server-side, DashboardLayout):
* { version: 1, tabs: [{ id, name, widgets: [{ app_id, settings, col, row, col_span, row_span }] }] }
*/
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import { apiGet, apiPost, apiPut, apiDelete } from './client';
export interface DashboardWidget {
app_id: string;
settings: Record<string, unknown>;
col: number;
row: number;
col_span: number;
row_span: number;
}
export interface DashboardTab {
id: string;
name: string;
widgets: DashboardWidget[];
}
export interface DashboardLayout {
version: number;
tabs: DashboardTab[];
}
export interface Dashboard {
id: string;
name: string;
layout: DashboardLayout;
is_default: boolean;
user_id: string;
created_at: string | null;
updated_at: string | null;
}
export interface DashboardInput {
name: string;
}
export interface DashboardUpdateInput {
name?: string;
layout?: DashboardLayout;
}
export const DASHBOARD_QUERY_KEYS = {
all: ['dashboards'] as const,
one: (id: string) => ['dashboards', id] as const,
};
export function useDashboards() {
return useQuery({
queryKey: DASHBOARD_QUERY_KEYS.all,
queryFn: () => apiGet<Dashboard[]>('/dashboards'),
staleTime: 30 * 1000,
});
}
export function useCreateDashboard() {
const qc = useQueryClient();
return useMutation({
mutationFn: (input: DashboardInput) => apiPost<Dashboard>('/dashboards', input),
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
});
}
export function useUpdateDashboard() {
const qc = useQueryClient();
return useMutation({
mutationFn: ({ id, input }: { id: string; input: DashboardUpdateInput }) =>
apiPut<Dashboard>(`/dashboards/${id}`, input),
onSuccess: (_data, vars) => {
qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all });
qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.one(vars.id) });
},
});
}
export function useDeleteDashboard() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string) => apiDelete<void>(`/dashboards/${id}`),
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
});
}
export function useSetDefaultDashboard() {
const qc = useQueryClient();
return useMutation({
mutationFn: (id: string) => apiPost<Dashboard>(`/dashboards/${id}/set-default`),
onSuccess: () => qc.invalidateQueries({ queryKey: DASHBOARD_QUERY_KEYS.all }),
});
}