Files
rack-planner/client/src/api/client.ts

199 lines
5.0 KiB
TypeScript
Raw Normal View History

import type {
Rack,
Module,
Port,
Vlan,
ServiceMap,
ServiceMapSummary,
ServiceNode,
ServiceEdge,
ModuleType,
PortType,
VlanMode,
NodeType,
} from '../types';
// ---- Core fetch wrapper ----
async function request<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const res = await fetch(`/api${endpoint}`, {
...options,
headers: { 'Content-Type': 'application/json', ...options.headers },
credentials: 'include',
});
const body = await res.json().catch(() => ({ data: null, error: `HTTP ${res.status}` }));
if (!res.ok) {
throw new Error((body as { error?: string }).error ?? `HTTP ${res.status}`);
}
return (body as { data: T }).data;
}
function get<T>(path: string) {
return request<T>(path);
}
function post<T>(path: string, data?: unknown) {
return request<T>(path, { method: 'POST', body: JSON.stringify(data) });
}
function put<T>(path: string, data?: unknown) {
return request<T>(path, { method: 'PUT', body: JSON.stringify(data) });
}
function del<T>(path: string) {
return request<T>(path, { method: 'DELETE' });
}
// ---- Auth ----
const auth = {
me: () => get<{ authenticated: boolean }>('/auth/me'),
login: (username: string, password: string) =>
post<{ success: boolean }>('/auth/login', { username, password }),
logout: () => post<{ success: boolean }>('/auth/logout'),
};
// ---- Racks ----
const racks = {
list: () => get<Rack[]>('/racks'),
get: (id: string) => get<Rack>(`/racks/${id}`),
create: (data: { name: string; totalU?: number; location?: string; displayOrder?: number }) =>
post<Rack>('/racks', data),
update: (
id: string,
data: Partial<{ name: string; totalU: number; location: string; displayOrder: number }>
) => put<Rack>(`/racks/${id}`, data),
delete: (id: string) => del<null>(`/racks/${id}`),
addModule: (
rackId: string,
data: {
name: string;
type: ModuleType;
uPosition: number;
uSize?: number;
manufacturer?: string;
model?: string;
ipAddress?: string;
notes?: string;
portCount?: number;
portType?: PortType;
}
) => post<Module>(`/racks/${rackId}/modules`, data),
};
// ---- Modules ----
const modules = {
update: (
id: string,
data: Partial<{
name: string;
uPosition: number;
uSize: number;
manufacturer: string;
model: string;
ipAddress: string;
notes: string;
}>
) => put<Module>(`/modules/${id}`, data),
delete: (id: string) => del<null>(`/modules/${id}`),
move: (id: string, rackId: string, uPosition: number) =>
post<Module>(`/modules/${id}/move`, { rackId, uPosition }),
getPorts: (id: string) => get<Port[]>(`/modules/${id}/ports`),
};
// ---- Ports ----
const ports = {
update: (
id: string,
data: {
label?: string;
mode?: VlanMode;
nativeVlan?: number | null;
notes?: string;
vlans?: Array<{ vlanId: string; tagged: boolean }>;
}
) => put<Port>(`/ports/${id}`, data),
};
// ---- VLANs ----
const vlans = {
list: () => get<Vlan[]>('/vlans'),
create: (data: { vlanId: number; name: string; description?: string; color?: string }) =>
post<Vlan>('/vlans', data),
update: (id: string, data: Partial<{ name: string; description: string; color: string }>) =>
put<Vlan>(`/vlans/${id}`, data),
delete: (id: string) => del<null>(`/vlans/${id}`),
};
// ---- Service Maps ----
const maps = {
list: () => get<ServiceMapSummary[]>('/maps'),
get: (id: string) => get<ServiceMap>(`/maps/${id}`),
create: (data: { name: string; description?: string }) => post<ServiceMap>('/maps', data),
update: (id: string, data: Partial<{ name: string; description: string }>) =>
put<ServiceMap>(`/maps/${id}`, data),
delete: (id: string) => del<null>(`/maps/${id}`),
addNode: (
mapId: string,
data: {
label: string;
nodeType: NodeType;
positionX: number;
positionY: number;
metadata?: string;
color?: string;
icon?: string;
moduleId?: string;
}
) => post<ServiceNode>(`/maps/${mapId}/nodes`, data),
populate: (mapId: string) => post<ServiceMap>(`/maps/${mapId}/populate`),
addEdge: (
mapId: string,
data: {
sourceId: string;
targetId: string;
label?: string;
edgeType?: string;
animated?: boolean;
}
) => post<ServiceEdge>(`/maps/${mapId}/edges`, data),
};
// ---- Nodes ----
const nodes = {
update: (
id: string,
data: Partial<{
label: string;
positionX: number;
positionY: number;
metadata: string;
color: string;
icon: string;
moduleId: string | null;
}>
) => put<ServiceNode>(`/nodes/${id}`, data),
delete: (id: string) => del<null>(`/nodes/${id}`),
};
// ---- Edges ----
const edges = {
update: (
id: string,
data: Partial<{ label: string; edgeType: string; animated: boolean; metadata: string }>
) => put<ServiceEdge>(`/edges/${id}`, data),
delete: (id: string) => del<null>(`/edges/${id}`),
};
export const apiClient = { auth, racks, modules, ports, vlans, maps, nodes, edges };