2026-02-20 12:27:52 +01:00
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< title > OxiCloud — Admin Panel</ title >
2026-03-05 13:15:34 +01:00
< script src = "/js/core/theme-init.js" ></ script >
2026-02-20 12:27:52 +01:00
< script src = "/js/core/icons.js" defer ></ script >
2026-03-03 01:44:39 +01:00
< script src = "/js/core/formatters.js" defer ></ script >
2026-03-03 01:10:50 +01:00
< script src = "/js/core/csrf.js" defer ></ script >
2026-02-21 00:19:04 +01:00
< link rel = "stylesheet" href = "/css/main.css" >
< link rel = "stylesheet" href = "/css/views/admin.css" >
2026-02-20 12:27:52 +01:00
</ head >
< body >
< div class = "admin-header" >
< div class = "admin-header-left" >
< a href = "/" class = "admin-logo-link link-reset-flex" >
< div class = "admin-logo" >
< svg viewBox = "0 0 500 500" >
< path d = "M345 310c32 0 58-26 58-58s-26-58-58-58c-6.2 0-12 0.9-17.5 2.7C318 166 289 143 255 143c-34.3 0-63.1 22.6-73 53.7C176.9 195.7 171 195 165 195c-32 0-58 26-58 58s26 58 58 58h180z" />
</ svg >
</ div >
< span class = "admin-title-text" > OxiCloud</ span >
</ a >
< span class = "admin-title-separator" > · Admin</ span >
</ div >
< div class = "admin-header-right" >
< a href = "/" >< i class = "fas fa-arrow-left" ></ i > Back to OxiCloud</ a >
</ div >
</ div >
< div class = "admin-container" >
< div id = "loading" >< i class = "fas fa-circle-notch" ></ i > Loading…</ div >
< div id = "access-denied" >
< div class = "access-icon" >< i class = "fas fa-lock" ></ i ></ div >
< h2 > Access Denied</ h2 >
< p > Administrator privileges required to access this panel.</ p >
< a href = "/login" >< i class = "fas fa-sign-in-alt" ></ i > Sign in</ a >
</ div >
< div id = "main-content" >
< div class = "admin-tabs" >
2026-03-05 13:15:34 +01:00
< button class = "admin-tab active" id = "tab-btn-dashboard" >< i class = "fas fa-chart-pie" ></ i > Dashboard</ button >
< button class = "admin-tab" id = "tab-btn-users" >< i class = "fas fa-users" ></ i > Users</ button >
< button class = "admin-tab" id = "tab-btn-oidc" >< i class = "fas fa-key" ></ i > SSO / OIDC</ button >
2026-02-20 12:27:52 +01:00
</ div >
< div id = "tab-dashboard" class = "tab-content active" >
< div class = "stats-grid" >
< div class = "stat-card" >< div class = "stat-value text-blue" id = "ds-total-users" > —</ div >< div class = "stat-label" > Total Users</ div ></ div >
< div class = "stat-card" >< div class = "stat-value text-green" id = "ds-active-users" > —</ div >< div class = "stat-label" > Active Users</ div ></ div >
< div class = "stat-card" >< div class = "stat-value text-blue" id = "ds-admin-users" > —</ div >< div class = "stat-label" > Admins</ div ></ div >
< div class = "stat-card" >< div class = "stat-value" id = "ds-version" > —</ div >< div class = "stat-label" > Version</ div ></ div >
</ div >
< div class = "admin-card" >
< h2 >< i class = "fas fa-hdd" ></ i > Storage Overview</ h2 >
< div class = "stats-grid" >
< div class = "stat-card" >< div class = "stat-value" id = "ds-used" > —</ div >< div class = "stat-label" > Used</ div ></ div >
< div class = "stat-card" >< div class = "stat-value" id = "ds-quota" > —</ div >< div class = "stat-label" > Total Quota</ div ></ div >
< div class = "stat-card" >< div class = "stat-value" id = "ds-usage-pct" > —</ div >< div class = "stat-label" > Usage %</ div ></ div >
</ div >
< div class = "progress-bar" >< div class = "progress-fill green width-zero" id = "ds-bar" ></ div ></ div >
< div class = "mt-14" >
< div class = "stats-grid" >
< div class = "stat-card warn" id = "ds-warn-card" >< div class = "stat-value text-orange" id = "ds-over80" > 0</ div >< div class = "stat-label" > Users > 80% quota</ div ></ div >
< div class = "stat-card danger" id = "ds-danger-card" >< div class = "stat-value text-red" id = "ds-overquota" > 0</ div >< div class = "stat-label" > Users over quota</ div ></ div >
</ div >
</ div >
</ div >
< div class = "admin-card" >
< h2 >< i class = "fas fa-server" ></ i > System</ h2 >
< div class = "stats-grid" >
< div class = "stat-card" >< div class = "stat-value" id = "ds-auth" > —</ div >< div class = "stat-label" > Auth</ div ></ div >
< div class = "stat-card" >< div class = "stat-value" id = "ds-oidc" > —</ div >< div class = "stat-label" > OIDC</ div ></ div >
< div class = "stat-card" >< div class = "stat-value" id = "ds-quotas-flag" > —</ div >< div class = "stat-label" > Quotas</ div ></ div >
</ div >
< div class = "toggle-row toggle-row-strong" >
< label >< i class = "fas fa-user-plus icon-muted-right" ></ i > Allow public self-registration</ label >
2026-03-05 13:15:34 +01:00
< label class = "switch" >< input type = "checkbox" id = "ds-registration" checked >< span class = "slider" ></ span ></ label >
2026-02-20 12:27:52 +01:00
</ div >
< div class = "warning" id = "registration-warning" >< i class = "fas fa-exclamation-triangle" ></ i > Public registration is disabled. Only admins can create new users.</ div >
</ div >
</ div >
< div id = "tab-users" class = "tab-content" >
< div class = "admin-card" >
2026-03-05 13:15:34 +01:00
< h2 class = "h2-space-between" >< span >< i class = "fas fa-users-cog" ></ i > User Management</ span >< button class = "btn btn-primary" id = "btn-create-user" >< i class = "fas fa-user-plus" ></ i > Create User</ button ></ h2 >
2026-02-20 12:27:52 +01:00
< div class = "table-wrap" >
< table >
< thead >
< tr >
< th > User</ th >
< th > Role</ th >
2026-02-21 20:28:09 +01:00
< th > Auth</ th >
2026-02-20 12:27:52 +01:00
< th > Status</ th >
< th > Storage</ th >
< th > Last Login</ th >
< th > Actions</ th >
</ tr >
</ thead >
2026-02-21 20:28:09 +01:00
< tbody id = "users-tbody" >< tr >< td colspan = "7" class = "table-loading-cell" >< i class = "fas fa-spinner fa-spin" ></ i > Loading users…</ td ></ tr ></ tbody >
2026-02-20 12:27:52 +01:00
</ table >
</ div >
< div class = "pagination" >
< span id = "users-info" > —</ span >
< div class = "flex-gap-6" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-sm btn-secondary" id = "prev-btn" disabled >< i class = "fas fa-chevron-left" ></ i > Prev</ button >
< button class = "btn btn-sm btn-secondary" id = "next-btn" > Next < i class = "fas fa-chevron-right" ></ i ></ button >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
</ div >
</ div >
< div id = "tab-oidc" class = "tab-content" >
< div class = "admin-card" >
< h2 >< i class = "fas fa-shield-alt" ></ i > Single Sign-On (OIDC / SSO)</ h2 >
< div class = "toggle-row" >
< label > Enable SSO Authentication</ label >
< label class = "switch" >< input type = "checkbox" id = "oidc-enabled" >< span class = "slider" ></ span ></ label >
</ div >
< div id = "oidc-form" >
< div class = "form-group" >
< label > Provider Name < span id = "badge-provider_name" ></ span ></ label >
< input type = "text" id = "provider-name" placeholder = "e.g., Authentik, Keycloak" >
</ div >
< div class = "form-group" >
< label > Issuer URL < span id = "badge-issuer_url" ></ span ></ label >
< input type = "url" id = "issuer-url" placeholder = "https://auth.example.com/application/o/oxicloud/" >
< small > OpenID Connect issuer URL of your identity provider</ small >
</ div >
< div class = "oidc-discover-wrap" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-secondary btn-sm" id = "discover-btn" >< i class = "fas fa-search" ></ i > Auto-discover</ button >
2026-02-20 12:27:52 +01:00
</ div >
< div id = "discovery-result" ></ div >
< div class = "form-group" >
< label > Client ID < span id = "badge-client_id" ></ span ></ label >
< input type = "text" id = "client-id" placeholder = "oxicloud" >
</ div >
< div class = "form-group" >
< label > Client Secret < span id = "badge-client_secret" ></ span ></ label >
< input type = "password" id = "client-secret" placeholder = "Leave empty to keep current value" >
< small id = "secret-hint" >< i class = "fas fa-check-circle secret-icon" ></ i > A client secret is already configured</ small >
</ div >
< div class = "form-group" >
< label > Callback URL < small class = "small-muted" > (register in your IdP)</ small ></ label >
2026-03-05 13:15:34 +01:00
< div class = "readonly-field" >< span id = "callback-url" > —</ span >< button id = "btn-copy-callback" title = "Copy" >< i class = "fas fa-copy" ></ i ></ button ></ div >
2026-02-20 12:27:52 +01:00
</ div >
< details >
< summary >< i class = "fas fa-sliders-h summary-icon-right" ></ i > Advanced Settings</ summary >
< div class = "form-group" >
< label > Scopes < span id = "badge-scopes" ></ span ></ label >
< input type = "text" id = "scopes" placeholder = "openid profile email" >
</ div >
< div class = "toggle-row" >
< label > Auto-provision users on first login</ label >
< label class = "switch" >< input type = "checkbox" id = "auto-provision" checked >< span class = "slider" ></ span ></ label >
</ div >
< div class = "form-group" >
< label > Admin Groups < span id = "badge-admin_groups" ></ span ></ label >
< input type = "text" id = "admin-groups" placeholder = "e.g., oxicloud-admins" >
< small > Comma-separated OIDC group names that map to admin role</ small >
</ div >
< div class = "toggle-row" >
< label > Disable password login (OIDC only)</ label >
< label class = "switch" >< input type = "checkbox" id = "disable-password" >< span class = "slider" ></ span ></ label >
</ div >
< div class = "warning" id = "password-warning" >< i class = "fas fa-exclamation-triangle" ></ i > This will prevent ALL password-based logins!</ div >
</ details >
< div class = "oidc-actions" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-secondary" id = "btn-test-oidc" >< i class = "fas fa-vial" ></ i > Test</ button >
< button class = "btn btn-primary" id = "save-btn" >< i class = "fas fa-save" ></ i > Save</ button >
2026-02-20 12:27:52 +01:00
</ div >
< div id = "oidc-status" class = "alert" ></ div >
</ div >
</ div >
</ div >
</ div >
</ div >
< div id = "quota-modal" class = "modal-overlay" >
< div class = "modal" >
< h3 >< i class = "fas fa-box modal-title-icon" ></ i > Update Storage Quota</ h3 >
< div class = "form-group" >
< label > User: < strong id = "qm-username" ></ strong ></ label >
</ div >
< div class = "form-group" >
< label > New Quota</ label >
< div class = "quota-input-row" >
< input type = "number" id = "qm-value" min = "0" step = "1" class = "flex-1" >
< select id = "qm-unit" class = "select-qm-unit" >< option value = "1073741824" > GB</ option >< option value = "1048576" > MB</ option >< option value = "1099511627776" > TB</ option ></ select >
</ div >
< small > Set to 0 for unlimited</ small >
</ div >
< div class = "modal-actions" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-secondary" id = "btn-close-quota" > Cancel</ button >
< button class = "btn btn-primary" id = "btn-save-quota" >< i class = "fas fa-save" ></ i > Save</ button >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
</ div >
< div id = "create-user-modal" class = "modal-overlay" >
< div class = "modal" >
< h3 >< i class = "fas fa-user-plus modal-title-icon" ></ i > Create New User</ h3 >
< div class = "form-group" >
< label > Username *</ label >
< input type = "text" id = "cu-username" placeholder = "johndoe" minlength = "3" maxlength = "32" >
< small > 3– 32 characters</ small >
</ div >
< div class = "form-group" >
< label > Password *</ label >
< input type = "password" id = "cu-password" placeholder = "Min 8 characters" minlength = "8" >
</ div >
< div class = "form-group" >
< label > Email < small class = "small-muted" > (optional)</ small ></ label >
< input type = "text" id = "cu-email" placeholder = "user@example.com (auto-generated if empty)" >
</ div >
< div class = "form-row" >
< div class = "form-group flex-1" >
< label > Role</ label >
< select id = "cu-role" class = "select-cu-role" >
< option value = "user" > User</ option >
< option value = "admin" > Admin</ option >
</ select >
</ div >
< div class = "form-group flex-1" >
< label > Quota</ label >
< div class = "quota-row" >
< input type = "number" id = "cu-quota-value" min = "0" step = "1" value = "1" class = "flex-1" >
< select id = "cu-quota-unit" class = "select-cu-quota-unit" >< option value = "1073741824" > GB</ option >< option value = "1048576" > MB</ option >< option value = "1099511627776" > TB</ option ></ select >
</ div >
</ div >
</ div >
< div id = "cu-error" class = "alert alert-no-margin" ></ div >
< div class = "modal-actions" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-secondary" id = "btn-close-create-user" > Cancel</ button >
< button class = "btn btn-primary" id = "cu-submit" >< i class = "fas fa-user-plus" ></ i > Create</ button >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
</ div >
< div id = "reset-pw-modal" class = "modal-overlay" >
< div class = "modal" >
< h3 >< i class = "fas fa-key modal-title-icon" ></ i > Reset Password</ h3 >
< div class = "form-group" >
< label > User: < strong id = "rp-username" ></ strong ></ label >
</ div >
< div class = "form-group" >
< label > New Password</ label >
< input type = "password" id = "rp-password" placeholder = "Min 8 characters" minlength = "8" >
</ div >
< div id = "rp-error" class = "alert alert-no-margin" ></ div >
< div class = "modal-actions" >
2026-03-05 13:15:34 +01:00
< button class = "btn btn-secondary" id = "btn-close-reset-pw" > Cancel</ button >
< button class = "btn btn-primary" id = "rp-submit" >< i class = "fas fa-save" ></ i > Reset</ button >
2026-02-20 12:27:52 +01:00
</ div >
</ div >
</ div >
< script src = "/js/views/admin/admin.js" defer ></ script >
</ body >
</ html >