20 Commits
Author SHA1 Message Date
gg bc9b337696 feat(crm): zentrale TagBadge-Komponente und Ergänzungen zur Workflow-Maske
- Position des Ansprechpartners in der Kopfzeile der Tagesworkflow-Maske anzeigen
- Neue TagBadge-Komponente (Farbchip, Name, Workflow-Icons: erledigend/
  Wiedervorlage) ersetzt die duplizierte Badge-Darstellung in Notiz-Liste,
  Workflow-Liste, Historie und Tag-Liste
- MultiSelect: optionale content-Option rendert ein fertiges Badge des
  Aufrufers statt Farbpunkt + Label im Auswahl-Modal; Suchfeld wird beim
  Öffnen des Modals fokussiert
- TagBadge-Attribut heißt tagData statt tag, da Mithril attrs-Objekte mit
  tag-Property als Vnode-Kinder behandelt (führte zu 'color' undefined)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-27 18:37:49 +02:00
gg 929664453e feat(form): flexContent-Option für Flex-Spalte im Formular-Inhalt
Der scrollbare Inhaltsbereich der Form kann bei Bedarf als Flex-Spalte
gerendert werden, damit Masken-Kinder den verbleibenden Platz füllen und
in sich scrollen können, statt die gesamte Maske scrollbar zu machen.
Wirkt nur zusammen mit stickyButtons (Default true).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-27 10:09:09 +02:00
gg 32afb35840 feat(workflow): Workflow-Buttons in die Standard-Button-Leiste der Form integrieren
Die Workflow-Buttons ("Nächster Kontakt", "Speichern und weiter") standen
bisher in einer eigenen Zeile über der Standard-Leiste (Zurücksetzen,
Abbrechen, Speichern). Das Form-Widget erhält dafür das neue optionale
Attribut extrabuttons, dessen Buttons rechts neben "Speichern" in die
Leiste eingereiht werden — sie profitieren damit auch vom Sticky-Verhalten
der Leiste.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-24 19:24:50 +02:00
gg 4d8febcc3f fix(select): Anzeige bei asynchron nachgeladenen Optionen nachziehen
Beim oninit war attrs.value teils keiner Option zuzuordnen, weil die
Optionen (z.B. Kundenliste) asynchron geladen werden — das Feld blieb
dauerhaft leer, da lastSyncedValue bereits gesetzt war und der Sync im
view nicht mehr griff. syncPending markiert die offene Synchronisierung
und wiederholt sie im view, bis eine passende Option existiert; Tippen
verwirft das Flag, damit die Nutzereingabe nicht überschrieben wird.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-24 19:14:16 +02:00
gg 3ba9b0a07f fix(treetable): Sticky-Header der Kopfzeile reparieren
Die schließende Klammer fehlte im calc() der Scroll-Container-Höhe, wodurch
die Höhe auf auto fiel und der Div nie selbst scrollte — Sticky bezog sich
damit auf keinen funktionierenden Scroll-Container. Zusätzlich das
overflow-y am table-Element entfernt (macht die Tabelle selbst zum
Scroll-Container und bricht Sticky) und w3-theme als eigener Hintergrund
auf die th gelegt, damit beim Scrollen keine Zeilen durchscheinen.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-24 19:02:40 +02:00
gg 981b28df03 feat(treetable): optionale Kopfzeile und abschaltbare Expand-Buttons
Neues Attribut header rendert eine sticky Spaltenüberschriftenzeile.
showExpandButtons=false blendet die Ein-/Ausklappen-Buttons aus; die
Topbar entfällt dann ganz, wenn auch keine Children oder Filter vorhanden
sind — der scrollbare Bereich nutzt in dem Fall die volle Höhe.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-24 18:54:42 +02:00
gg 3a6732e36b feat(select): Öffnen-Button für ungefilterte Liste und Sync externer value-Änderungen
Der neue Öffnen-Button blendet die Optionsliste ungefiltert ein, ohne das
Feld zu leeren. Der Anzeigetext wird zudem im view nachgezogen, wenn der
Eltern-View den value ändert (z.B. Zurücksetzen eines Filters).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-24 18:53:44 +02:00
gg a67921ec74 feat(isdirty): Navigations-Guard gegen ungespeichertes Verlassen von Bearbeitungsmasken
Zentraler DirtyGuard (dirtyguard.ts) mit DirtyMaskHelper-Klasse und
3-Button-Bestätigungs-Modal (Speichern/Verwerden/Abbrechen). Form meldet
Dirty-State via onDirtyChange nach oben; input-Event ergänzt change für
frühzeitiges Dirty-Marking. Alle App-Navigationen (Breadcrumb, Menü,
In-Masken-Buttons, Abbrechen) laufen über guardedNavigate. Auto-Redraw
bei dirty per e.redraw=false unterbunden, damit DOM-Eingaben erhalten
bleiben (Input-Widget hat kein Live-Binding).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 18:21:58 +02:00
gg fd30049a32 feat(nav): Breadcrumb-Navigation für Hierarchie-Aufrufkette
Neue BreadcrumbBar-Widget-Komponente (breadcrumb.ts) zeigt die
Aufrufkette als anklickbare Leiste. Der Route-Param bc (JSON-String)
transportiert die Vorgänger-Ansichten durch alle Listen und Masken.
Jede Ansicht hängt beim Weiternavigieren ihren eigenen Crumb an die
Kette an; Masken reichen bc beim Speichern/Abbrechen zurück.
Erfasst: kunde, projekt, kontaktadresse, call_log, kontakt.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 16:16:49 +02:00
gg d30adf1579 feat(calllog): Tags einer Gesprächsnotiz zuordnen (n:m)
Backend:
- Neues CallLogTag-Model (Tabelle call_logs_tags) mit Relationship
  auf CallLog (cascade delete-orphan); to_dict liefert 'tags'.
- Migration _db_V01_11 (idempotent via create_all).
- _set_call_log_tags in create/update_call_log: ersetzt
  Tag-Zuordnungen, filtert is_parent-Tags, eliminiert Duplikate.
- _parse_date wandelt ISO-Strings in date-Objekte (fixt autoflush-
  Crash bei Date-Spalten).

Frontend:
- iCallLog um tags (Lesen) und tag_ids (Schreiben) ergänzt.
- Neues generisches MultiSelect-Widget (widgets/select.ts):
  Badges + Edit-Button, inline Modal mit Suchfeld, Checkbox-Liste,
  OK-Button; konfigurierbare Texte (placeholder, modalTitle,
  editTooltip).
- Call_Log-Formular: Tag-Auswahl via MultiSelect, Submit via
  FormData.getAll; Tag-Badges in der Listenansicht hinter dem Betreff.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 15:12:36 +02:00
gg 675d7775c1 feat: oninput-Callback zum Input-Widget hinzugefügt
Ermöglicht ein Live-Binding der Eingabewerte, damit Eingaben bei einem
Redraw (z.B. durch interaktive Elemente außerhalb des Inputs) nicht
verloren gehen.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 14:07:30 +02:00
ggandMistral Vibe 3361ef16dd feat: Treetable filter auf Kind-Knoten anwenden
Der filter-Callback wird jetzt auch auf Kind-Knoten angewendet, nicht nur auf Top-Level-Nodes. Dadurch lässt sich bei hierarchischen Daten (z.B. Tag-Baum) die Suche auf den gesamten Teilbaum verfeinern — nur Knoten, die selbst matchen oder einen matchenden Nachfahren haben, werden gerendert.

Abwärtskompatibel: Aufrufer ohne filter-Attribut sind unaffected.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-19 10:39:11 +02:00
gg 9ed5e88e01 Menü Projekt-Berechtigungen, Übersichtssichten und AppAdmin-Erkennung
- Menü: Dropdown "Projekt-Berechtigungen" unter Optionen mit
  Unterpunkten "Projekt-Zugriffe" und "Nutzer-Zugriffe" (nur SysAdmin/AppAdmin)
- AppAdmin-Erkennung: Server liefert isAppAdmin-Flag im Login- und
  getusers-Response (applikationsspezifisch via has_permission)
- Login: CurrentUserIsAppAdmin in sessionStorage speichern/entfernen
- Projekt-Zugriffe: geschachtelter Treetable (Projekt → Nutzer) als
  reine Anzeige, Detail-Sicht aus Projekt-Maske mit Bearbeitung
- Nutzer-Zugriffe: neue Komponente user_projektliste.ts, geschachtelter
  Treetable (Nutzer → Projekte), reine Anzeige
- Server: neuer Endpunkt GET /xhr/projektuser/listall (nur AppAdmin/SysAdmin)
- Server: get_all_projekt_users() mit Batch-Query für Projekte und User
- Treetable-Widget: Platzhalter-Pfeil bei kinderlosen Nodes nur wenn
  Geschwister mit Kindern existieren (hasSiblingsWithChildren)
- Datei projekt_user.ts umbenannt in projekt_userliste.ts (konsistent
  mit user_projektliste.ts)

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-07 16:04:06 +02:00
gg 461953a7e9 Datumsspalten auf Date-Typ umgestellt und Normalisierungsmigration
Modelle: startdatum (Projekt), datum und wiedervorlage_datum (CallLog)
von String(20) auf Date umgestellt. columns2dict serialisiert diese nun
über isoformat() als yyyy-MM-dd. Die String-Normalisierung in
columns2dict wurde entfernt, da sie nicht mehr benötigt wird.

Migration V01.08: Normalisiert bestehende String-Datumswerte (z.B.
'2026-08-3') auf ISO-Format yyyy-MM-dd mittels printf/substr, da
SQLite's date() einstellige Komponenten nicht erkennt. Leere Strings
werden zu NULL. V01.07 ist Platzhalter für die fehlgeschlagene V01.06.

Client: toDateInputValue normalisiert ebenfalls String-Datumswerte
als Fallback für Route-Params (Neuanlage).

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-04 16:57:17 +02:00
gg 68e9de8dc1 Treetable: optionale isSelected-Callback für Zeilen-Markierung
Die Treetable unterstützt nun ein optionales isSelected-Callback (iTreetable.isSelected),
mit dem die Hintergrund-Einfärbung der gesamten <tr>-Zeile gesteuert werden kann. Bisher
musste jede Zelle einzeln über den columnmapper gestylt werden. Die Markierung verwendet
die w3-theme-l4-Klasse statt einer festen Farbe.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-09-01 10:27:13 +02:00
gg 28f858f6da Form-Widget stickyButtons und einheitliches Form-View-Layout
Form-Widget um stickyButtons-Attribut erweitert (default true): nur der
Formularinhalt scrollt, die Buttons bleiben fixiert am unteren Rand. Neue
CSS-Klasse .form-view-container (flex-Column, volle Höhe) für die
umschließenden View-Container. Form-Views (kunde, projekt, call_log, tags)
auf w3-auto.form-view-container umgestellt; Tag-Form von w3-twothird auf
w3-auto korrigiert.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-08-31 20:10:54 +02:00
gg ba6c0c50d1 Select-Widget verfeinert: ClosureComponent-Muster, Tastatur-Navigation, Clear-Button
Select auf sauberes ClosureComponent-Muster umgestellt (Closure-Parameter
weggelassen, attrs nur über Hook-vnode gelesen). Auswahl per Maus über
mousedown umgestellt, damit das Dropdown zuverlässig geschlossen wird.
Zusätzlich Clear-Button (Material-Icon "clear") im Eingabefeld, absolut
positioniert und vertikal zentriert, leert das Suchfeld. readonly-Modus
unterstützt.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-08-31 18:23:55 +02:00
gg d4319de445 Neues Select-Widget hinzugefügt: suchbares Dropdown mit Tastatur-Navigation
Erzeugt ein Combobox-Widget (widgets/select.ts) mit Suchfeld, gefilterter
Optionliste, Maus-Auswahl und Tastaturbedienung (Pfeil-auf/ab, Enter,
Escape). Verstecktes Feld für die FormData-Übergabe, readonly-Modus für
voreingestellte Werte.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-08-31 15:34:57 +02:00
gg ada80d0938 Typanpassung für toDateInputValue: Unterstützung für Datums- und String-Parameter hinzugefügt 2026-08-30 15:27:55 +02:00
gg 1ba78992a6 Initial Commit für das Grundgerüst der Anwendung, bestehend aus der Dev-Container Konfiguration, der Docker und docker-Compose Definitionen sowie der Verzeichnisse App_Server für die Backend-Programme sowie Client für die browserseitigen GUI-Komponenten 2026-08-17 16:10:11 +02:00