Refactor auth flow: add loading overlay, separate login, extract initializeApp

This commit is contained in:
Ryan
2025-05-05 07:28:28 -04:00
committed by GitHub
parent bd1841b788
commit d1726f0160
8 changed files with 183 additions and 108 deletions

View File

@@ -1,6 +1,6 @@
# Changelog
## Changes 5/4/2025
## Changes 5/4/2025 v1.3.1
### Modals
@@ -10,9 +10,47 @@
- TOTP Login & Setup
- Change Password
- **Truncated** long filenames in the File Tags modal header using CSS `text-overflow: ellipsis`.
- **Resized** File Tags modal from 400px 450px wide (with `max-width: 90vw` fallback).
- **Resized** File Tags modal from 400px to 450px wide (with `max-width: 90vw` fallback).
- **Capped** User Panel height at 381px and hidden scrollbars to eliminate layout jumps on hover.
### HTML
- **Moved** `<div id="loginForm">…</div>` out of `.main-wrapper` so the login form can show independently of the app shell.
- **Added** `<div id="loadingOverlay"></div>` immediately inside `<body>` to cover the UI during auth checks.
- **Inserted** inline `<style>` in `<head>` to:
- Hide `.main-wrapper` by default.
- Style `#loadingOverlay` as a full-viewport white overlay.
- **Added** `addUserModal`, `removeUserModal` & `renameFileModal` modals to `style="display:none;"`
### `main.js`
- **Extracted** `initializeApp()` helper to centralize post-auth startup (tag search, file list, drag-and-drop, folder tree, upload, trash/restore, admin config).
- **Updated** DOMContentLoaded `checkAuthentication()` flow to call `initializeApp()` when already authenticated.
- **Extended** `updateAuthenticatedUI()` to call `initializeApp()` after a fresh login so all UI modules re-hydrate.
- **Enhanced** setup-mode in `checkAuthentication()`:
- Show `#addUserModal` as a flex overlay (`style.display = 'flex'`).
- Keep `.main-wrapper` hidden until setup completes.
- **Added** post-setup handler in the Add-User modals save button:
- Hide setup modal.
- Show login form.
- Keep app shell hidden.
- Pre-fill and focus the new username in the login inputs.
### `auth.js` / Auth Logic
- **Refactored** `checkAuthentication()` to handle three states:
1. **`data.setup`** remove overlay, hide main UI, show setup modal.
2. **`data.authenticated`** remove overlay, call `updateAuthenticatedUI()`.
3. **not authenticated** remove overlay, show login form, keep main UI hidden.
- **Refined** `updateAuthenticatedUI()` to:
- Remove loading overlay.
- Show `.main-wrapper` and main operations.
- Hide `#loginForm`.
- Reveal header buttons.
- Initialize dynamic header buttons (restore, admin, user-panel).
- Call `initializeApp()` to load all modules after login.
---
## Changes 5/3/2025 v1.3.0

View File

@@ -1,2 +0,0 @@
cd /var/www/public
ln -s ../uploads uploads

View File

@@ -9,6 +9,21 @@
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
<meta name="csrf-token" content="">
<meta name="share-url" content="">
<style>
/* hide the app shell until JS says otherwise */
.main-wrapper { display: none; }
/* full-screen white overlay while we check auth */
#loadingOverlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: var(--bg-color,#fff);
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
}
</style>
<!-- Google Fonts and Material Icons -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500&display=swap" rel="stylesheet" />
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
@@ -165,19 +180,13 @@
</div>
</header>
<div id="loadingOverlay"></div>
<!-- Custom Toast Container -->
<div id="customToast"></div>
<div id="hiddenCardsContainer" style="display:none;"></div>
<!-- Main Wrapper: Hidden by default; remove "display: none;" after login -->
<div class="main-wrapper">
<!-- Sidebar Drop Zone: Hidden until you drag a card (display controlled by JS) -->
<div id="sidebarDropArea" class="drop-target-sidebar"></div>
<!-- Main Column -->
<div id="mainColumn" class="main-column">
<div class="container-fluid">
<!-- Login Form (unchanged) -->
<div class="row" id="loginForm">
<div class="row mt-4" id="loginForm">
<div class="col-12">
<form id="authForm" method="post">
<div class="form-group">
@@ -207,6 +216,13 @@
</div>
</div>
<!-- Main Wrapper: Hidden by default; remove "display: none;" after login -->
<div class="main-wrapper">
<!-- Sidebar Drop Zone: Hidden until you drag a card (display controlled by JS) -->
<div id="sidebarDropArea" class="drop-target-sidebar"></div>
<!-- Main Column -->
<div id="mainColumn" class="main-column">
<div class="container-fluid">
<!-- Main Operations: Upload and Folder Management -->
<div id="mainOperations">
<div class="container" style="max-width: 1400px; margin: 0 auto;">
@@ -439,7 +455,7 @@
<button id="saveNewPasswordBtn" class="btn btn-primary" data-i18n-key="save" style="width:100%;">Save</button>
</div>
</div>
<div id="addUserModal" class="modal">
<div id="addUserModal" class="modal" style="display:none;">
<div class="modal-content">
<h3 data-i18n-key="create_new_user_title">Create New User</h3>
<!-- 1) Add a form around these fields -->
@@ -468,7 +484,7 @@
</form>
</div>
</div>
<div id="removeUserModal" class="modal">
<div id="removeUserModal" class="modal" style="display:none;">
<div class="modal-content">
<h3 data-i18n-key="remove_user_title">Remove User</h3>
<label for="removeUsernameSelect" data-i18n-key="select_user_remove">Select a user to remove:</label>
@@ -479,7 +495,7 @@
</div>
</div>
</div>
<div id="renameFileModal" class="modal">
<div id="renameFileModal" class="modal" style="display:none;">
<div class="modal-content">
<h4 data-i18n-key="rename_file_title">Rename File</h4>
<input type="text" id="newFileName" class="form-control" data-i18n-placeholder="rename_file_placeholder"

View File

@@ -3,7 +3,7 @@ import { loadAdminConfigFunc } from './auth.js';
import { showToast, toggleVisibility, attachEnterKeyListener } from './domUtils.js';
import { sendRequest } from './networkUtils.js';
const version = "v1.3.0";
const version = "v1.3.1";
const adminTitle = `${t("admin_panel")} <small style="font-size:12px;color:gray;">${version}</small>`;
// ————— Inject updated styles —————
@@ -389,7 +389,7 @@ export function openAdminPanel() {
// — Header Settings —
document.getElementById("headerSettingsContent").innerHTML = `
<div class="form-group">
<label for="headerTitle">${t("header_title")}:</label>
<label for="headerTitle">${t("header_title_text")}:</label>
<input type="text" id="headerTitle" class="form-control" value="${window.headerTitle}" />
</div>
`;
@@ -548,7 +548,7 @@ export function openUserPermissionsModal() {
`;
userPermissionsModal.innerHTML = `
<div class="modal-content" style="${modalContentStyles}">
<span id="closeUserPermissionsModal" style="position: absolute; top: 10px; right: 10px; cursor: pointer; font-size: 24px;">&times;</span>
<span id="closeUserPermissionsModal" class="editor-close-btn">&times;</span>
<h3>${t("user_permissions")}</h3>
<div id="userPermissionsList" style="max-height: 300px; overflow-y: auto; margin-bottom: 15px;">
<!-- User rows will be loaded here -->

View File

@@ -18,6 +18,7 @@ import {
setLastLoginData
} from './authModals.js';
import { openAdminPanel } from './adminPanel.js';
import { initializeApp } from './main.js';
// Production OIDC configuration (override via API as needed)
const currentOIDCConfig = {
@@ -189,6 +190,11 @@ function insertAfter(newNode, referenceNode) {
}
function updateAuthenticatedUI(data) {
document.getElementById('loadingOverlay').remove();
// show the wrapper (so the login form can be visible)
document.querySelector('.main-wrapper').style.display = '';
document.getElementById('loginForm').style.display = 'none';
toggleVisibility("loginForm", false);
toggleVisibility("mainOperations", true);
toggleVisibility("uploadFileForm", true);
@@ -263,6 +269,7 @@ function updateAuthenticatedUI(data) {
userPanelBtn.style.display = "block";
}
}
initializeApp();
applyTranslations();
updateItemsPerPageSelect();
updateLoginOptionsUIFromStorage();
@@ -272,6 +279,11 @@ function checkAuthentication(showLoginToast = true) {
return sendRequest("/api/auth/checkAuth.php")
.then(data => {
if (data.setup) {
document.getElementById('loadingOverlay').remove();
// show the wrapper (so the login form can be visible)
document.querySelector('.main-wrapper').style.display = '';
document.getElementById('loginForm').style.display = 'none';
window.setupMode = true;
if (showLoginToast) showToast("Setup mode: No users found. Please add an admin user.");
toggleVisibility("loginForm", false);
@@ -283,6 +295,7 @@ function checkAuthentication(showLoginToast = true) {
}
window.setupMode = false;
if (data.authenticated) {
localStorage.setItem('isAdmin', data.isAdmin ? 'true' : 'false');
localStorage.setItem("folderOnly", data.folderOnly);
localStorage.setItem("readOnly", data.readOnly);
@@ -298,6 +311,11 @@ function checkAuthentication(showLoginToast = true) {
updateAuthenticatedUI(data);
return data;
} else {
document.getElementById('loadingOverlay').remove();
// show the wrapper (so the login form can be visible)
document.querySelector('.main-wrapper').style.display = '';
document.getElementById('loginForm').style.display = '';
if (showLoginToast) showToast("Please log in to continue.");
toggleVisibility("loginForm", true);
toggleVisibility("mainOperations", false);
@@ -450,11 +468,11 @@ function initAuth() {
document.getElementById("newUsername").focus();
});
// remove your old saveUserBtn click-handler…
// remove your old saveUserBtn click-handler…
// instead:
const addUserForm = document.getElementById("addUserForm");
addUserForm.addEventListener("submit", function (e) {
// instead:
const addUserForm = document.getElementById("addUserForm");
addUserForm.addEventListener("submit", function (e) {
e.preventDefault(); // stop the browser from reloading the page
const newUsername = document.getElementById("newUsername").value.trim();
@@ -481,6 +499,9 @@ addUserForm.addEventListener("submit", function (e) {
showToast("User added successfully!");
closeAddUserModal();
checkAuthentication(false);
if (window.setupMode) {
toggleVisibility("loginForm", true);
}
} else {
showToast("Error: " + (data.error || "Could not add user"));
}
@@ -488,7 +509,7 @@ addUserForm.addEventListener("submit", function (e) {
.catch(() => {
showToast("Error: Could not add user");
});
});
});
document.getElementById("cancelUserBtn").addEventListener("click", closeAddUserModal);
document.getElementById("removeUserBtn").addEventListener("click", function () {

View File

@@ -174,7 +174,7 @@ export function openUserPanel() {
border-radius: 8px;
overflow-y: auto;
overflow-x: hidden;
max-height: 381px !important;
max-height: 383px !important;
flex-shrink: 0 !important;
scrollbar-gutter: stable both-edges;
border: ${isDarkMode ? "1px solid #444" : "1px solid #ccc"};

View File

@@ -55,6 +55,7 @@ const translations = {
// Additional keys for HTML translations:
"title": "FileRise",
"header_title": "FileRise",
"header_title_text": "Header Title",
"logout": "Logout",
"change_password": "Change Password",
"restore_text": "Restore or",
@@ -316,6 +317,7 @@ const translations = {
// Additional keys for HTML translations:
"title": "FileRise",
"header_title": "FileRise",
"header_title_text": "Header Title",
"logout": "Cerrar sesión",
"change_password": "Cambiar contraseña",
"restore_text": "Restaurar o",

View File

@@ -14,6 +14,28 @@ import { initFileActions, renameFile, openDownloadModal, confirmSingleDownload }
import { editFile, saveFile } from './fileEditor.js';
import { t, applyTranslations, setLocale } from './i18n.js';
export function initializeApp() {
window.currentFolder = "root";
initTagSearch();
loadFileList(window.currentFolder);
initDragAndDrop();
loadSidebarOrder();
loadHeaderOrder();
initFileActions();
initUpload();
loadFolderTree();
setupTrashRestoreDelete();
loadAdminConfigFunc();
const helpBtn = document.getElementById("folderHelpBtn");
const helpTooltip = document.getElementById("folderHelpTooltip");
if (helpBtn && helpTooltip) {
helpBtn.addEventListener("click", () => {
helpTooltip.style.display =
helpTooltip.style.display === "block" ? "none" : "block";
});
}
}
export function loadCsrfToken() {
return fetchWithCsrf('/api/auth/token.php', {
@@ -100,30 +122,8 @@ document.addEventListener("DOMContentLoaded", function () {
// Continue with initializations that rely on a valid CSRF token:
checkAuthentication().then(authenticated => {
if (authenticated) {
window.currentFolder = "root";
initTagSearch();
loadFileList(window.currentFolder);
initDragAndDrop();
loadSidebarOrder();
loadHeaderOrder();
initFileActions();
initUpload();
loadFolderTree();
setupTrashRestoreDelete();
loadAdminConfigFunc();
const helpBtn = document.getElementById("folderHelpBtn");
const helpTooltip = document.getElementById("folderHelpTooltip");
helpBtn.addEventListener("click", function () {
// Toggle display of the tooltip.
if (helpTooltip.style.display === "none" || helpTooltip.style.display === "") {
helpTooltip.style.display = "block";
} else {
helpTooltip.style.display = "none";
}
});
} else {
console.warn("User not authenticated. Data loading deferred.");
document.getElementById('loadingOverlay').remove();
initializeApp();
}
});