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 }}