mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-07-29 07:33:49 +00:00
refactor(frontend): restructure project layout and update API schema
Relocate frontend source code from `next-app/` to `frontend/` to align with the new project structure. This includes removing the old Next.js boilerplate files and establishing a cleaner workspace. Additionally, updates the OpenAPI specification to include support for the `immich` widget type and its corresponding configuration schema. - Move frontend files to `frontend/` - Delete obsolete `next-app/` directory and its configuration - Add `immich` widget type to `openapi.yaml` - Update `FrontendPlan.md` with dashboard refactor and UX direction
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import type {
|
||||
Dashboard,
|
||||
Group,
|
||||
Service,
|
||||
WidgetInstance,
|
||||
WidgetData,
|
||||
AssetFile,
|
||||
CreateGroupRequest,
|
||||
PatchGroupRequest,
|
||||
ServiceRequest,
|
||||
LayoutRequest,
|
||||
WidgetRequest,
|
||||
} from "./schema";
|
||||
|
||||
const API_BASE = process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8080";
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const res = await fetch(`${API_BASE}${path}`, {
|
||||
headers: { "Content-Type": "application/json", ...init?.headers },
|
||||
...init,
|
||||
});
|
||||
if (res.status === 204) return undefined as T;
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ message: res.statusText }));
|
||||
throw new ApiError(res.status, err.code || "unknown", err.message || "Request failed", err.details);
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
export class ApiError extends Error {
|
||||
constructor(
|
||||
public status: number,
|
||||
public code: string,
|
||||
message: string,
|
||||
public details?: unknown,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "ApiError";
|
||||
}
|
||||
}
|
||||
|
||||
// ── Dashboard ──
|
||||
export function getDashboard(): Promise<Dashboard> {
|
||||
return request("/api/v1/dashboard");
|
||||
}
|
||||
|
||||
// ── Groups ──
|
||||
export function listGroups(): Promise<Group[]> {
|
||||
return request("/api/v1/groups");
|
||||
}
|
||||
export function createGroup(body: CreateGroupRequest): Promise<Group> {
|
||||
return request("/api/v1/groups", { method: "POST", body: JSON.stringify(body) });
|
||||
}
|
||||
export function patchGroup(id: string, body: PatchGroupRequest): Promise<Group> {
|
||||
return request(`/api/v1/groups/${id}`, { method: "PATCH", body: JSON.stringify(body) });
|
||||
}
|
||||
export function deleteGroup(id: string, moveServices = false): Promise<void> {
|
||||
return request(`/api/v1/groups/${id}?moveServicesToUngrouped=${moveServices}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
// ── Services ──
|
||||
export function listServices(): Promise<Service[]> {
|
||||
return request("/api/v1/services");
|
||||
}
|
||||
export function createService(body: ServiceRequest): Promise<Service> {
|
||||
return request("/api/v1/services", { method: "POST", body: JSON.stringify(body) });
|
||||
}
|
||||
export function patchService(id: string, body: ServiceRequest): Promise<Service> {
|
||||
return request(`/api/v1/services/${id}`, { method: "PATCH", body: JSON.stringify(body) });
|
||||
}
|
||||
export function deleteService(id: string): Promise<void> {
|
||||
return request(`/api/v1/services/${id}`, { method: "DELETE" });
|
||||
}
|
||||
|
||||
// ── Layout ──
|
||||
export function putLayout(body: LayoutRequest): Promise<Dashboard> {
|
||||
return request("/api/v1/layout", { method: "PUT", body: JSON.stringify(body) });
|
||||
}
|
||||
|
||||
// ── Assets ──
|
||||
export async function uploadIcon(file: File): Promise<AssetFile> {
|
||||
const form = new FormData();
|
||||
form.append("file", file);
|
||||
const res = await fetch(`${API_BASE}/api/v1/assets/icons`, { method: "POST", body: form });
|
||||
if (!res.ok) {
|
||||
const err = await res.json().catch(() => ({ message: res.statusText }));
|
||||
throw new ApiError(res.status, err.code || "unknown", err.message || "Upload failed");
|
||||
}
|
||||
return res.json();
|
||||
}
|
||||
|
||||
// ── Widgets ──
|
||||
export function listWidgets(): Promise<WidgetInstance[]> {
|
||||
return request("/api/v1/widgets");
|
||||
}
|
||||
export function createWidget(body: WidgetRequest): Promise<WidgetInstance> {
|
||||
return request("/api/v1/widgets", { method: "POST", body: JSON.stringify(body) });
|
||||
}
|
||||
export function patchWidget(id: string, body: WidgetRequest): Promise<WidgetInstance> {
|
||||
return request(`/api/v1/widgets/${id}`, { method: "PATCH", body: JSON.stringify(body) });
|
||||
}
|
||||
export function deleteWidget(id: string): Promise<void> {
|
||||
return request(`/api/v1/widgets/${id}`, { method: "DELETE" });
|
||||
}
|
||||
export function getWidgetData(id: string): Promise<WidgetData> {
|
||||
return request(`/api/v1/widgets/${id}/data`);
|
||||
}
|
||||
export function refreshWidget(id: string): Promise<WidgetData> {
|
||||
return request(`/api/v1/widgets/${id}/refresh`, { method: "POST" });
|
||||
}
|
||||
Reference in New Issue
Block a user