release(v1.8.12): auth UI & DnD polish — show OIDC, auto-SSO, right-aligned header icons
This commit is contained in:
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,5 +1,33 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Changes 11/8/2025 (v1.8.12)
|
||||||
|
|
||||||
|
release(v1.8.12): auth UI & DnD polish — show OIDC, auto-SSO, right-aligned header icons
|
||||||
|
|
||||||
|
- auth (public/js/main.js)
|
||||||
|
- Robust login options: tolerate key variants (disableFormLogin/disable_form_login, etc.).
|
||||||
|
- Correctly show/hide wrapper + individual methods (form/OIDC/basic).
|
||||||
|
- Auto-SSO when OIDC is the only enabled method; add opt-out with `?noauto=1`.
|
||||||
|
- Minor cleanup (SW register catch spacing).
|
||||||
|
|
||||||
|
- drag & drop (public/js/dragAndDrop.js)
|
||||||
|
- Reworked zones model: Sidebar / Top (left/right) / Header (icon+modal).
|
||||||
|
- Persist user layout with `userZonesSnapshot.v2` and responsive stash for small screens.
|
||||||
|
- Live UI sync: toggle icon (`material-icons`) updates immediately after moves.
|
||||||
|
- Smarter small-screen behavior: lift sidebar cards ephemerally; restore only what belonged to sidebar.
|
||||||
|
- Cleaner header icon modal plumbing; remove legacy/dead code.
|
||||||
|
|
||||||
|
- styles (public/css/styles.css)
|
||||||
|
- Header drop zone fills remaining space and right-aligns its icons.
|
||||||
|
|
||||||
|
UX:
|
||||||
|
|
||||||
|
- OIDC button reliably appears when form/basic are disabled.
|
||||||
|
- If OIDC is the sole method, users are taken straight to the provider (unless `?noauto=1`).
|
||||||
|
- Header icons sit with the other header actions (right-aligned), and the toggle icon reflects layout changes instantly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Changes 11/8/2025 (v1.8.11)
|
## Changes 11/8/2025 (v1.8.11)
|
||||||
|
|
||||||
release(v1.8.11): fix(oidc): always send PKCE (S256) and treat empty secret as public client
|
release(v1.8.11): fix(oidc): always send PKCE (S256) and treat empty secret as public client
|
||||||
|
|||||||
@@ -141,7 +141,15 @@ body {
|
|||||||
}#userDropdownToggle {
|
}#userDropdownToggle {
|
||||||
border-radius: 4px !important;
|
border-radius: 4px !important;
|
||||||
padding: 6px 10px !important;
|
padding: 6px 10px !important;
|
||||||
}.header-buttons button:hover {
|
}
|
||||||
|
/* make the drop zone fill leftover space and right-align its own icons */
|
||||||
|
#headerDropArea.header-drop-zone{
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
min-width: 100px;
|
||||||
|
|
||||||
|
}
|
||||||
|
.header-buttons button:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.2);
|
background-color: rgba(255, 255, 255, 0.2);
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -403,39 +403,57 @@ function bindDarkMode() {
|
|||||||
function applySiteConfig(cfg, { phase = 'final' } = {}) {
|
function applySiteConfig(cfg, { phase = 'final' } = {}) {
|
||||||
try {
|
try {
|
||||||
const title = (cfg && cfg.header_title) ? String(cfg.header_title) : 'FileRise';
|
const title = (cfg && cfg.header_title) ? String(cfg.header_title) : 'FileRise';
|
||||||
|
|
||||||
// Always keep <title> correct early (no visual flicker)
|
// Always keep <title> correct early (no visual flicker)
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
|
||||||
// --- Login options (apply in BOTH phases so login page is correct) ---
|
// --- Login options (apply in BOTH phases so login page is correct) ---
|
||||||
const lo = (cfg && cfg.loginOptions) ? cfg.loginOptions : {};
|
const lo = (cfg && cfg.loginOptions) ? cfg.loginOptions : {};
|
||||||
const disableForm = !!lo.disableFormLogin;
|
|
||||||
const disableOIDC = !!lo.disableOIDCLogin;
|
|
||||||
const disableBasic = !!lo.disableBasicAuth;
|
// be tolerant to key variants just in case
|
||||||
|
const disableForm = !!(lo.disableFormLogin ?? lo.disable_form_login ?? lo.disableForm);
|
||||||
const row = $('#loginForm');
|
const disableOIDC = !!(lo.disableOIDCLogin ?? lo.disable_oidc_login ?? lo.disableOIDC);
|
||||||
if (row) {
|
const disableBasic = !!(lo.disableBasicAuth ?? lo.disable_basic_auth ?? lo.disableBasic);
|
||||||
if (disableForm) {
|
|
||||||
row.setAttribute('hidden', '');
|
const showForm = !disableForm;
|
||||||
row.style.display = ''; // don't leave display:none lying around
|
const showOIDC = !disableOIDC;
|
||||||
|
const showBasic = !disableBasic;
|
||||||
|
|
||||||
|
const loginWrap = $('#loginForm'); // outer wrapper that contains buttons + form
|
||||||
|
const authForm = $('#authForm'); // inner username/password form
|
||||||
|
const oidcBtn = $('#oidcLoginBtn'); // OIDC button
|
||||||
|
const basicLink = document.querySelector('a[href="/api/auth/login_basic.php"]');
|
||||||
|
|
||||||
|
// 1) Show the wrapper if ANY method is enabled (form OR OIDC OR basic)
|
||||||
|
if (loginWrap) {
|
||||||
|
const anyMethod = showForm || showOIDC || showBasic;
|
||||||
|
if (anyMethod) {
|
||||||
|
loginWrap.removeAttribute('hidden'); // remove [hidden], which beats display:
|
||||||
|
loginWrap.style.display = ''; // let CSS decide
|
||||||
} else {
|
} else {
|
||||||
row.removeAttribute('hidden');
|
loginWrap.setAttribute('hidden', '');
|
||||||
row.style.display = '';
|
loginWrap.style.display = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const oidc = $('#oidcLoginBtn'); if (oidc) oidc.style.display = disableOIDC ? 'none' : '';
|
|
||||||
|
// 2) Toggle the pieces inside the wrapper
|
||||||
|
if (authForm) authForm.style.display = showForm ? '' : 'none';
|
||||||
|
if (oidcBtn) oidcBtn.style.display = showOIDC ? '' : 'none';
|
||||||
|
if (basicLink) basicLink.style.display = showBasic ? '' : 'none';
|
||||||
|
const oidc = $('#oidcLoginBtn'); if (oidc) oidc.style.display = disableOIDC ? 'none' : '';
|
||||||
const basic = document.querySelector('a[href="/api/auth/login_basic.php"]');
|
const basic = document.querySelector('a[href="/api/auth/login_basic.php"]');
|
||||||
if (basic) basic.style.display = disableBasic ? 'none' : '';
|
if (basic) basic.style.display = disableBasic ? 'none' : '';
|
||||||
|
|
||||||
// --- Header <h1> only in the FINAL phase (prevents visible flips) ---
|
// --- Header <h1> only in the FINAL phase (prevents visible flips) ---
|
||||||
if (phase === 'final') {
|
if (phase === 'final') {
|
||||||
const h1 = document.querySelector('.header-title h1');
|
const h1 = document.querySelector('.header-title h1');
|
||||||
if (h1) {
|
if (h1) {
|
||||||
// prevent i18n or legacy from overwriting it
|
// prevent i18n or legacy from overwriting it
|
||||||
if (h1.hasAttribute('data-i18n-key')) h1.removeAttribute('data-i18n-key');
|
if (h1.hasAttribute('data-i18n-key')) h1.removeAttribute('data-i18n-key');
|
||||||
|
|
||||||
if (h1.textContent !== title) h1.textContent = title;
|
if (h1.textContent !== title) h1.textContent = title;
|
||||||
|
|
||||||
// lock it so late code can't stomp it
|
// lock it so late code can't stomp it
|
||||||
if (!h1.__titleLock) {
|
if (!h1.__titleLock) {
|
||||||
const mo = new MutationObserver(() => {
|
const mo = new MutationObserver(() => {
|
||||||
@@ -1037,6 +1055,21 @@ function bindDarkMode() {
|
|||||||
if (login) login.style.display = '';
|
if (login) login.style.display = '';
|
||||||
// …wire stuff…
|
// …wire stuff…
|
||||||
applySiteConfig(window.__FR_SITE_CFG__ || {}, { phase: 'final' });
|
applySiteConfig(window.__FR_SITE_CFG__ || {}, { phase: 'final' });
|
||||||
|
// Auto-SSO if OIDC is the only enabled method (add ?noauto=1 to skip)
|
||||||
|
(() => {
|
||||||
|
const lo = (window.__FR_SITE_CFG__ && window.__FR_SITE_CFG__.loginOptions) || {};
|
||||||
|
const disableForm = !!(lo.disableFormLogin ?? lo.disable_form_login ?? lo.disableForm);
|
||||||
|
const disableBasic = !!(lo.disableBasicAuth ?? lo.disable_basic_auth ?? lo.disableBasic);
|
||||||
|
const disableOIDC = !!(lo.disableOIDCLogin ?? lo.disable_oidc_login ?? lo.disableOIDC);
|
||||||
|
|
||||||
|
const onlyOIDC = disableForm && disableBasic && !disableOIDC;
|
||||||
|
const qp = new URLSearchParams(location.search);
|
||||||
|
|
||||||
|
if (onlyOIDC && qp.get('noauto') !== '1') {
|
||||||
|
const btn = document.getElementById('oidcLoginBtn');
|
||||||
|
if (btn) setTimeout(() => btn.click(), 250);
|
||||||
|
}
|
||||||
|
})();
|
||||||
await revealAppAndHideOverlay();
|
await revealAppAndHideOverlay();
|
||||||
const hb = document.querySelector('.header-buttons');
|
const hb = document.querySelector('.header-buttons');
|
||||||
if (hb) hb.style.visibility = 'hidden';
|
if (hb) hb.style.visibility = 'hidden';
|
||||||
@@ -1102,7 +1135,7 @@ function bindDarkMode() {
|
|||||||
const onHttps = location.protocol === 'https:' || location.hostname === 'localhost';
|
const onHttps = location.protocol === 'https:' || location.hostname === 'localhost';
|
||||||
if ('serviceWorker' in navigator && onHttps && !hasCapBridge && !isCapUA) {
|
if ('serviceWorker' in navigator && onHttps && !hasCapBridge && !isCapUA) {
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
navigator.serviceWorker.register(`/js/pwa/sw.js?v=${encodeURIComponent(QVER)}`).catch(() => {});
|
navigator.serviceWorker.register(`/js/pwa/sw.js?v=${encodeURIComponent(QVER)}`).catch(() => { });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
Reference in New Issue
Block a user