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>
|
</div>
|
||||||
<button class="btn btn-primary btn-sm" id="cfg-profile-save" data-i18n="save">Speichern</button>
|
<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>
|
<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>
|
<p class="panel-desc" data-i18n="settings_private_visibility_desc">Wie private Termine für andere Gruppenmitglieder erscheinen</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -995,26 +1012,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- Calendars -->
|
||||||
<div class="settings-section">
|
<div class="settings-section">
|
||||||
<h4>Meine Kalender</h4>
|
<h4>Meine Kalender</h4>
|
||||||
|
|||||||
@@ -3110,6 +3110,7 @@ function openSettingsModal() {
|
|||||||
api.get('/profile/').then(p => {
|
api.get('/profile/').then(p => {
|
||||||
document.getElementById('cfg-email').value = p.email || '';
|
document.getElementById('cfg-email').value = p.email || '';
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
|
initAppPasswords();
|
||||||
|
|
||||||
// Set active contrast/hour-height/duration buttons
|
// Set active contrast/hour-height/duration buttons
|
||||||
[
|
[
|
||||||
@@ -4144,12 +4145,17 @@ function bindProfileModal() {
|
|||||||
document.getElementById('2fa-disable-pw').value = '';
|
document.getElementById('2fa-disable-pw').value = '';
|
||||||
} catch (e) { showToast(e.message, true); }
|
} 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');
|
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 = '';
|
document.getElementById('app-pw-new-value').textContent = '';
|
||||||
async function loadAppPasswords() {
|
|
||||||
|
const load = async () => {
|
||||||
try {
|
try {
|
||||||
const rows = await api.get('/profile/app-passwords');
|
const rows = await api.get('/profile/app-passwords');
|
||||||
appPwList.innerHTML = rows.length
|
appPwList.innerHTML = rows.length
|
||||||
@@ -4160,17 +4166,17 @@ function bindProfileModal() {
|
|||||||
</div>`).join('')
|
</div>`).join('')
|
||||||
: `<p class="text-muted">${t('app_pw_none')}</p>`;
|
: `<p class="text-muted">${t('app_pw_none')}</p>`;
|
||||||
} catch (e) { /* ignore */ }
|
} catch (e) { /* ignore */ }
|
||||||
}
|
};
|
||||||
loadAppPasswords();
|
load();
|
||||||
|
|
||||||
document.getElementById('app-pw-create-btn').onclick = async () => {
|
document.getElementById('app-pw-create-btn').onclick = async () => {
|
||||||
const label = document.getElementById('app-pw-label').value.trim() || 'CalDAV';
|
const label = document.getElementById('app-pw-label').value.trim() || 'CalDAV';
|
||||||
try {
|
try {
|
||||||
const res = await api.post('/profile/app-passwords', { label });
|
const res = await api.post('/profile/app-passwords', { label });
|
||||||
document.getElementById('app-pw-new-value').textContent = res.password;
|
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 = '';
|
document.getElementById('app-pw-label').value = '';
|
||||||
loadAppPasswords();
|
load();
|
||||||
} catch (e) { showToast(e.message, true); }
|
} catch (e) { showToast(e.message, true); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4185,7 +4191,7 @@ function bindProfileModal() {
|
|||||||
if (!confirm(t('app_pw_revoke_confirm'))) return;
|
if (!confirm(t('app_pw_revoke_confirm'))) return;
|
||||||
try {
|
try {
|
||||||
await api.delete(`/profile/app-passwords/${btn.dataset.id}`);
|
await api.delete(`/profile/app-passwords/${btn.dataset.id}`);
|
||||||
loadAppPasswords();
|
load();
|
||||||
} catch (err) { showToast(err.message, true); }
|
} catch (err) { showToast(err.message, true); }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
// Increment APP_VERSION with every code change
|
// Increment APP_VERSION with every code change
|
||||||
export const APP_VERSION = 'v68';
|
export const APP_VERSION = 'v69';
|
||||||
|
|||||||
Reference in New Issue
Block a user