Tag-Modell um is_erledigend, loest_wiedervorlage_aus und wiedervorlage_abstand_tage erweitert. Migration V01_12 idempotent angelegt, Geschäftslogik mit Validierung, Client-Maske mit Controls und Workflow-Badges. Farb-Default Grau bei fehlender Farbe, parent_id im onchange direkt in currentTag übernehmen. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
115 lines
3.4 KiB
TypeScript
115 lines
3.4 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
|
|
/** True = Kontakt gilt als erledigt, wenn dieser Tag zugewiesen wird. */
|
|
is_erledigend: boolean
|
|
/** True = Tag löst eine Wiedervorlage aus. */
|
|
loest_wiedervorlage_aus: boolean
|
|
/** Tage bis zur Wiedervorlage (nur relevant, wenn loest_wiedervorlage_aus True). */
|
|
wiedervorlage_abstand_tage: number | null
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
}
|