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:
erikandClaude Opus 5.5 committed 2026-10-30 08:23:02 +01:00
1 parent a2266662ad
commit 4c2e04e78b
19 files changed
+1100 -139

No files matched your search

+27 -3
View File
@@ -40,7 +40,7 @@ function openDatePicker(opts){
document.body.appendChild(pop);
const anchorRect = opts.anchor ? opts.anchor.getBoundingClientRect() : { left: window.innerWidth/2 - 140, bottom: window.innerHeight/2 - 160 };
pop.style.left = Math.max(8, Math.min(anchorRect.left, window.innerWidth - 296)) + 'px';
pop.style.left = Math.max(8, Math.min(anchorRect.left, window.innerWidth - 332)) + 'px';
pop.style.top = Math.min(anchorRect.bottom + 6, window.innerHeight - 340) + 'px';
renderRangePicker();
@@ -80,7 +80,7 @@ function openRangePicker(opts){
// Position: unterhalb des Ankers, innerhalb des Viewports halten
const anchorRect = opts.anchor ? opts.anchor.getBoundingClientRect() : { left: window.innerWidth/2 - 140, bottom: window.innerHeight/2 - 160 };
pop.style.left = Math.max(8, Math.min(anchorRect.left, window.innerWidth - 296)) + 'px';
pop.style.left = Math.max(8, Math.min(anchorRect.left, window.innerWidth - 332)) + 'px';
pop.style.top = Math.min(anchorRect.bottom + 6, window.innerHeight - 340) + 'px';
renderRangePicker();
@@ -160,6 +160,14 @@ function applyRangePicker(){
const selected = start || end;
if(startInput) startInput.value = isSingle ? (selected ? formatDateISO(selected) : '') : (start ? formatDateISO(start) : '');
if(endInput) endInput.value = end ? formatDateISO(end) : (start ? formatDateISO(start) : '');
// Für umgeleitete native Datumsfelder (siehe unten): deren onchange/
// oninput-Handler sollen wie bei einer Eingabe von Hand laufen.
[startInput, endInput].forEach(el => {
if(el && el.type === 'date'){
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
}
});
if(opts.displayId){
const disp = document.getElementById(opts.displayId);
if(disp){
@@ -199,10 +207,15 @@ function renderRangePicker(){
</div>
<div class="range-picker-hint">${hint}</div>
<div class="range-picker-grid">`;
// Erste Spalte: Kalenderwoche (Eriks Wunsch — im Büro wird in KW gedacht).
html += '<div class="range-picker-weekday range-picker-kw-kopf">KW</div>';
['Mo','Di','Mi','Do','Fr','Sa','So'].forEach(w => html += `<div class="range-picker-weekday">${w}</div>`);
const kwZelle = d => `<div class="range-picker-kw">${getWeekNumber(d)}</div>`;
if(firstWeekday > 0) html += kwZelle(first);
for(let i = 0; i < firstWeekday; i++) html += '<div></div>';
for(let day = 1; day <= daysInMonth; day++){
const d = new Date(st.viewYear, st.viewMonth, day);
if(d.getDay() === 1) html += kwZelle(d);
const iso = formatDateISO(d);
const classes = ['range-picker-day'];
if(d.getDay() === 0 || d.getDay() === 6) classes.push('weekend');
@@ -218,4 +231,15 @@ function renderRangePicker(){
${st.mode !== 'single' && st.start && !st.end ? '<button type="button" class="small" onclick="rangePickerState.end = rangePickerState.start; applyRangePicker()">Nur dieser Tag</button>' : ''}
</div>`;
pop.innerHTML = html;
}
}
// Native Datumsfelder (<input type="date">) öffnen statt des Browser-
// Kalenders (kennt keine KW) denselben Kalender wie der Rest der App. Das
// Feld selbst bleibt — Tippen funktioniert weiter, der Picker schreibt den
// ISO-Wert hinein und löst input/change aus. Ausnahme: data-nativ.
document.addEventListener('click', e => {
const input = e.target && e.target.closest ? e.target.closest('input[type="date"]') : null;
if(!input || input.disabled || input.readOnly || input.hasAttribute('data-nativ')) return;
e.preventDefault();
if(!input.id) input.id = 'datum_' + Math.random().toString(36).slice(2, 9);
openDatePicker({ anchor: input, inputId: input.id });
}, true);