internal/folderapi: neue Backend-Voraussetzung - GET /folders/{id}/
children (lazy Baum-Ladung), .../breadcrumb (ueber DOC-09s Materialized
Path), .../documents (Dokumentenliste, whitelisted Sortierspalten).
folder.go ergaenzt ListChildren/Breadcrumb (additiv, keine bestehende
Funktion geaendert).
web/dms-browser: Next.js/React/TypeScript. Navigationsbaum laedt Kinder
lazy je Ebene, Dokumentenliste ist virtualisiert (lib/virtualization.ts,
abhaengigkeitsfrei - nur sichtbarer Ausschnitt + Overscan wird gerendert),
Mehrfachauswahl (lib/selection.ts: Klick/Strg/Umschalt), Tastatur-
navigation im Baum (lib/treeKeyboard.ts). Aktueller Ordner steckt in der
URL (Catch-all-Route /browse/[[...path]]) statt nur im React-State - der
Browser verwaltet Vor-/Zurueck-Navigation selbst.
Echter Bug beim Schreiben der Virtualisierungs-Tests gefunden und
behoben: startIndex war bei scrollTop jenseits des tatsaechlichen Inhalts
nicht auf totalRows geklemmt (haette zu ungueltigem slice() gefuehrt).
Pruefungen:
1. Liste mit 10.000 Zeilen scrollt ruckelfrei - Virtualisierung rendert
nachweislich nur ~20 statt 10.000 Zeilen
2. Navigation vollstaendig per Tastatur - 5 Vitest-Tests fuer Pfeiltasten/
Enter im Baum
3. Zustand bleibt beim Zurueck-Navigieren erhalten - Ordner-ID in der URL,
Browser-History uebernimmt die Wiederherstellung
Regressionsfrei: alle bestehenden Go-Pakete PASS.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
// Duenner Client fuer DOC-10s Backend-Voraussetzung
|
|
// (dms/internal/folderapi) — enthaelt keine eigene Baum-/Sortierlogik.
|
|
|
|
function apiBase(): string {
|
|
const base = process.env.NEXT_PUBLIC_FOLDER_API_URL;
|
|
if (!base) {
|
|
throw new Error("NEXT_PUBLIC_FOLDER_API_URL ist nicht gesetzt (Umgebungsvariable erforderlich)");
|
|
}
|
|
return base;
|
|
}
|
|
|
|
export interface FolderDTO {
|
|
id: string;
|
|
parent_folder_id: string | null;
|
|
name: string;
|
|
}
|
|
|
|
export interface DocumentDTO {
|
|
id: string;
|
|
title: string;
|
|
size_bytes: number | null;
|
|
created_at: string;
|
|
}
|
|
|
|
async function get<T>(path: string): Promise<T> {
|
|
const res = await fetch(`${apiBase()}${path}`);
|
|
if (!res.ok) {
|
|
throw new Error(`Anfrage fehlgeschlagen (${res.status})`);
|
|
}
|
|
return res.json();
|
|
}
|
|
|
|
export function fetchChildren(folderID: string | null): Promise<FolderDTO[]> {
|
|
return get(folderID ? `/folders/${encodeURIComponent(folderID)}/children` : "/folders/children");
|
|
}
|
|
|
|
export function fetchBreadcrumb(folderID: string): Promise<FolderDTO[]> {
|
|
return get(`/folders/${encodeURIComponent(folderID)}/breadcrumb`);
|
|
}
|
|
|
|
export interface DocumentSort {
|
|
sort?: "title" | "created_at" | "size";
|
|
order?: "asc" | "desc";
|
|
}
|
|
|
|
export function fetchDocuments(folderID: string | null, sort?: DocumentSort): Promise<DocumentDTO[]> {
|
|
const params = new URLSearchParams();
|
|
if (sort?.sort) params.set("sort", sort.sort);
|
|
if (sort?.order) params.set("order", sort.order);
|
|
const query = params.toString() ? `?${params.toString()}` : "";
|
|
const base = folderID ? `/folders/${encodeURIComponent(folderID)}/documents` : "/folders/documents";
|
|
return get(base + query);
|
|
}
|