Kleine Verbesserungen und Teams, Outlook Integration
- Outlook: Kalender-Abo je Konto (eigene Aufgaben, Meilensteine, Abwesenheiten als .ics), einzurichten unter Einstellungen - Teams: Nachricht in einen Kanal bei neuen Aufgaben, mit Link direkt auf die Aufgabe; einzurichten unter Admin → Teams - Sitzungen nach Bedarf laden: beim Start nur die aktuelle und drei davor, im Verlauf „Weitere laden“ in Fünferschritten - Termin aus Mail: Wahl Aufgabe/Meilenstein, Notiz auch bei Meilensteinen, nur aktiv mit eingerichteter KI - Kalender zeigt die KW, auch statt der Browser-Datumsfelder - Pfeile bei den Abwesenheiten, kleinere Server-Korrekturen Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a2266662ad
commit
4c2e04e78b
19 files changed
+1100
-139
No files matched your search
@@ -1422,8 +1422,9 @@ step into a project explicit. Everything lives in `public/js/auftrag.js`:
|
||||
`renderPlanKommentarVerlauf()` in `plan-info.js`): je Gewerk nur, wenn
|
||||
sich der Text gegenüber der Sitzung davor geändert hat; gleicher Text in
|
||||
mehreren Gewerken einer Sitzung (Altbestand aus der Umstellung auf
|
||||
Kommentare je Gewerk) wird EIN Eintrag „HLS, ARCH“. Drei sichtbar, Rest
|
||||
über „Alle N anzeigen“. Keine neue Datenhaltung — jede Sitzung hält ihre
|
||||
Kommentare je Gewerk) wird EIN Eintrag „HLS, ARCH“. Gezeigt wird, was
|
||||
geladen ist, darunter „Weitere laden“ (siehe „Sitzungen nach Bedarf
|
||||
laden“). Keine neue Datenhaltung — jede Sitzung hält ihre
|
||||
Kopie des Projekts. Stile: Block „Kommentar der Sitzung mit Verlauf“ am
|
||||
Ende von `plan-styles.css`.
|
||||
**Eigene Kachel „Protokolle“** (Eriks Wunsch; links unter „Termine und
|
||||
@@ -1791,8 +1792,11 @@ step into a project explicit. Everything lives in `public/js/auftrag.js`:
|
||||
Eriks Wunsch: Mailtext per Drag & Drop (markierter Text oder ganze
|
||||
`.eml`-Datei) oder Strg+V (außerhalb von Eingabefeldern) auf die Bereiche
|
||||
**Terminplan** oder **Aufgaben** eines Projekts; eine KI macht daraus
|
||||
Einträge. **Nur Aufgaben, keine Meilensteine** — Eriks Vorgabe: Der
|
||||
Terminplan ist nur die grafische Darstellung der Aufgabenliste.
|
||||
Einträge — **Aufgabe oder Meilenstein**: Die KI schlägt die Art vor
|
||||
(`art` in `KI_MAIL_SCHEMA`), in der Auswahlliste `#mailAuswahlModal` (immer,
|
||||
auch bei nur einem Vorschlag) steht je Zeile der Umschalter
|
||||
„Aufgabe | Meilenstein“ (Eriks Wunsch). Danach öffnet sich je Eintrag das
|
||||
passende Panel.
|
||||
- Beim Hineinziehen erscheint die Fläche `#mailAblage` (fest, `pointer-events:
|
||||
none`, Zähler für dragenter/-leave). Nicht in gesperrten Sitzungen. Kein
|
||||
Konflikt mit dem Balken-Ziehen (das läuft über Maus-Ereignisse).
|
||||
@@ -1805,15 +1809,25 @@ Terminplan ist nur die grafische Darstellung der Aufgabenliste.
|
||||
„nächsten Freitag“ stimmt. Ohne KI/bei Fehler: ein Eintrag mit dem Betreff
|
||||
als Titel. **Speichert nichts.** `.msg` (Outlook) wird abgewiesen mit dem
|
||||
Hinweis, Text zu markieren.
|
||||
- **Nur mit eingerichteter KI aktiv** (Eriks Wunsch): `mailKiStatusLaden()`
|
||||
holt nach der Anmeldung (`afterAuthenticated()`) und nach jeder Änderung
|
||||
der KI-Zugangsdaten (`putMyAiKey()`) die Anbieter mit Schlüssel; ohne
|
||||
einen gibt es weder Ablagefläche noch abgefangenes Strg+V.
|
||||
- Anbieter: zuletzt erfolgreich genutzter (`localStorage
|
||||
projuebersicht-mail-ki`), sonst der erste mit Schlüssel.
|
||||
- Jeder Vorschlag öffnet das normale Aufgaben-Panel vorausgefüllt
|
||||
(`openTodoModal(null, prefill)`, neu: `title`, `aufwand`, `notiz`,
|
||||
`mailHinweis`, `nachSchliessen`); bei mehreren erst eine Auswahl
|
||||
(`#mailAuswahlModal`), dann nacheinander. Ohne Speichern entsteht nichts.
|
||||
- **Notiz je Aufgabe** (`t.notiz`, `plan_todos.notiz`, Migration
|
||||
`migrateAddPlanTodoNotiz()`, in `IMPORT_OPTIONAL_COLS`): Feld „Notiz“ im
|
||||
Aufgaben-Panel für jede Aufgabe; aus einer Mail mit Absender, Datum,
|
||||
- Umschalter „Aufgabe | Meilenstein“: eigene Stile `.segmented.mail-auswahl-art`
|
||||
und Klasse `mail-art-knopf` (sonst greift unter Glas
|
||||
`html.glas button:not([class])` mit Rand und Glanzkante, und der gewählte
|
||||
Knopf war von `var(--surface)` kaum zu unterscheiden).
|
||||
- Jeder gewählte Vorschlag öffnet nacheinander das normale Panel
|
||||
vorausgefüllt: `openTodoModal(null, prefill)` (`title`, `start`/`end`,
|
||||
`assignees`, `aufwand`, `notiz`, `mailHinweis`, `nachSchliessen`) bzw.
|
||||
`openMilestoneModal(null, prefill)` (`name`, `date` = Ende des Vorschlags,
|
||||
`notiz`, `mailHinweis`, `nachSchliessen`). Ohne Speichern entsteht nichts.
|
||||
- **Notiz je Aufgabe und Meilenstein** (`t.notiz`/`m.notiz`,
|
||||
`plan_todos.notiz`/`plan_milestones.notiz`, Migration
|
||||
`migrateAddPlanTodoNotiz()`, in `IMPORT_OPTIONAL_COLS`): Feld „Notiz“ in
|
||||
beiden Panels; aus einer Mail mit Absender, Datum,
|
||||
Betreff, Bezugssatz und Mailtext. In der Aufgabenliste ein Symbol mit
|
||||
Tooltip. Stile: Block „Termin aus Mail“ am Ende von `plan-styles.css`.
|
||||
|
||||
@@ -3458,8 +3472,8 @@ nur, wenn sich der Kommentar DES GEWÄHLTEN GEWERKS gegenüber der Sitzung davor
|
||||
geändert hat; Sitzungen dazwischen als grauer Vermerk („KW 40 bis KW 43 ohne
|
||||
neuen Kommentar“); geänderte Leistungsphasen seit dem vorigen Eintrag als
|
||||
Chips („LPH 5: 60 → 75 %“); Verfasser und Datum; „übernehmen“
|
||||
(`berichtVerlaufUebernehmen()` → `takeCommentFromHistory()`); drei
|
||||
sichtbar, Rest über „Alle N anzeigen“ (`berichtVerlaufUmschalten()` zeichnet
|
||||
(`berichtVerlaufUebernehmen()` → `takeCommentFromHistory()`); gezeigt wird,
|
||||
was geladen ist, „Weitere laden“ holt ältere (`berichtVerlaufNeu()` zeichnet
|
||||
nur den Abschnitt neu, ein angefangener Kommentar bleibt). Die dichte Karte
|
||||
bekommt dafür `opts.ohneVerlauf` (`renderBoardDrawer()`), damit der
|
||||
Kachel-Streifen dort nicht zusätzlich erscheint. Projektliste und
|
||||
@@ -4168,6 +4182,94 @@ across Gewerke or users. Erik's own words: "macht so keinen Sinn mehr."
|
||||
no special-casing needed. A redirect `GET /Test.html`-style old link isn't
|
||||
needed here since nothing ever pointed at this tab before it existed.
|
||||
|
||||
## Kalender-Abo für Outlook (iCalendar)
|
||||
|
||||
Eriks Wunsch: die eigenen Termine in Outlook sehen, nur zum Lesen.
|
||||
Einstellungen → Mein Konto → Karte „Kalender in Outlook“
|
||||
(`renderSettingsKalender()`, `js/settings/settings.js`): Adresse erzeugen,
|
||||
kopieren, „In Outlook öffnen“ (`webcal:`-Link), Anleitung, „Neue Adresse“
|
||||
(alte wird ungültig), „Abschalten“.
|
||||
- **Server:** `users.kalender_token` (Migration in `migrateUsersDepartment()`,
|
||||
leer = aus). `GET`/`POST /mein-kalender` (requireAuth, nur eigenes Konto;
|
||||
POST `{aus:true}` schaltet ab, sonst neue Adresse). **`GET
|
||||
/kalender/<token>.ics` ist ohne Sitzung erreichbar** — der Token (24 Byte
|
||||
zufällig) IST die Anmeldung, weil Outlook sich nicht einloggen kann.
|
||||
Unbekannt, deaktiviertes Konto oder Rolle ohne „Anwendung nutzen“ → 404.
|
||||
- **Inhalt** (`kalenderEreignisse()`, rein und testbar): aus der jüngsten
|
||||
echten Sitzung die eigenen offenen Aufgaben mit Termin (ohne erledigte und
|
||||
ohne Phasenbalken), Meilensteine der Projekte, denen man zugeordnet ist
|
||||
oder in denen man eine eigene Aufgabe hat, dazu die eigenen
|
||||
Abwesenheiten. Alles ganztägig (`VALUE=DATE`, DTEND = Tag danach), als
|
||||
„frei“ (Abwesenheit „abwesend“). Notizen gehen in die Beschreibung.
|
||||
`kalenderText()` maskiert nach RFC 5545 und faltet Zeilen auf 75 Byte.
|
||||
- **Adresse** (`kalenderUrl()`): der Host, über den der Browser die App
|
||||
aufruft — wer über `localhost` öffnet, bekommt eine `localhost`-Adresse
|
||||
(eine automatische Ersetzung durch die Geräte-IP hat Erik verworfen, weil
|
||||
sie im Docker-Container nicht verlässlich ist).
|
||||
- **Grenze:** Neues Outlook / Outlook im Browser holen das Abo über
|
||||
Microsoft-Server aus dem Internet ab — dafür muss der Server von außen
|
||||
erreichbar sein. Das klassische Outlook am PC holt es im Firmennetz direkt.
|
||||
|
||||
## Teams: Nachricht bei neuen Aufgaben
|
||||
|
||||
Eriks Wunsch: Wird jemandem eine Aufgabe zugewiesen, erscheint in einem
|
||||
Teams-Kanal eine Karte mit Link direkt auf die Aufgabe.
|
||||
- **Einrichten:** In Teams im Kanal *Workflows* → „Beim Empfang einer
|
||||
Webhook-Anfrage in einem Kanal posten“; die erzeugte https-Adresse unter
|
||||
**Admin → Teams** eintragen (`loadAdminTeams()`, `js/admin/admin.js`,
|
||||
Recht **`a.teams`**, neu im Katalog „Admin-Bereich“), „Testnachricht
|
||||
senden“. Anleitung steht aufklappbar in der Karte.
|
||||
- **Speicher:** Tabelle `integrationen` (schluessel/wert; `teams_webhook`,
|
||||
`teams_neue_aufgaben`), bewusst NICHT `app_settings` (das darf jedes
|
||||
Konto lesen) und nicht in `IMPORT_TABLES`. Die Adresse geht nie an den
|
||||
Browser zurück — `GET /admin/teams` liefert nur `konfiguriert`/`host`.
|
||||
`PUT /admin/teams {webhook?, neueAufgaben?}` (nur https), `POST
|
||||
/admin/teams/test` (Fehler als `{ok:false}` mit HTTP 200).
|
||||
- **Auslöser:** `neueZuweisungenMelden()` (aus `/save-week` und
|
||||
`/save-projects`, jetzt mit `req`) sammelt je Aufgabe die NEU Zuständigen
|
||||
— auch Personen ohne Konto, nicht wer sich selbst zuweist, keine
|
||||
Phasenbalken, nie die Sandbox — und `teamsNeueAufgaben()` schickt je
|
||||
Aufgabe EINE Adaptive Card (`teamsKarte()`: Titel, Projekt, Zuständig,
|
||||
Fällig/Zeitraum, Aufwand, Zugewiesen von, Knopf „Aufgabe öffnen“). Im
|
||||
Hintergrund; Fehler nur im Log, das Speichern scheitert nie daran.
|
||||
- **Link** (`aufgabenLink()`): `/Projektplan/<Name>?weekLabel=…&projNr=…
|
||||
&aufgabe=<todoId>#aufgaben`, Host aus der speichernden Anfrage (= Adresse
|
||||
der App im Büro; funktioniert nur im Büronetz/VPN). Im Browser liest
|
||||
`plan-state.js` `aufgabe` beim Laden (`startAufgabe`): öffnet die
|
||||
JÜNGSTE Sitzung, falls der Link eine ältere nennt (Aufgaben-ids bleiben
|
||||
beim Sitzungswechsel gleich), springt nach „Aufgaben“ und öffnet das
|
||||
Aufgaben-Panel; Adresszeile wird nachgezogen.
|
||||
- Braucht Internetzugang nach außen (Microsoft-Server).
|
||||
|
||||
## Sitzungen nach Bedarf laden (`js/store.js`)
|
||||
|
||||
Eriks Wunsch: `/load-all` wuchs jede Woche (alle Sitzungen, ~17 KB je
|
||||
Woche). Jetzt lädt der Browser beim Start nur die jüngsten
|
||||
`SITZUNGEN_START` (4: aktuelle + drei davor) über `GET /load-all?wochen=4`;
|
||||
dieselbe Antwort trägt `wochenListe` = ALLE echten Sitzungen schlank
|
||||
(`{id, label, date, locked, updatedAt}`, `echteSitzungenSortiert()`), im
|
||||
Browser `db.wochenListe`. **`db.weeks` hält damit nur die GELADENEN
|
||||
Sitzungen** — wer über `db.weeks` iteriert, sieht nicht alle.
|
||||
- **Verlauf** (Wochenbericht „Verlauf der Vorwochen“, Kommentar-Verlauf im
|
||||
Projekt-Dashboard, Verlauf-Kacheln der Projektliste): zeigt, was geladen
|
||||
ist; darunter `weitereLadenKnopf()` → `weitereSitzungenLaden()` →
|
||||
`GET /weeks-aelter?vor=<älteste geladene>&anzahl=5` holt je
|
||||
`SITZUNGEN_NACHLADEN` (5) ältere. Die früheren Knöpfe „Alle N anzeigen“
|
||||
sind entfallen. Der Wochenbericht zeichnet danach nur den Verlauf neu
|
||||
(`berichtVerlaufNeu()`), damit ein angefangener Kommentar bleibt; der
|
||||
Kachel-Verlauf merkt sich, ob er aufgeklappt war (`verlaufOffen`).
|
||||
- **Nicht geladene Sitzungen bei Bedarf**: `sitzungSicherLaden(label)` (über
|
||||
`GET /week`). Genutzt von Admin → Sitzungen (Liste aus `adminSitzungen()`
|
||||
= alle; Entsperren/Öffnen/Löschen/Sperren nehmen jetzt das Label) und von
|
||||
`openPlanView()` bei einem Link auf ein Projekt einer älteren Sitzung.
|
||||
- Live: Ein Ereignis zu einer nicht geladenen Sitzung zieht nur deren Eintrag
|
||||
in `db.wochenListe` nach, statt alles neu zu laden. `deleteWeekById()`
|
||||
zählt für „mindestens eine Sitzung“ die `wochenListe`.
|
||||
- `/load-all` ohne `wochen` liefert weiterhin alles (ältere Browser-Stände).
|
||||
`loadWeeks()` nimmt dafür auch eine Liste von Labels (`IN (…)`).
|
||||
- Gemessen: 98 KB statt 158 KB bei 9 Sitzungen; bleibt künftig etwa gleich,
|
||||
statt mit jeder Woche zu wachsen.
|
||||
|
||||
## Gleichzeitiges Arbeiten (Zusammenführen statt Verwerfen, `js/store.js`)
|
||||
|
||||
Eine Sitzung wird weiterhin als Ganzes über `POST /save-week` mit
|
||||
@@ -4324,6 +4426,17 @@ Rechner.
|
||||
kein `backdrop-filter` — eigenes Design, Kiosk-Rechner) und
|
||||
`prefers-reduced-transparency` (deckende Flächen).
|
||||
|
||||
## Datums-Kalender mit KW (`js/date-picker.js`)
|
||||
|
||||
Eriks Wunsch: Jeder Kalender beim Anlegen/Bearbeiten zeigt die
|
||||
Kalenderwoche. `renderRangePicker()` hat eine erste Spalte „KW“
|
||||
(`getWeekNumber()`, `.range-picker-kw`, Popup 316px breit). Native
|
||||
`<input type="date">` (Feiertage, Abwesenheiten in der Benutzerverwaltung,
|
||||
„Aufgabe aus Kommentar“, Assistent, TODOs aus Protokoll) öffnen über einen
|
||||
globalen Klick-Abfänger denselben Kalender statt des Browser-Kalenders; der
|
||||
Wert wird ins Feld geschrieben und `input`/`change` ausgelöst. Ausnahme per
|
||||
Attribut `data-nativ`.
|
||||
|
||||
## Dunkelmodus nachgeschärft (Kalender, Sitzungskommentar)
|
||||
|
||||
Eriks Wahl „A“ aus einem Kontrast-Vergleich; Block „DUNKELMODUS
|
||||
@@ -4460,8 +4573,8 @@ Speicherüberlauf. Vier Ebenen, jede fängt ab, was die darüber verpasst:
|
||||
(`wlan-energiesparen-aus.service`), `wlan-waechter.timer` jede Minute —
|
||||
ohne Gateway ab 2 min neu verbinden, nach 10 min `systemctl reboot`.
|
||||
- **Prüfen:** `Docker/pi-pruefen.sh` (Speicher, Neustarts, OOM, Strom).
|
||||
- Offen (Schritt 4 des Plans): `/load-all` liefert weiter ALLE Sitzungen —
|
||||
wächst wöchentlich auf Server und Browser.
|
||||
- **Sitzungen nach Bedarf** (Schritt 4, umgesetzt 30.10.2026): siehe
|
||||
„Sitzungen nach Bedarf laden“ unten.
|
||||
|
||||
## Docker
|
||||
|
||||
|
||||
Reference in new issue
Block a user