feat(tags): Backend mit REST-API und Client-Anbindung fuer hierarchische Tags
- SQLAlchemy-Modell Tag mit Selbst-Referenz (parent_id), is_parent-Flag - DB-Migration V01.10 (idempotent via create_all) - Geschaeftslogik tag.py: CRUD, Hierarchie-Aufbau, kaskadierendes Loeschen, Zirkelbezug-Pruefung - REST-Endpunkte /xhr/tag/*: Lesen fuer Mitarbeiter, Schreiben fuer AppAdmin - Client-Modell tag.ts mit REST-Funktionen - Frontend tags.ts auf REST-API umgestellt, hartcodierte Daten entfernt, Loesch-Dialog mit kaskadierender Bestaetigung Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
1 parent
675d7775c1
commit
5abcb2d96c
6 files changed
+600
-648
No files matched your search
@@ -0,0 +1,108 @@
|
||||
import m from "mithril"
|
||||
|
||||
/**
|
||||
* Datenmodell für einen Tag (hierarchische Taxonomie).
|
||||
* Die Feldnamen entsprechen den serverseitigen ORM-Spalten (snake_case).
|
||||
* Tags koennen beliebig verschachtelt werden (parent_id -> tags.id).
|
||||
*/
|
||||
export interface iTag {
|
||||
id: number
|
||||
name: string
|
||||
description: string
|
||||
color: string
|
||||
parent_id: number | null
|
||||
is_parent: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Tag mit verschachtelten Kindern für die Hierarchie-Darstellung.
|
||||
* Das children-Array wird serverseitig im Hierarchie-Endpunkt befüllt.
|
||||
*/
|
||||
export interface iTagWithChildren extends iTag {
|
||||
children: iTagWithChildren[]
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* REST-API-Aufrufe (Client-Seite) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Die folgenden Funktionen kapseln die Kommunikation mit den */
|
||||
/* serverseitigen REST-Endpunkten (/xhr/tag/*). */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Basis-Pfad der Tag-REST-Endpunkte.
|
||||
*/
|
||||
const TAG_REST_BASE = "/xhr/tag"
|
||||
|
||||
/**
|
||||
* Lädt alle Tags als flache Liste vom Server.
|
||||
* Ist parentId gesetzt, werden nur die direkten Kinder dieses Tags
|
||||
* geliefert (serverseitige Filterung).
|
||||
*/
|
||||
export function fetchTags(parentId?: number): Promise<iTag[]> {
|
||||
const params: Record<string, any> = {}
|
||||
if (parentId !== undefined) {
|
||||
params.parent_id = parentId
|
||||
}
|
||||
return m.request({
|
||||
method: "GET",
|
||||
url: TAG_REST_BASE + "/list",
|
||||
params: params
|
||||
}).then((result) => result as iTag[])
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt die vollständige Tag-Hierarchie als verschachtelte Struktur vom Server.
|
||||
* Jeder Tag enthält ein children-Array mit seinen rekursiv eingebetteten Kindern.
|
||||
*/
|
||||
export function fetchTagHierarchy(): Promise<iTagWithChildren[]> {
|
||||
return m.request({
|
||||
method: "GET",
|
||||
url: TAG_REST_BASE + "/hierarchy"
|
||||
}).then((result) => result as iTagWithChildren[])
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt einen einzelnen Tag anhand seiner ID vom Server.
|
||||
*/
|
||||
export function fetchTagById(id: number): Promise<iTag> {
|
||||
return m.request({
|
||||
method: "GET",
|
||||
url: TAG_REST_BASE + "/get",
|
||||
params: {id: id}
|
||||
}).then((result) => result as iTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Legt einen neuen Tag serverseitig an. Die ID wird vom Server
|
||||
* vergeben und im zurückgegebenen Tag-Objekt gesetzt.
|
||||
*/
|
||||
export function createTagREST(tag: iTag): Promise<iTag> {
|
||||
return m.request({
|
||||
method: "POST",
|
||||
url: TAG_REST_BASE + "/create",
|
||||
body: tag
|
||||
}).then((result) => result as iTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Aktualisiert einen bestehenden Tag serverseitig.
|
||||
*/
|
||||
export function updateTagREST(tag: iTag): Promise<iTag> {
|
||||
return m.request({
|
||||
method: "PUT",
|
||||
url: TAG_REST_BASE + "/update",
|
||||
body: tag
|
||||
}).then((result) => result as iTag)
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht einen Tag inkl. aller Nachfahren serverseitig anhand seiner ID.
|
||||
*/
|
||||
export function deleteTagREST(id: number): Promise<void> {
|
||||
return m.request({
|
||||
method: "DELETE",
|
||||
url: TAG_REST_BASE + "/delete",
|
||||
params: {id: id}
|
||||
}).then(() => undefined)
|
||||
}
|
||||
Reference in new issue
Block a user