Einige kleine verbesserungen #1
Reference in New Issue
Block a user
Delete Branch "beta"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Enddatum wird im Event-Popup angezeigt wenn Termin über Mitternacht geht. Neuer Kopieren-Button (📋) im Popup öffnet Kalender-Auswahl und dupliziert den Termin in den gewählten Kalender (CalDAV / Lokal / Google).Wenn der Access-Token eines Google-Accounts abläuft und der Refresh fehlschlägt, wurde die leere Terminliste bisher still zurückgegeben (kein Log, keine UI-Meldung). Jetzt wird der Fehler geloggt, an den Aufrufer weitergegeben und als Toast-Meldung im Frontend angezeigt ("Token abgelaufen – bitte Konto trennen und neu verbinden"). Das Events-Endpoint gibt nun {events, errors} statt ein reines Array zurück; das Frontend extrahiert die Events entsprechend.- Neue Integration: Home Assistant als Kalenderquelle via REST-API (GET /api/calendars + GET /api/calendars/{entity_id}) - Authentifizierung per Long-Lived Access Token - Neues Modal zum Verbinden (Name, URL, Token) mit Fehlerbehandlung - Kalender einzeln aktivierbar/deaktivierbar, Farbe änderbar - Ausgeblendete HA-Kalender in Einstellungen wiederherstellbar - Sync- und Trennen-Buttons in den Einstellungen - Bugfix: CalDAV- und Google-Kalender mit sidebar_hidden=true liefern nun keine Events mehr im KalenderPUT/DELETE /api/calendars/{entity_id}/{uid} existieren nicht in HA. Stattdessen: POST /api/services/calendar/update_event und POST /api/services/calendar/delete_event (HA 2023.x+)iCal speichert DTEND exklusiv (Tag NACH dem letzten Tag). Bisher führte das dazu, dass ein Termin mit Ende=18.08 nur bis zum 17.08 angezeigt wurde, obwohl der User 18.08 als letzten Tag erwartete. Fix: Im Date-Picker arbeiten wir jetzt mit inklusiven End-Daten ('endet am 18.08' = 18.08 ist letzter Tag) und konvertieren beim Speichern auf exklusiv (DTEND=19.08). Beim Laden umgekehrt: -1 Tag fürs Anzeigen im Picker. Betrifft: openEditEventModal, openCopyEditModal, Save-Handler.- View-Switcher auf Mobile in Popup-Menü ausgelagert (neuer Icon-Button rechts in der Topbar). Dadurch wird in der Topbar Platz frei für prev/next + Monatstitel ("Mai 2026" usw.). - Topbar-Settings-Icon auf Mobile ausgeblendet, dafür neuer "Einstellungen"-Eintrag im User-Dropdown. "Heute" wandert ins View-Popup. - KW-Bubble: von oben-links nach unten-links verschoben — überlappt jetzt nicht mehr die Tagesnummer. - Termine in der Monatsansicht zeigen wieder ihren Text (kleinere 14px-Höhe, 9px Schrift) statt nur farbiger Punkte. - Long-Press auf einen Tag öffnet das Kontextmenü "Termin erstellen" (synthetisches contextmenu-Event nach 500 ms ohne Bewegung). Der nachfolgende synthetische Click wird unterdrückt. - Settings-Modal: Sidebar (Darstellung/Konten/Benutzerverwaltung) auf Mobile als slide-in Overlay mit Hamburger-Toggle. Auf Desktop bleibt sie immer sichtbar. - Version v4 → v5 (auch SW-Cache)- Titel im Topbar wird auf Mobile auf 2 Zeilen aufgeteilt: Hauptlabel (z.B. "Mai – Jun") oben, Jahr ("2026") darunter in kleinerer Schrift. Auf Desktop bleibt es einzeilig durch margin-left auf der Year-Span. - Event-Popup: 44px-Mindestgröße der Icon-Buttons greift hier nicht mehr — Buttons bleiben kompakt 32px, weniger Gap, schmaleres Popup (max 92vw / 340px), sodass das Schließen-X nicht aus dem Rand herausragt. - Monatsansicht auf Mobile: Startuhrzeit ("00:00 Lemgo") wird versteckt, nur der Titel ist sichtbar. Auf Desktop wie bisher mit Uhrzeit-Präfix. Die Info bleibt im Termin-Popup verfügbar. Version v8 → v9.Bisher konnten alte JS-/CSS-Dateien durch Service-Worker- und Browser- Cache hartnäckig hängen bleiben, obwohl auf dem Server schon eine neue Version lag. Strategie jetzt: Backend (main.py) - Neue HTTP-Middleware setzt explizite Cache-Control-Header: * /, /index.html, /manifest.json, /sw.js, /static/js/version.js bekommen no-cache, no-store, must-revalidate * /static/* und /icons/* bekommen public, max-age=7200, must-revalidate (2 h) * SPA-Fallback-Antworten ebenfalls no-cache * /api/* bleibt unangetastet Service Worker (sw.js) - Wechsel von Cache-First zu Network-First für alles - Cache wird nur noch für die index.html-Offline-Hülle vorgehalten, nicht mehr für JS/CSS — Browser-HTTP-Cache übernimmt das mit den 2-h-Headern vom Server - Bei Netzwerkfehler bleibt nur die HTML-Shell offline verfügbar Version v11 → v12 (auch SW-Cache-Key).Die bisherigen Stufen-Wähler ("Dunkel/Mittel/Hell/Maximum" und "Kaum/Subtil/Normal/Stark") für Schrift- bzw. Linienkontrast sind durch echte Hex-Color-Picker ersetzt. Zusätzlich kann jetzt auch die Hintergrundfarbe der Seite frei gewählt werden. Wenn ein Override gesetzt ist: - text_color → setzt --text-1 direkt, --text-2/--text-3 werden daraus per shadeHex(-0.25 / -0.55) abgeleitet, damit der Hue passt - line_color → setzt --border, --border-light wird leicht abgedunkelt - bg_color → setzt --bg-app, daraus werden Topbar/Sidebar/Surface/ Hover/Active per shadeHex(+0.10…+0.40) konsistent hochskaliert Per "Reset"-Knopf wird der Override geleert und die alte Stufen-Logik (falls noch vorhanden) bzw. der Default-Theme greift wieder. Backend: - 3 neue nullable VARCHAR(7)-Spalten in user_settings (text_color, line_color, bg_color) inkl. Migrationen in main.py - settings_router nutzt model_dump(exclude_unset=True) und respektiert explizite null-Werte nur für diese 3 Override-Felder, damit Reset funktioniert Auch enthalten: Auflösen der Merge-Konflikte in sw.js, index.html, version.js (HEAD-Stand v17 behalten) und Bump auf v18.- Live-Vorschau beim Tippen statt erst bei Blur (input-Event) - Hex-Werte werden auch ohne fuehrendes '#' akzeptiert ("ff0000" -> "#FF0000") - Reset-Button wendet Standardwerte sofort an - v19 / sw cache v19Kollaborations-Features ausschliesslich fuer lokale Kalender: - Sharing: calendar_shares-Tabelle, GET/POST/DELETE /api/local/calendars/{id}/shares (nur Besitzer), GET /api/users/directory, geteilte Kalender in GET /api/local/calendars (shared_by/permission/owned) und im Merge-Read. - Gruppen: groups/group_members/group_calendars + /api/groups-Router inkl. kombinierter Ansicht /api/groups/{id}/combined (owner + is_group_event). - Ersteller: local_events.creator_id (serverseitig gesetzt) + creator_name_external aus ORGANIZER; creator-Feld in allen lokalen Event-Responses. - Private-Flag: local_events.is_private + user_settings.private_event_visibility (hidden|busy), Filterung in der Gruppenansicht. - iCal Import/Export: ical_io.py, POST /api/local/calendars/{id}/import, POST /api/local/import, GET /api/local/calendars/{id}/export. - Zentraler Berechtigungs-Helper (permissions.py) und gemeinsamer Event-Dict- Builder (local_events_util.py) ersetzen die Nur-Besitzer-Filter. - pytest-Suite (12 Tests) fuer Sharing, Gruppen, Parser, Private-Filterung. Additiv & rueckwaertskompatibel; Migrationen in main.py._migrate(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>- Sidebar-Sektion "Gruppen": Liste, Erstellen (Name + Mitglieder-Picker), Verwalten (Mitglieder hinzufuegen/entfernen), Loeschen. - Gruppenansicht: laedt /api/groups/{id}/combined fuer den sichtbaren Bereich; Event-Titel werden mit Besitzer-Initialen bzw. Gruppen-Icon praefixt; Banner mit "Gruppenansicht verlassen". - Server: GET /api/local/calendars liefert nun auch Gruppenkalender (group:true, read_write) fuer Mitglieder, damit sie im Editor waehlbar sind. Test ergaenzt (13 gruen). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Die Quelle/Konto stand inline rechts und hat die Kalendernamen abgeschnitten. Jetzt im title-Tooltip des Eintrags ("Name · Quelle"); der Name nutzt die volle Breite. Version v29. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Kombinierte Ansicht: kryptisches "[SC]"-Initialen-Präfix ersetzt durch den Vornamen ("Guido: Titel") für fremde Termine; eigene Termine ohne Präfix; Gruppen-Termine mit 👥. Zusätzlich feste Farbkodierung pro Besitzer, damit jedes Mitglied als Gruppe lesbar ist. Version v33. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>- Gruppe: wählbares Emoji-Icon (groups.icon-Spalte + PUT /api/groups/{id}); wird in der Sidebar statt des Zahnrads angezeigt; Verwalten jetzt klares "⋯". Gruppe umbenennen möglich (war vorher gesperrt). - "Meine Kalender": der aktuell für Gruppen sichtbare Kalender wird mit 👥 gekennzeichnet. - Gruppenansicht: Gruppenkalender-Termine zeigen, wer sie hinzugefügt hat (👥 Vorname: Titel) und sind nach Ersteller eingefärbt; jeder kann weiterhin Termine im Gruppenkalender anlegen. Version v34. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>- Monatsmarker ("JUN") sitzt jetzt inline neben der Tageszahl ("1 JUN") statt darüber -> einheitliche Zeilenhöhe; Termine der Woche rutschen nicht mehr nach unten und überlappen nicht mehr mit "+X weitere". - Gruppenkalender erscheint in "Meine Kalender" (mit 👥-Markierung) und kann aus-/eingeblendet werden; Besitzer kann ihn umfärben. Recolor fremder Kalender abgefangen (nur Besitzer). Version v36. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>- Pro Mitglied eine Farbe (group_members.color, auto aus Palette, vom Owner oder Mitglied selbst änderbar via PUT /groups/{id}/members/{uid}/color). - Gruppentermin-Farbe = Farbe des Gruppenkalenders. - API liefert Farben aus: GET /groups & /groups/{id} (member.color, group_calendar_color), GET /groups/{id}/combined (display_color pro Event) -> Apps können dieselben Farben anzeigen. Test ergänzt (18 grün). - Web nutzt display_color; Gruppenkalender im Termin-Editor mit 👥 markiert (Gruppentermine ohne Gruppenansicht erstellbar); Mitglieder-Farben im Verwalten-Dialog editierbar. Version v37. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>The group-event icon + owner-name prefix was being done per-client (iOS only), so web/Android were inconsistent. The /groups/{id}/combined endpoint now emits a decorated `display_title` per event (group's own icon for group-calendar events, owner first-name for other members' events) while keeping the raw `title` for editing. All clients can render this identically. 18 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Findings from the security review: - HIGH: private local events leaked in full (title/location/description) to anyone who could READ a shared or group calendar via GET /api/caldav/events — the private_event_visibility rule was only enforced in /groups/{id}/combined. Now enforced in the merge read too, via a shared helper (apply_event_privacy) so the two paths can't drift. - HIGH: 'busy' masking was a blacklist that still leaked creator identity, source-calendar name, recurrence rule and per-event colour. Replaced with a whitelist (mask_busy_event): only timing/identity/render fields survive. - MEDIUM: .ics import had no size limit (raw = await file.read()) → memory DoS. Now capped at 5 MB (413), read before creating any calendar. - LOW/INFO: profile email now checked for uniqueness + basic format; display name / username / email length-capped and control-chars stripped. Deferred (tracked): RRULE expansion cap at the trust boundary, SQLite PRAGMA foreign_keys + ON DELETE cascade, and JWT-by-user-id + token version. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.