Files
kbcrm/Client/models/tag.ts
T
gg 5abcb2d96c 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>
2026-09-19 14:08:34 +02:00

109 lines
3.1 KiB
TypeScript

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)
}