fix(caldav): move app-password section to Settings → Profile where users look
The app-password UI was in the user-menu profile modal, but users manage CalDAV in Settings, so it went unnoticed. Move the section into the Settings → Profile panel (next to account/privacy) and drive it from openSettingsModal via a top-level initAppPasswords(). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -716,6 +716,23 @@
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm" id="cfg-profile-save" data-i18n="save">Speichern</button>
|
||||
|
||||
<h4 class="panel-title" style="margin-top:24px" data-i18n="app_pw_title">App-Passwörter (CalDAV)</h4>
|
||||
<p class="panel-desc" data-i18n="app_pw_desc">Eigene Passwörter für CalDAV-Clients. Bei aktivem 2FA nötig, da Apps keinen 2FA-Code eingeben können. Jederzeit widerrufbar.</p>
|
||||
<div class="form-group app-pw-create">
|
||||
<input type="text" id="app-pw-label" data-i18n-placeholder="app_pw_label_ph" placeholder="Name (z.B. iPhone)" maxlength="100" />
|
||||
<button class="btn btn-primary btn-sm" id="app-pw-create-btn" data-i18n="app_pw_create">Erstellen</button>
|
||||
</div>
|
||||
<div id="app-pw-new" class="app-pw-new hidden">
|
||||
<label data-i18n="app_pw_new_label">Neues App-Passwort (nur jetzt sichtbar):</label>
|
||||
<div class="totp-secret-row">
|
||||
<code id="app-pw-new-value"></code>
|
||||
<button class="btn btn-ghost btn-sm" id="app-pw-copy" title="Kopieren">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-pw-list"></div>
|
||||
|
||||
<h4 class="panel-title" style="margin-top:24px" data-i18n="settings_privacy">Privatsphäre</h4>
|
||||
<p class="panel-desc" data-i18n="settings_private_visibility_desc">Wie private Termine für andere Gruppenmitglieder erscheinen</p>
|
||||
<div class="form-group">
|
||||
@@ -995,26 +1012,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- App passwords (CalDAV) -->
|
||||
<div class="settings-section">
|
||||
<h4 data-i18n="app_pw_title">App-Passwörter (CalDAV)</h4>
|
||||
<p class="text-muted" data-i18n="app_pw_desc">Eigene Passwörter für CalDAV-Clients. Bei aktivem 2FA nötig, da Apps keinen 2FA-Code eingeben können. Jederzeit widerrufbar.</p>
|
||||
<div class="form-group app-pw-create">
|
||||
<input type="text" id="app-pw-label" data-i18n-placeholder="app_pw_label_ph" placeholder="Name (z.B. iPhone)" maxlength="100" />
|
||||
<button class="btn btn-primary btn-sm" id="app-pw-create-btn" data-i18n="app_pw_create">Erstellen</button>
|
||||
</div>
|
||||
<div id="app-pw-new" class="app-pw-new hidden">
|
||||
<label data-i18n="app_pw_new_label">Neues App-Passwort (nur jetzt sichtbar):</label>
|
||||
<div class="totp-secret-row">
|
||||
<code id="app-pw-new-value"></code>
|
||||
<button class="btn btn-ghost btn-sm" id="app-pw-copy" title="Kopieren">
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="app-pw-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Calendars -->
|
||||
<div class="settings-section">
|
||||
<h4>Meine Kalender</h4>
|
||||
|
||||
@@ -3110,6 +3110,7 @@ function openSettingsModal() {
|
||||
api.get('/profile/').then(p => {
|
||||
document.getElementById('cfg-email').value = p.email || '';
|
||||
}).catch(() => {});
|
||||
initAppPasswords();
|
||||
|
||||
// Set active contrast/hour-height/duration buttons
|
||||
[
|
||||
@@ -4144,12 +4145,17 @@ function bindProfileModal() {
|
||||
document.getElementById('2fa-disable-pw').value = '';
|
||||
} catch (e) { showToast(e.message, true); }
|
||||
};
|
||||
}
|
||||
|
||||
// ── App passwords (CalDAV) ──
|
||||
// ── App passwords (CalDAV) — lives in Settings → Profile ──
|
||||
function initAppPasswords() {
|
||||
const appPwList = document.getElementById('app-pw-list');
|
||||
document.getElementById('app-pw-new').classList.add('hidden');
|
||||
if (!appPwList) return;
|
||||
const newBox = document.getElementById('app-pw-new');
|
||||
newBox.classList.add('hidden');
|
||||
document.getElementById('app-pw-new-value').textContent = '';
|
||||
async function loadAppPasswords() {
|
||||
|
||||
const load = async () => {
|
||||
try {
|
||||
const rows = await api.get('/profile/app-passwords');
|
||||
appPwList.innerHTML = rows.length
|
||||
@@ -4160,17 +4166,17 @@ function bindProfileModal() {
|
||||
</div>`).join('')
|
||||
: `<p class="text-muted">${t('app_pw_none')}</p>`;
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
loadAppPasswords();
|
||||
};
|
||||
load();
|
||||
|
||||
document.getElementById('app-pw-create-btn').onclick = async () => {
|
||||
const label = document.getElementById('app-pw-label').value.trim() || 'CalDAV';
|
||||
try {
|
||||
const res = await api.post('/profile/app-passwords', { label });
|
||||
document.getElementById('app-pw-new-value').textContent = res.password;
|
||||
document.getElementById('app-pw-new').classList.remove('hidden');
|
||||
newBox.classList.remove('hidden');
|
||||
document.getElementById('app-pw-label').value = '';
|
||||
loadAppPasswords();
|
||||
load();
|
||||
} catch (e) { showToast(e.message, true); }
|
||||
};
|
||||
|
||||
@@ -4185,7 +4191,7 @@ function bindProfileModal() {
|
||||
if (!confirm(t('app_pw_revoke_confirm'))) return;
|
||||
try {
|
||||
await api.delete(`/profile/app-passwords/${btn.dataset.id}`);
|
||||
loadAppPasswords();
|
||||
load();
|
||||
} catch (err) { showToast(err.message, true); }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
// Increment APP_VERSION with every code change
|
||||
export const APP_VERSION = 'v68';
|
||||
export const APP_VERSION = 'v69';
|
||||
|
||||
Reference in New Issue
Block a user