Commit Graph
29 Commits
Author SHA1 Message Date
Guido Schmit b1b08072e7 fix: Termine in unchecked Kalendern erstellen + HA-Kalender als Kopier-Ziel
- populateCalendarSelect: filtert jetzt nach !sidebar_hidden statt
  enabled. Unchecked (versteckte) Kalender bleiben so im
  Termin-erstellen-Dropdown verfügbar
- buildWritableCalendars: HA-Kalender werden als Kopier-Ziele aufgeführt
- copyEventToCalendar: routet HA-Ziele über /homeassistant/events
  Endpoint (vorher fielen sie in den CalDAV-Fallback)
2026-05-05 17:46:12 +02:00
Guido Schmit b961cf94ef fix: CalDAV-Events bekommen source-Feld – Kalenderfarbe-Patch wirkt sofort
CalDAV-Events hatten bisher kein source-Feld gesetzt. applyCalendarColor
filtert aber via ev.source !== 'caldav', sodass der Patch nie auf
CalDAV-Events angewendet wurde – die Farbe blieb sichtbar bis F5.
Jetzt wird source: 'caldav' beim Anreichern der Events gesetzt.
2026-04-29 20:27:31 +02:00
Guido Schmit dce9890bfa fix: Termin-Änderungen (Farbe, Titel, etc.) sofort ohne Reload anzeigen
Nach dem Speichern eines Termins wird das gecachte Event-Objekt
direkt in-place gepatcht und die View neu gerendert. Vorher war die
neue Farbe erst nach F5 sichtbar, weil zwar fetchAndRender(true)
aufgerufen wurde, aber der Render-Pfad das Update nicht zuverlässig
übernommen hat.
2026-04-29 20:22:34 +02:00
Guido Schmit 98870ccfb3 feat: HA-Events über WebSocket API (calendar/event/delete und update)
Manche HA-Integrationen registrieren nur den WebSocket-Handler, keinen
Service-Call. Die HA-Web-UI nutzt deshalb den WebSocket-Pfad. Calendarr
macht das jetzt auch:
- _ha_ws_call: minimaler WebSocket-Client für eine einzelne Command
- create: erst WS, dann Service-Call als Fallback
- update: nur WS (Service-Call existiert oft nicht)
- delete: nur WS (Service-Call existiert oft nicht)
Neue Dependency: websocket-client==1.8.0
2026-04-29 20:01:12 +02:00
Guido Schmit 1f010078d3 fix: HA Delete – mehrere Body-Formate ausprobieren
HA's Service-Call-Schema akzeptiert je nach Version verschiedene
Body-Shapes für entity_id. Wir probieren jetzt der Reihe nach:
1. entity_id als String
2. entity_id als Liste
3. target-Wrapper
Wenn alle fehlschlagen, klare Anweisung zum HA-Developer-Tools-Test.
2026-04-29 19:58:56 +02:00
Guido Schmit 80cde5aaee fix: HA Delete – Fallback auf REST DELETE und klarere Fehlermeldung
calendar.delete_event schlägt mit 400 fehl, wenn die HA-Integration
das Feature nicht unterstützt (z.B. Google-Calendar via HA hat nur
CREATE_EVENT, kein DELETE/UPDATE).
- Versucht erst Service-Call, dann REST DELETE als Fallback
- Bei 400 wird der User aufgeklärt, dass die Integration vermutlich
  kein Löschen unterstützt
2026-04-29 19:55:04 +02:00
Guido Schmit 0ea0a530f6 fix: HA Datetime-Format mit Timezone, leere Strings filtern, Debug-Logs
- _ha_format_dt: Parst ISO-Datetime zu datetime-Objekt, emittiert
  ohne Millisekunden, MIT Timezone-Offset. Vorher landeten Termine
  am falschen Datum, weil das Frontend UTC schickt aber wir die
  Timezone gestrippt haben → HA hat als lokale Zeit interpretiert
- Leere Strings werden nicht mehr in den Body aufgenommen (HA
  Validator könnte diese ablehnen)
- Logging in create/delete/update für besseres Debugging der HA-Calls
2026-04-29 19:50:52 +02:00
Guido Schmit 7047f55cf7 feat: HA-Termine erstellen über calendar.create_event Service
- POST /api/homeassistant/events Endpoint mit calendar.create_event
- Frontend: HA-Termine erstellen statt 'nicht unterstützt' Toast
- Datetime-Format an HA-Konvention angepasst:
  'YYYY-MM-DD HH:MM:SS' (Space-Separator, ohne Timezone)
- _ha_format_dt Helper für ISO → HA Datetime-Konvertierung
2026-04-29 19:07:02 +02:00
Guido Schmit d859e969d0 fix: HA-Event-Update Fallback auf delete+create
calendar.update_event existiert erst ab HA 2024.6. Wenn der Service
nicht verfügbar ist (400), wird stattdessen delete_event + create_event
verwendet. Funktioniert mit HA 2022.5+.
2026-04-29 18:54:33 +02:00
Guido Schmit f970276b91 fix: HA update_event – bessere Fehlermeldung mit JSON-Response-Details
Liest message-Feld aus HA JSON-Response und loggt den Request-Body
für Debugging
2026-04-29 18:52:32 +02:00
Guido Schmit 4964dcf7f3 fix: HA Service-Call Parameter-Format korrigiert
- update_event: start_date_time/end_date_time statt dtstart/dtend
- Ganztägig: start_date/end_date statt dtstart/dtend
- Datetime-Werte als ISO-String mit Timezone statt space-separated
- Bessere Fehlermeldungen: HA-Response-Body wird im Error angezeigt
2026-04-29 18:50:00 +02:00
Guido Schmit 86fa07d18c fix: HA-Events über Service-Call API statt nicht-existierender REST-Endpoints
PUT/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+)
2026-04-29 18:45:24 +02:00
Guido Schmit 59f53b5524 fix: HA-Event-Update URL-Encoding und Popup-Überlappung bei Lösch-Dialog
- HA Update/Delete: UID wird URL-encoded (@ → %40), Delete mit
  Fallback auf Service-Call API für ältere HA-Versionen
- Lösch-Dialog: Event-Popup wird geschlossen BEVOR der Bestätigungsdialog
  erscheint, kein Überlappen mehr
2026-04-29 18:38:43 +02:00
Guido Schmit e5265b3694 fix: HA-Events bearbeitbar, Selected≠Today Styling, Serien-Löschung
- HA-Events: Update/Delete-Endpoints via HA REST API implementiert
- HA read-only Guard entfernt, stattdessen korrekte API-Anbindung
- Selected-Day: Outline-Ring statt gefüllter Kreis (Today bleibt gefüllt)
- Serien-Löschung: RECURRENCE-ID aus CalDAV-Events erkennen, damit
  expandierte Serientermine als recurring markiert werden und der
  Lösch-Dialog Einzel-/Serienlöschung anbietet
2026-04-29 18:31:58 +02:00
Guido Schmit 3e204d3355 fix: CalDAV-Update DTSTART-Fehler und HA-Events read-only
- caldav_client: del+add statt direkter Zuweisung bei VEVENT-Properties
  (behebt "DTSTART MUST appear exactly once" Validierungsfehler)
- HA-Events als read-only behandeln (kein Bearbeiten/Löschen im Popup)
- [object Object] Toast behoben: HA-Events fallen nicht mehr in CalDAV-Pfad
2026-04-29 18:21:56 +02:00
Guido Schmit 1638c9f631 fix: Runde-2-Fixes – Monatsauswahl, CalDAV-Update, Lösch-Dialog, EXDATE
- Monatsansicht: selectedDate von currentDate getrennt, Klick verschiebt View nicht mehr
- Selected-Day Styling: weißer Text auf Primary-Hintergrund statt nur Textfarbe
- Kontextmenü: --bg-surface statt fehlendem --bg-card
- CalDAV Update/Delete: parent Calendar-Objekt übergeben (behebt NoneType-Fehler)
- HA-Kalender im Kalender-Selektor ergänzt
- Browser-confirm() durch styled Modal-Dialog ersetzt mit Serie/Einzeln-Option
- EXDATE-Support: einzelne Vorkommen wiederkehrender Termine löschen (lokal + CalDAV)
- Fehlende i18n-Keys für Lösch-Dialog ergänzt (DE + EN)
2026-04-29 18:13:12 +02:00
Guido Schmit 013fb3dbc2 feat: Datum-Validierung, Monatsauswahl, CalDAV-Fix, wiederkehrende Termine
- End-Datum passt sich automatisch an wenn Start geändert wird (Duration bleibt erhalten)
- Erstellen-Button nutzt den aktuell angesehenen Tag statt immer heute
- Monatsansicht: Einzelklick = Tag auswählen, Doppelklick = Tagesansicht, Rechtsklick = Kontextmenü
- CalDAV URL-Matching robuster (Normalisierung, Path-Fallback, calendar_id Parameter)
- iCal-Abo-Termine sind nicht mehr bearbeitbar (Read-Only-Schutz)
- Wiederkehrende Termine mit RRULE-Support (täglich/wöchentlich/monatlich/jährlich/benutzerdefiniert)
2026-04-29 17:49:03 +02:00
Guido Schmit 7f123de148 fix: Tint für mehrtägige Ganztags-Events korrekt via alldayLayout
Der bisherige multiDayAllDayEvs-Filter hatte einen Timezone-Fehler
bei der Datumsberechnung (UTC-Parsing vs. lokale Zeit in UTC+2).
Neue Lösung: das bereits korrekt arbeitende alldayLayout wird direkt
als Quelle verwendet. Items mit colEnd > colStart sind mehrtägig —
die Spaltenindizes aus dem Layout ergeben den Tint-Bereich exakt.
2026-04-08 22:24:05 +02:00
Guido Schmit a362ab21ae perf/fix: Kalender-Toggle ohne Ladescreen + Mehrfach-Tint als Verlauf
Ausblenden: Events werden sofort client-seitig aus dem Cache gefiltert
(calendar_id-Match), kein Netzwerkaufruf für die Ansicht nötig.
Einblenden: fetchAndRender(force, silent=true) überspringt showLoading(),
die aktuelle Ansicht bleibt sichtbar und wird nach dem Fetch aktualisiert.
Mehrere mehrtägige Events am selben Tag erzeugen jetzt einen vertikalen
Farbverlauf (linear-gradient) statt gestapelter Ebenen, bei denen nur
die letzte Farbe sichtbar war.
2026-04-08 22:14:08 +02:00
Guido Schmit 15c540bd25 fix: Kalender-Toggle sofort wirksam + Tint für mehrtägige Ganztags-Events
- fetchAndRender(true) beim Ein-/Ausblenden eines Kalenders erzwingt
  einen Neu-Abruf statt Cache-Treffer, damit die Änderung sofort sichtbar ist
- Tint-Berechnung in der Wochenansicht berücksichtigt jetzt auch
  mehrtägige Ganztags-Events (z.B. Urlaub), nicht nur mehrtägige
  Termin-Events — exclusive Enddaten werden dabei korrekt normalisiert
2026-04-08 21:59:41 +02:00
Guido Schmit f2da15784b fix: Wochenkalender-Filter und per-Kalender Fehlerbehandlung
Der Wochenkalender von Google hat locale-spezifische IDs
(z.B. de.german#weeknum@...) die nicht im alten exakten Set-Filter
gefangen wurden. Dadurch wurde er in die DB gespeichert und
verursachte beim Event-Abruf einen API-Fehler.
Da der try/except die gesamte Kalender-Schleife umschloss, wurden
bei einem einzigen fehlerhaften Kalender alle anderen Events ebenfalls
verloren — Ursache für keine Termine trotz korrektem Token.
- _is_system_calendar(): prüft jetzt auch 'weeknum' als Substring
- _sync_google_calendars(): bereinigt bereits gespeicherte System-Kalender
- get_google_events(): try/except ist jetzt pro Kalender, nicht global
2026-04-08 21:49:24 +02:00
Guido Schmit 62e7fa8be1 fix: Google-Token-Fehler wird sichtbar gemacht und dem User gemeldet
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.
2026-04-08 21:40:13 +02:00
Guido Schmit 3846af527a fix: Kalenderfarbe wird sofort ohne Reload aktualisiert
Statt nach Farbänderung den Cache zu invalidieren und neu zu laden,
wird calendarColor direkt in-place auf allen gecachten Events gepatcht
und dann nur renderView() aufgerufen. Kein Netzwerk-Request, sofortige
Darstellung der neuen Farbe.
2026-04-07 22:18:10 +02:00
Guido Schmit 59751349b7 perf: Sliding-window Cache — Hintergrund-Prefetch bei Cache-Randnähe
Wenn die aktuelle Ansicht weniger als 4 Wochen vom Cache-Rand entfernt
ist, werden im Hintergrund 8 weitere Wochen in diese Richtung geladen
und in den Cache gemergt. Der Cache wächst damit automatisch mit der
Navigation mit — kein sichtbarer Ladevorgang auch bei langen Sprüngen.
2026-04-07 22:09:11 +02:00
Guido Schmit bc93474f49 perf: Event cache mit ±8-Wochen-Puffer für schnelle Navigation
Beim ersten Laden wird ein Fenster von ±8 Wochen um die aktuelle
Ansicht geholt. Wochenweise Navigation trifft danach den Cache
sofort (kein Spinner, kein Netzwerk). Nach echten Datenänderungen
(Event speichern/löschen, Sync, Konto-Änderungen) wird der Cache
invalidiert und neu geladen.
2026-04-07 22:05:03 +02:00
Guido Schmit 62ac0162eb feat: Rolling 5-week month view with week-by-week scroll
Month view now shows 5 weeks starting from the week containing
currentDate (not fixed to month boundaries), enabling views like
"mid-April to mid-May". Prev/Next buttons jump 4 weeks; mouse
wheel scrolls 1 week at a time with 500ms debounce.
2026-04-07 21:58:51 +02:00
Guido Schmit 46f6765087 fix: Month scroll navigates by full month, not by week
Scrolling in month view was moving currentDate by 7 days, but the
grid always renders the complete month — so 4 scrolls were needed
before any visual change. Now each scroll step advances/retreats
by exactly one month (same as the prev/next buttons).
2026-04-07 21:51:15 +02:00
Guido Schmit e2f98520e2 fix: Month grid lines, scroll throttle, custom dark date/time picker
- Month view: Replaced day-strip+events-area with full-height column
  divs (.month-col) so borders extend the full row height and clicking
  anywhere in a day column (including below events) navigates to day view.
  Events overlay uses pointer-events:none (pass-through) while span bars
  and +N-more labels stay pointer-events:all.
- Scroll navigation: Changed wheel handler from 80ms debounce to 500ms
  leading-edge throttle — one navigation per trackpad gesture.
- Custom date/time picker (date-picker.js): Dark calendar grid with
  prev/next navigation, today/selected highlighting, and a CSS
  scroll-snap time scroller (hours 0-23, minutes 0-59) matching the
  app's primary color. Language-aware (month names, day headers via t()).
- Event modal datetime inputs replaced with hidden inputs + .dt-display
  click targets that open the custom picker. setDtValue() helper keeps
  hidden input and display label in sync.
2026-04-07 21:44:44 +02:00
Guido Schmit 94cbe4e7fb feat: Spanning event bars, wheel nav, dark datetime picker, segmented settings UI
- Month view: Multi-day events render as continuous Google Calendar-style
  spanning bars across days/weeks using a greedy lane-packing algorithm.
  Timed multi-day events no longer repeat per day.
- Mouse wheel / trackpad scrolls week-by-week in month view, day/week in
  other views (debounced, prevents default page scroll).
- datetime-local/date inputs now use color-scheme:dark so the native
  browser picker opens in dark mode; calendar icon styled to match.
- Contrast/hour-height selectors redesigned as connected segmented pill
  controls instead of individual tiles.
- Hidden calendars list gains proper padding and separator lines.
- "Google Konten" settings panel renamed "Konten" and expanded to show
  CalDAV, local calendars, iCal subscriptions, and Google accounts in
  one unified panel with sync/disconnect actions.
- New i18n keys added for accounts panel in both de and en.
2026-04-07 21:20:42 +02:00