| @@ -186,10 +186,32 @@ Alle drei nutzen die gleichen Filter-Parameter wie die Report-Seite, exportieren | |||||
| Alle Spalten der Report-Tabelle sind serverseitig sortierbar (Klick auf Spaltenheader togglet ASC/DESC). URL-Parameter: `?sort={column}&dir={ASC|DESC}`. Default: `sort=date&dir=DESC`. | Alle Spalten der Report-Tabelle sind serverseitig sortierbar (Klick auf Spaltenheader togglet ASC/DESC). URL-Parameter: `?sort={column}&dir={ASC|DESC}`. Default: `sort=date&dir=DESC`. | ||||
| Sortierbare Spalten: `date`, `client`, `project`, `service`, `user`, `note`, `duration`, `revenue`. Die Revenue-Sortierung nutzt einen `HIDDEN`-Select-Alias (`COALESCE(p.hourlyRate, c.hourlyRate, s.hourlyRate) * t.duration`), da DQL keine berechneten Ausdrücke direkt im `ORDER BY` unterstützt. Sekundärsort ist immer `t.createdAt DESC`. | |||||
| Sortierbare Spalten: `date`, `client`, `project`, `service`, `label`, `user`, `note`, `duration`, `revenue`. Die Revenue-Sortierung nutzt einen `HIDDEN`-Select-Alias (`COALESCE(p.hourlyRate, c.hourlyRate, s.hourlyRate) * t.duration`), da DQL keine berechneten Ausdrücke direkt im `ORDER BY` unterstützt. Sekundärsort ist immer `t.createdAt DESC`. | |||||
| Twig-Macro `sort_header` im Template rendert die klickbaren Spaltenheader mit Sort-Indikator (▴/▾). JS (`initSortHeaders()`) setzt `sort`/`dir` als URL-Parameter und navigiert. | Twig-Macro `sort_header` im Template rendert die klickbaren Spaltenheader mit Sort-Indikator (▴/▾). JS (`initSortHeaders()`) setzt `sort`/`dir` als URL-Parameter und navigiert. | ||||
| ## Labels | |||||
| Optionales Freitext-Label pro Zeiteintrag zur Kategorisierung (z.B. Ticketnummer, Feature-Name). | |||||
| ### Datenmodell | |||||
| - `TimeEntry.label` (`VARCHAR(255)`, nullable, indiziert via `idx_time_entry_label`) | |||||
| - Wird bei Create, Update und Timer-Start gesetzt | |||||
| ### API | |||||
| | Route | Method | Beschreibung | | |||||
| |-----------------|--------|-----------------------------------------------------------| | |||||
| | `/api/labels` | GET | Autocomplete: `?projectId=X` (Top 5) oder `?q=X` (Suche) | | |||||
| ### Frontend | |||||
| - **Entry-Formular** (Create + Edit): Chip-UI mit Autocomplete-Dropdown. Beim Projektwechsel werden projektspezifische Label-Vorschläge geladen (`findTopLabelsByProject`). Freitextsuche über `searchLabels`. | |||||
| - **Stoppuhr-Popover**: Einfaches Textfeld (Desktop + Hamburger-Menü), Label wird beim Timer-Start mitgesendet. | |||||
| - **Report-Tabelle**: Eigene sortierbare Spalte (`label`), Anzeige als Badge. | |||||
| - **Report-Filter**: Label-Filter mit Mehrfachauswahl, Autocomplete und Negation (`labels_neg`). Filterlogik: `IN` (default) oder `NOT IN` (negiert). | |||||
| ## Stoppuhr / Timer | ## Stoppuhr / Timer | ||||
| Live-Timer zum Tracken von Zeiteinträgen. UI in der Navigation (Desktop + Hamburger-Menü), zusätzlich Play-Button an jeder Entry-Row zum Fortsetzen. | Live-Timer zum Tracken von Zeiteinträgen. UI in der Navigation (Desktop + Hamburger-Menü), zusätzlich Play-Button an jeder Entry-Row zum Fortsetzen. | ||||