2026-05-01 00:29:06 +03:00
{{ define "admin/dashboard.html" }}
<!DOCTYPE html>
< html lang = "en" >
< head >
< meta charset = "UTF-8" >
< meta name = "viewport" content = "width=device-width, initial-scale=1" >
< title > WarpBox Admin Dashboard< / title >
< link rel = "icon" type = "image/png" href = "/static/WarpBoxLogo.png" >
< link rel = "stylesheet" href = "/static/css/app.css" >
< link rel = "stylesheet" href = "/static/css/window.css" >
< link rel = "stylesheet" href = "/static/css/dashboard.css" >
< link rel = "stylesheet" href = "/static/css/components/buttons.css" >
< link rel = "stylesheet" href = "/static/css/components/toast.css" >
< link rel = "stylesheet" href = "/static/css/admin.css" >
< / head >
< body >
2026-05-04 10:54:44 +03:00
{{ $d := .Dashboard }}
2026-05-01 00:29:06 +03:00
< div class = "admin-shell" >
< div class = "admin-frame" >
{{ template "admin/header.html" . }}
< div class = "win98-window admin-dashboard-window" role = "main" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< img class = "win98-titlebar-icon" src = "/static/WarpBoxLogo.png" alt = "" aria-hidden = "true" >
< h1 > WarpBox Account Control Panel< / h1 >
< / div >
< div class = "win98-window-controls" aria-hidden = "true" >
< button class = "win98-control" type = "button" > _< / button >
< button class = "win98-control" type = "button" > □< / button >
< button class = "win98-control" type = "button" > x< / button >
< / div >
< / div >
< nav class = "menu-bar" aria-label = "Dashboard toolbar" >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > File< / button >
< div class = "menu-popup" >
< button class = "menu-action" type = "button" data-command = "refresh" > < span > R< / span > < span > Refresh dashboard< / span > < span class = "shortcut" > F5< / span > < / button >
< button class = "menu-action" type = "button" data-command = "dashboard-snapshot" > < span > S< / span > < span > Export dashboard snapshot< / span > < span > < / span > < / button >
< div class = "menu-separator" > < / div >
< button class = "menu-action" type = "button" data-command = "logout" > < span > Q< / span > < span > Log out< / span > < span > < / span > < / button >
< / div >
< / div >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > View< / button >
< div class = "menu-popup" >
< button class = "menu-action" type = "button" data-scroll-to = "alerts" > < span > !< / span > < span > Go to alerts< / span > < span class = "shortcut" > Alt+A< / span > < / button >
< button class = "menu-action" type = "button" data-scroll-to = "recent-boxes" > < span > B< / span > < span > Go to recent boxes< / span > < span class = "shortcut" > Alt+B< / span > < / button >
< button class = "menu-action" type = "button" data-scroll-to = "recent-activity" > < span > T< / span > < span > Go to recent activity< / span > < span class = "shortcut" > Alt+R< / span > < / button >
< div class = "menu-separator" > < / div >
< button class = "menu-action" type = "button" data-command = "compact-mode" > < span > C< / span > < span > Toggle compact density< / span > < span > < / span > < / button >
< / div >
< / div >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > Boxes< / button >
< div class = "menu-popup" >
2026-05-04 10:54:44 +03:00
< button class = "menu-action" type = "button" data-command = "show-all-boxes" > < span > B< / span > < span > Open boxes page< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "export-boxes" > < span > C< / span > < span > Export visible boxes CSV< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "cleanup-expired" > < span > D< / span > < span > Cleanup expired boxes< / span > < span > < / span > < / button >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > Alerts< / button >
< div class = "menu-popup" >
2026-05-04 10:54:44 +03:00
< button class = "menu-action" type = "button" data-command = "show-all-alerts" > < span > !< / span > < span > Open alerts page< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "close-low-alerts" > < span > L< / span > < span > Close low alerts< / span > < span > < / span > < / button >
< button class = "menu-action" type = "button" data-command = "export-alerts" > < span > J< / span > < span > Export visible alerts JSON< / span > < span > < / span > < / button >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > Admin< / button >
< div class = "menu-popup" >
< button class = "menu-action" type = "button" data-command = "open-users" > < span > U< / span > < span > Open user manager< / span > < span > < / span > < / button >
2026-05-04 10:54:44 +03:00
< button class = "menu-action" type = "button" data-command = "open-activity" > < span > A< / span > < span > Open activity log< / span > < span > < / span > < / button >
2026-05-01 00:29:06 +03:00
< button class = "menu-action" type = "button" data-command = "open-settings" > < span > G< / span > < span > Open settings< / span > < span > < / span > < / button >
< / div >
< / div >
< div class = "menu-item" >
< button class = "menu-button" type = "button" aria-expanded = "false" > Help< / button >
< div class = "menu-popup" >
< button class = "menu-action" type = "button" data-command = "shortcuts" > < span > K< / span > < span > Keyboard shortcuts< / span > < span > < / span > < / button >
2026-05-04 10:54:44 +03:00
< button class = "menu-action" type = "button" data-command = "about" > < span > W< / span > < span > About this dashboard< / span > < span > < / span > < / button >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< / nav >
< div class = "dashboard-body" >
< section class = "dashboard-hero raised-panel" aria-labelledby = "dashboardTitle" >
< div class = "hero-copy" >
< h2 id = "dashboardTitle" > Dashboard< / h2 >
2026-05-04 10:54:44 +03:00
< p > Live overview for boxes, alerts, storage, users, and recent account activity.< / p >
2026-05-01 00:29:06 +03:00
< / div >
< div class = "hero-status" aria-label = "System summary" >
2026-05-04 10:54:44 +03:00
< div class = "hero-status-row" > < span > Guest uploads< / span > < strong class = "{{ if eq $d.GuestUploadsLabel " enabled " } } status-ok { { else } } status-danger { { end } } " > {{ $d.GuestUploadsLabel }}< / strong > < / div >
< div class = "hero-status-row" > < span > API uploads< / span > < strong class = "{{ if eq $d.APIUploadsLabel " enabled " } } status-ok { { else } } status-danger { { end } } " > {{ $d.APIUploadsLabel }}< / strong > < / div >
< div class = "hero-status-row" > < span > ZIP downloads< / span > < strong class = "{{ if eq $d.ZipDownloadsLabel " enabled " } } status-ok { { else } } status-warn { { end } } " > {{ $d.ZipDownloadsLabel }}< / strong > < / div >
2026-05-01 00:29:06 +03:00
< / div >
< / section >
< section class = "stats-grid" aria-label = "Dashboard statistics" >
< article class = "stat-card sunken-panel is-info" id = "activeBoxesCard" >
< p class = "stat-label" > Active boxes< / p >
2026-05-04 10:54:44 +03:00
< p class = "stat-value" > {{ $d.ActiveBoxes }}< / p >
< p class = "stat-note" > < span class = "stat-note-pill" > +{{ $d.BoxesCreatedToday }} today< / span > < span class = "stat-note-pill" > {{ $d.PasswordedBoxes }} passworded< / span > < / p >
2026-05-01 00:29:06 +03:00
< / article >
< article class = "stat-card sunken-panel is-info" id = "storageCard" >
< p class = "stat-label" > Storage available< / p >
2026-05-04 10:54:44 +03:00
< p class = "stat-value" > {{ $d.StorageFreeLabel }}< / p >
< p class = "stat-note" > < span class = "stat-note-pill" > {{ $d.StorageUsedLabel }} used< / span > < span class = "stat-note-pill" > {{ $d.StorageCapLabel }} cap< / span > < span class = "stat-note-pill" > {{ $d.StorageBackend }} backend< / span > < / p >
< span class = "meter-track" aria-hidden = "true" > < span class = "meter-bar" style = "--meter: {{ $d.StorageMeter }}" > < / span > < / span >
2026-05-01 00:29:06 +03:00
< / article >
< article class = "stat-card sunken-panel is-warning" id = "alertsCard" >
< p class = "stat-label" > Alerts< / p >
2026-05-04 10:54:44 +03:00
< p class = "stat-value" > < span id = "alertCountValue" > {{ $d.OpenAlerts }}< / span > < / p >
< p class = "stat-note" id = "alertStatNote" > < span class = "stat-note-pill" > {{ $d.HighAlerts }} high< / span > < span class = "stat-note-pill" > {{ $d.MediumAlerts }} medium< / span > < span class = "stat-note-pill" > {{ $d.LowAlerts }} low< / span > < / p >
2026-05-01 00:29:06 +03:00
< / article >
< article class = "stat-card sunken-panel is-ok" id = "usersCard" >
< p class = "stat-label" > Users< / p >
2026-05-04 10:54:44 +03:00
< p class = "stat-value" > {{ $d.TotalUsers }}< / p >
< p class = "stat-note" > < span class = "stat-note-pill" > {{ $d.ActiveUsers }} active< / span > < span class = "stat-note-pill" > {{ $d.DisabledUsers }} disabled< / span > < span class = "stat-note-pill" > {{ $d.APIKeyCount }} API keys< / span > < / p >
2026-05-01 00:29:06 +03:00
< / article >
< / section >
< section class = "dashboard-main-grid" aria-label = "Dashboard panels" >
< article id = "alerts" class = "win98-window section-window" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< span class = "win98-titlebar-icon" > !< / span >
< h2 > Alerts Inbox< / h2 >
< / div >
< div class = "titlebar-actions" >
2026-05-01 00:46:10 +03:00
< a class = "titlebar-link-button" href = "/admin/alerts" > Show all< / a >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< div class = "section-body sunken-panel" >
< div class = "scroll-panel alerts-scroll" aria-label = "Scrollable alerts inbox" >
< div class = "alert-list" >
2026-05-04 10:54:44 +03:00
{{ if $d.Alerts }}
{{ range $d.Alerts }}
< div class = "alert-row" data-alert-id = "{{ .ID }}" data-severity = "{{ .Severity }}" data-alert-title = "{{ .Title }}" data-alert-code = "{{ .Code }}" data-alert-meta = '{{ toJSON .Meta }}' >
< span class = "alert-severity" > {{ .Severity }}< / span >
< div >
< p class = "alert-title" > {{ .Title }}< / p >
< p class = "alert-desc" > {{ .Message }}< / p >
< p class = "alert-trace" > {{ .Code }} {{ .Trace }} · {{ .CreatedAtLabel }} UTC · {{ .Status }}< / p >
< / div >
< div class = "alert-actions" >
< button class = "tiny-button" type = "button" data-view-meta > Meta< / button >
< button class = "tiny-button" type = "button" data-close-alert > Close< / button >
< / div >
< / div >
{{ end }}
{{ else }}
< div class = "dashboard-empty-state" > No open alerts. Nice and boring, which is the good kind of admin dashboard.< / div >
{{ end }}
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< / div >
< / article >
< article id = "recent-activity" class = "win98-window section-window" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< span class = "win98-titlebar-icon" > T< / span >
< h2 > Recent Activity< / h2 >
< / div >
< div class = "titlebar-actions" >
2026-05-04 10:54:44 +03:00
< a class = "titlebar-link-button" href = "/admin/activity" > Show all< / a >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< div class = "section-body sunken-panel" >
< div class = "scroll-panel activity-scroll" aria-label = "Scrollable recent activity list" >
< div class = "activity-list" >
2026-05-04 10:54:44 +03:00
{{ if $d.Events }}
{{ range $d.Events }}
< div class = "activity-row" >
< span class = "activity-time" > {{ .CreatedAtLabel }}< / span >
< div >
< p class = "activity-title" > {{ .Message }}< / p >
< p class = "activity-meta" > {{ .Kind }} · {{ .Method }} {{ .Path }} {{ if .IP }}· {{ .IP }}{{ end }}< / p >
< / div >
< span class = "tag {{ .TagClass }}" > {{ .TagLabel }}< / span >
< / div >
{{ end }}
{{ else }}
< div class = "dashboard-empty-state" > No activity has been recorded yet.< / div >
{{ end }}
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< / div >
< / article >
< article id = "recent-boxes" class = "win98-window section-window dashboard-span-2" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< span class = "win98-titlebar-icon" > B< / span >
< h2 > Recent Boxes< / h2 >
< / div >
< div class = "titlebar-actions" >
2026-05-04 10:54:44 +03:00
< a class = "titlebar-link-button" href = "/admin/boxes" > Show all< / a >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< div class = "section-body sunken-panel" >
< div class = "scroll-panel boxes-scroll" aria-label = "Scrollable recent boxes table" >
< table class = "box-table" >
2026-05-04 10:54:44 +03:00
< thead > < tr > < th > Box< / th > < th > Status< / th > < th > Files< / th > < th > Size< / th > < th > Created< / th > < th > Expires< / th > < th > Flags< / th > < th > Actions< / th > < / tr > < / thead >
2026-05-01 00:29:06 +03:00
< tbody >
2026-05-04 10:54:44 +03:00
{{ if $d.Boxes }}
{{ range $d.Boxes }}
< tr data-box-id = "{{ .ID }}" >
< td > {{ .ID }}< / td >
< td > < span class = "tag {{ .StatusClass }}" > {{ .StatusLabel }}< / span > < / td >
< td > {{ .CompleteFiles }}/{{ .FileCount }}< / td >
< td > {{ .TotalSizeLabel }}< / td >
< td > {{ .CreatedAtLabel }}< / td >
< td > {{ .ExpiresAtLabel }}< / td >
< td >
{{ range .Flags }}< span class = "tag info" > {{ . }}< / span > {{ end }}
{{ if not .Flags }}< span class = "tag ok" > plain< / span > {{ end }}
< / td >
< td > < div class = "box-actions" > < a class = "win98-button box-action-button" href = "{{ .OpenURL }}" > Open< / a > < a class = "win98-button box-action-button" href = "/admin/boxes?q={{ .ID }}" > Manage< / a > < / div > < / td >
< / tr >
{{ end }}
{{ else }}
< tr > < td colspan = "8" > No boxes found yet.< / td > < / tr >
{{ end }}
2026-05-01 00:29:06 +03:00
< / tbody >
< / table >
< / div >
< / div >
< / article >
< / section >
< / div >
< div class = "win98-statusbar admin-dashboard-statusbar" >
< span id = "statusText" > Ready< / span >
2026-05-04 10:54:44 +03:00
< span > {{ $d.OpenAlerts }} open alert(s)< / span >
< span > Live dashboard< / span >
2026-05-01 00:29:06 +03:00
< / div >
< / div >
< / div >
< / div >
< div class = "modal-backdrop" data-modal-backdrop > < / div >
< aside class = "popup-window win98-window" data-alert-modal aria-label = "Alert metadata" aria-hidden = "true" >
< div class = "win98-titlebar" >
< div class = "win98-titlebar-label" >
< span class = "win98-titlebar-icon" > !< / span >
< h2 id = "modalTitle" > Alert Metadata< / h2 >
< / div >
< button class = "win98-control" type = "button" data-close-modal > x< / button >
< / div >
< div class = "popup-body sunken-panel" >
< pre class = "metadata-pre" id = "modalMeta" > {}< / pre >
< / div >
< / aside >
< div class = "toast" id = "toast" role = "status" aria-live = "polite" > < / div >
2026-05-04 10:54:44 +03:00
< script id = "dashboard-data" type = "application/json" > { { toJSON $d } } < / script >
2026-05-01 00:29:06 +03:00
< script src = "/static/js/warpbox-ui.js" > < / script >
< script src = "/static/js/admin/dashboard.js" > < / script >
< / body >
< / html >
{{ end }}