feat(web): improve dashboard experience
CI / validate (push) Successful in 26m4s

This commit is contained in:
2026-08-16 14:40:39 +02:00
parent d0193dc0fe
commit 2ae87e65ea
9 changed files with 174 additions and 75 deletions
+6 -6
View File
@@ -10,9 +10,9 @@ const defaultLanguage = "en"
var messages = map[string]map[string]string{
"en": {
"brand.control": "Game server control", "nav.primary": "Primary navigation", "nav.dashboard": "Dashboard", "nav.instances": "Instances", "nav.catalog": "Catalog", "nav.backups": "Backups", "nav.audit": "Audit", "nav.settings": "Settings", "nav.planned": "This page is planned for a future milestone",
"setup.title": "Create administrator", "setup.heading": "Welcome to DoGaMa", "setup.introduction": "Create the first administrator to finish setup.", "setup.submit": "Create administrator",
"login.title": "Sign in", "login.heading": "Sign in to DoGaMa", "login.introduction": "Manage your game servers from one secure place.", "login.submit": "Sign in", "logout.submit": "Sign out",
"brand.control": "Docker Gameserver Manager", "nav.primary": "Primary navigation", "nav.dashboard": "Dashboard", "nav.instances": "Instances", "nav.catalog": "Catalog", "nav.backups": "Backups", "nav.audit": "Audit", "nav.settings": "Settings", "nav.administration": "Administration", "nav.planned": "This page is planned for a future milestone",
"setup.title": "Create administrator", "setup.heading": "Welcome", "setup.introduction": "Create the first administrator to finish setup.", "setup.submit": "Create administrator",
"login.title": "Sign in", "login.heading": "Sign in", "login.introduction": "Manage your game servers from one secure place.", "login.submit": "Sign in", "logout.submit": "Sign out",
"dashboard.title": "Dashboard", "dashboard.eyebrow": "Dashboard", "dashboard.heading": "Game servers", "dashboard.introduction": "Overview of all your game server instances.", "dashboard.search": "Search instances", "dashboard.search_placeholder": "Search instance", "dashboard.summary": "Instance summary", "dashboard.total": "Total instances", "dashboard.running": "Running", "dashboard.stopped": "Stopped", "dashboard.updating": "Updating", "dashboard.error": "Error", "dashboard.no_match": "No matching instance", "dashboard.empty_heading": "No instances deployed", "dashboard.empty_copy": "Your game servers will appear here when they are added from the Catalog.", "dashboard.instances_eyebrow": "Servers", "dashboard.instances": "Your instances", "dashboard.activity_eyebrow": "Operations", "dashboard.recent_activity": "Recent activity", "dashboard.no_activity": "No recent activity", "dashboard.system_eyebrow": "Health", "dashboard.system_status": "System status", "dashboard.agent": "Docker agent", "dashboard.database": "Database", "dashboard.storage": "Storage", "dashboard.backups": "Backups", "dashboard.audit_log": "Audit log", "dashboard.online": "Online", "dashboard.offline": "Offline", "dashboard.healthy": "Healthy", "dashboard.unavailable": "Unavailable", "dashboard.last_backup": "Last backup", "dashboard.no_backup": "No backup", "dashboard.retention_days": "days retention", "dashboard.unlimited": "Unlimited retention", "dashboard.by": "by",
"catalog.title": "Catalog", "catalog.eyebrow": "Game library", "catalog.heading": "Catalog", "catalog.search": "Search games", "catalog.search_placeholder": "Search a game", "catalog.scan": "Scan", "catalog.found": "templates found", "catalog.valid": "valid", "catalog.invalid": "invalid", "catalog.no_match": "No matching game", "catalog.empty": "No game available", "catalog.empty_admin": "Add templates to /var/lib/dogama/templates, then use Scan.", "catalog.back": "Back to catalog", "catalog.minimum": "Minimum", "catalog.recommended": "Recommended", "catalog.memory": "Memory", "catalog.storage": "Storage", "catalog.other": "Other", "catalog.deploy": "Deploy", "catalog.deploy_unavailable": "Deployment will be available in the next milestone.",
"deployment.title": "Deploy", "deployment.eyebrow": "New instance", "deployment.heading": "Configure your server", "deployment.name": "Instance name", "deployment.description": "Instance description", "deployment.parameters": "Game parameters", "deployment.backup": "Import an external save", "deployment.backup_help": "ZIP, TAR, TAR.GZ or TAR.ZST archives are validated before use.", "deployment.go": "Go",
@@ -24,9 +24,9 @@ var messages = map[string]map[string]string{
"instance.title": "Instance", "instance.back": "Back to dashboard", "instance.start": "Start", "instance.stop": "Stop", "instance.backup": "Back up", "instance.update": "Update", "instance.update_unknown": "No verified update is available.", "instance.players": "Players", "instance.password": "Server password", "instance.unavailable": "Unavailable", "instance.backups": "Backups", "instance.no_backups": "No backups", "instance.restore": "Restore", "instance.restore_confirm": "Restore this backup? The current server data will be replaced.", "instance.server_functions": "Server functions", "instance.module_unavailable": "No active module exposes server functions for this instance.", "instance.action_done.instance.start": "Instance started.", "instance.action_done.instance.stop": "Instance stopped.", "instance.action_done.backup.create": "Backup created.", "instance.action_done.backup.restore": "Backup restored.", "instance.action_failed.instance.start": "Unable to start the instance.", "instance.action_failed.instance.stop": "Unable to stop the instance.", "instance.action_failed.backup.create": "Unable to create the backup.", "instance.action_failed.backup.restore": "Unable to restore the backup.",
},
"fr": {
"brand.control": "Gestion des serveurs de jeux", "nav.primary": "Navigation principale", "nav.dashboard": "Tableau de bord", "nav.instances": "Instances", "nav.catalog": "Catalogue", "nav.backups": "Sauvegardes", "nav.audit": "Audit", "nav.settings": "Paramètres", "nav.planned": "Cette page est prévue pour un futur jalon",
"setup.title": "Créer l'administrateur", "setup.heading": "Bienvenue dans DoGaMa", "setup.introduction": "Créez le premier administrateur pour terminer la configuration.", "setup.submit": "Créer l'administrateur",
"login.title": "Connexion", "login.heading": "Se connecter à DoGaMa", "login.introduction": "Gérez vos serveurs de jeux depuis un espace sécurisé.", "login.submit": "Se connecter", "logout.submit": "Se déconnecter",
"brand.control": "Docker Gameserver Manager", "nav.primary": "Navigation principale", "nav.dashboard": "Tableau de bord", "nav.instances": "Instances", "nav.catalog": "Catalogue", "nav.backups": "Sauvegardes", "nav.audit": "Audit", "nav.settings": "Paramètres", "nav.administration": "Administration", "nav.planned": "Cette page est prévue pour un futur jalon",
"setup.title": "Créer l'administrateur", "setup.heading": "Bienvenue", "setup.introduction": "Créez le premier administrateur pour terminer la configuration.", "setup.submit": "Créer l'administrateur",
"login.title": "Connexion", "login.heading": "Se connecter", "login.introduction": "Gérez vos serveurs de jeux depuis un espace sécurisé.", "login.submit": "Se connecter", "logout.submit": "Se déconnecter",
"dashboard.title": "Tableau de bord", "dashboard.eyebrow": "Tableau de bord", "dashboard.heading": "Serveurs de jeux", "dashboard.introduction": "Vue d'ensemble de toutes vos instances de serveurs de jeux.", "dashboard.search": "Rechercher des instances", "dashboard.search_placeholder": "Rechercher une instance", "dashboard.summary": "Résumé des instances", "dashboard.total": "Instances totales", "dashboard.running": "En cours", "dashboard.stopped": "Arrêtées", "dashboard.updating": "Mise à jour", "dashboard.error": "Erreur", "dashboard.no_match": "Aucune instance correspondante", "dashboard.empty_heading": "Aucune instance déployée", "dashboard.empty_copy": "Vos serveurs de jeux apparaîtront ici lorsqu'ils seront ajoutés depuis le Catalogue.", "dashboard.instances_eyebrow": "Serveurs", "dashboard.instances": "Vos instances", "dashboard.activity_eyebrow": "Opérations", "dashboard.recent_activity": "Activité récente", "dashboard.no_activity": "Aucune activité récente", "dashboard.system_eyebrow": "Santé", "dashboard.system_status": "État du système", "dashboard.agent": "Agent Docker", "dashboard.database": "Base de données", "dashboard.storage": "Stockage", "dashboard.backups": "Sauvegardes", "dashboard.audit_log": "Journal d'audit", "dashboard.online": "En ligne", "dashboard.offline": "Hors ligne", "dashboard.healthy": "Saine", "dashboard.unavailable": "Indisponible", "dashboard.last_backup": "Dernière sauvegarde", "dashboard.no_backup": "Aucune sauvegarde", "dashboard.retention_days": "jours de rétention", "dashboard.unlimited": "Rétention illimitée", "dashboard.by": "par",
"catalog.title": "Catalogue", "catalog.eyebrow": "Bibliothèque de jeux", "catalog.heading": "Catalogue", "catalog.search": "Rechercher des jeux", "catalog.search_placeholder": "Rechercher un jeu", "catalog.scan": "Scanner", "catalog.found": "templates trouvés", "catalog.valid": "valides", "catalog.invalid": "invalides", "catalog.no_match": "Aucun jeu correspondant", "catalog.empty": "Aucun jeu disponible", "catalog.empty_admin": "Ajoutez des templates dans /var/lib/dogama/templates, puis utilisez Scanner.", "catalog.back": "Retour au catalogue", "catalog.minimum": "Minimum", "catalog.recommended": "Recommandé", "catalog.memory": "Mémoire", "catalog.storage": "Stockage", "catalog.other": "Autre", "catalog.deploy": "Déployer", "catalog.deploy_unavailable": "Le déploiement sera disponible au prochain bloc.",
"deployment.title": "Déployer", "deployment.eyebrow": "Nouvelle instance", "deployment.heading": "Configurer votre serveur", "deployment.name": "Nom de l’instance", "deployment.description": "Description de l’instance", "deployment.parameters": "Paramètres du jeu", "deployment.backup": "Importer une sauvegarde externe", "deployment.backup_help": "Les archives ZIP, TAR, TAR.GZ et TAR.ZST sont validées avant utilisation.", "deployment.go": "Go",
+8 -2
View File
@@ -196,6 +196,12 @@ a{
border-color: #20d9f388;
box-shadow: 0 14px 34px #0007,0 0 20px #20d9f312
}
.instance-card,
.instance-card:hover,
.instance-card:focus,
.instance-card:visited {
text-decoration: none;
}
.instance-art{
position: relative;
display: grid;
@@ -770,7 +776,7 @@ code{
border-radius: 10px
}
.instance-art{
height: 112px;
height: 189px;
border-bottom: 1px solid #424b6d
}
.instance-art:after{
@@ -803,7 +809,7 @@ code{
.summary-grid article{
position: relative;
padding: 15px 17px;
border-top: 2px solid #384260
border-top: 2px solid currentColor
}
.summary-grid strong{
display: block;
+96 -26
View File
@@ -263,12 +263,39 @@ button,
margin: 0 auto 24px;
}
.summary-grid {
grid-template-columns: repeat(5, minmax(0,1fr));
grid-template-columns: repeat(5, 1fr);
gap: 14px;
margin: 0 auto 22px;
}
.summary-card {
min-width: 0;
overflow: hidden;
position: relative;
display: flex;
align-items: center;
gap: 14px;
min-width: 0;
min-height: 82px;
padding: 14px 18px;
background:
radial-gradient(circle at 18% 50%, currentColor 0, transparent 34%),
linear-gradient(145deg, #101425dd, #090d1bdd);
border: 1px solid color-mix(in srgb, currentColor 35%, var(--border));
border-radius: 10px;
box-shadow:
inset 0 1px 0 #ffffff08,
0 8px 24px #0004;
overflow: hidden;
}
.summary-card::before {
content: "";
position: absolute;
inset: 0;
pointer-events: none;
opacity: .08;
}
.summary-card::after {
content: "";
@@ -281,37 +308,80 @@ button,
filter: blur(26px);
opacity: .18;
}
.summary-card .summary-icon {
float: right;
.summary-icon {
position: relative;
z-index: 1;
display: grid;
flex: 0 0 auto;
width: 48px;
height: 48px;
place-items: center;
width: 32px;
height: 32px;
border: 1px solid currentColor;
border-radius: 9px;
font-size: 1rem;
}
.summary-card.total {
color: var(--accent-cyan);
.summary-icon .ui-icon {
width: 29px;
height: 29px;
fill: currentColor;
filter:
drop-shadow(0 0 5px currentColor)
drop-shadow(0 0 10px color-mix(in srgb, currentColor 55%, transparent));
}
.summary-card.running {
color: var(--status-running);
}
.summary-card.stopped {
color: var(--status-error);
}
.summary-card.updating {
color: var(--status-warning);
}
.summary-card.error {
color: #ff3c5f;
}
.summary-card > span:not(.summary-icon) {
color: var(--text-secondary);
.summary-content {
position: relative;
z-index: 1;
min-width: 0;
border-left: 1px solid #303955;
padding-left: 10px;
}
.summary-card strong {
display: block;
color: var(--text-primary);
font-size: 1.55rem;
font-weight: 800;
line-height: 1.05;
}
.summary-card span {
display: block;
margin-top: 5px;
color: var(--text-secondary);
font-size: .78rem;
}
/* Total instances */
.summary-card.total {
color: var(--accent-cyan);
}
/* Running */
.summary-card.running {
color: var(--status-running);
}
/* Stopped */
.summary-card.stopped {
color: var(--status-error);
}
/* Updating */
.summary-card.updating {
color: var(--status-warning);
}
/* Error */
.summary-card.error {
color: #ff375f;
}
@media (max-width: 1050px) {
.summary-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 600px) {
.summary-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.summary-card:last-child {
grid-column: span 2;
}
}
.instance-card h3 {
margin: 5px 0 7px;
+1
View File
@@ -8,6 +8,7 @@
Settings · DoGaMa
</title>
<link rel="stylesheet" href="/static/app.css">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body class="app-body">
{{template "sidebar" .}}
+15 -11
View File
@@ -17,24 +17,22 @@
</a>
<nav aria-label="{{.Msg "nav.primary"}}">
<a class="nav-dashboard {{if eq .ActivePage "dashboard"}}active{{end}}" href="/">
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#home"></use></svg>
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#dashboard"></use></svg>
{{.Msg "nav.dashboard"}}
</a>
<a class="nav-catalog {{if eq .ActivePage "catalog"}}active{{end}}" href="/catalog">
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#menu_book"></use></svg>
{{.Msg "nav.catalog"}}
</a>
{{if .IsAdmin}}
<a class="nav-audit {{if eq .ActivePage "audit"}}active{{end}}" href="/audit">
{{.Msg "nav.audit"}}
</a>
<a class="nav-administration {{if eq .ActivePage "administration"}}active{{end}}" href="/administration">
Administration
</a>
{{end}}
<a class="nav-account {{if eq .ActivePage "account"}}active{{end}}" href="/account">
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#settings"></use></svg>
{{.Msg "nav.settings"}}
<a class="nav-audit {{if eq .ActivePage "audit"}}active{{end}}" href="/audit">
{{.Msg "nav.audit"}}
</a>
<a class="nav-administration {{if eq .ActivePage "administration"}}active{{end}}" href="/administration">
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#admin_panel_settings"></use></svg>
{{.Msg "nav.administration"}}
</a>
{{end}}
</nav>
<div class="account">
<p class="sr-only">{{.Msg "account.signed_in"}} <strong>{{.User.Username}}</strong>.</p>
@@ -51,6 +49,12 @@
</small>
</span>
</div>
<aside class="sidebar">
<a class="nav-account {{if eq .ActivePage "account"}}active{{end}}" href="/account">
<svg class="ui-icon" aria-hidden="true"><use href="/static/icons.svg#settings"></use></svg>
{{.Msg "nav.settings"}}
</a>
</aside>
<form method="post" action="/logout">
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
<button class="signout-button" type="submit">
+45 -30
View File
@@ -38,44 +38,59 @@
</header>
<section class="summary-grid" aria-label="{{.Msg "dashboard.summary"}}">
<article class="summary-card total">
<span>
{{.Msg "dashboard.total"}}
</span>
<strong>
{{len .Instances}}
</strong>
<div class="summary-icon" aria-hidden="true">
<svg class="ui-icon">
<use href="/static/icons.svg#server"></use>
</svg>
</div>
<div class="summary-content">
<strong>{{len .Instances}}</strong>
<span>{{.Msg "dashboard.total"}}</span>
</div>
</article>
<article class="summary-card running">
<span>
{{.Msg "dashboard.running"}}
</span>
<strong>
{{index .StatusCounts "running"}}
</strong>
<div class="summary-icon" aria-hidden="true">
<svg class="ui-icon">
<use href="/static/icons.svg#play"></use>
</svg>
</div>
<div class="summary-content">
<strong>{{index .StatusCounts "running"}}</strong>
<span>{{.Msg "dashboard.running"}}</span>
</div>
</article>
<article class="summary-card stopped">
<span>
{{.Msg "dashboard.stopped"}}
</span>
<strong>
{{index .StatusCounts "stopped"}}
</strong>
<div class="summary-icon" aria-hidden="true">
<svg class="ui-icon">
<use href="/static/icons.svg#stop"></use>
</svg>
</div>
<div class="summary-content">
<strong>{{index .StatusCounts "stopped"}}</strong>
<span>{{.Msg "dashboard.stopped"}}</span>
</div>
</article>
<article class="summary-card updating">
<span>
{{.Msg "dashboard.updating"}}
</span>
<strong>
{{index .StatusCounts "updating"}}
</strong>
<div class="summary-icon" aria-hidden="true">
<svg class="ui-icon">
<use href="/static/icons.svg#restart"></use>
</svg>
</div>
<div class="summary-content">
<strong>{{index .StatusCounts "updating"}}</strong>
<span>{{.Msg "dashboard.updating"}}</span>
</div>
</article>
<article class="summary-card error">
<span>
{{.Msg "dashboard.error"}}
</span>
<strong>
{{index .StatusCounts "error"}}
</strong>
<div class="summary-icon" aria-hidden="true">
<svg class="ui-icon">
<use href="/static/icons.svg#alert"></use>
</svg>
</div>
<div class="summary-content">
<strong>{{index .StatusCounts "error"}}</strong>
<span>{{.Msg "dashboard.error"}}</span>
</div>
</article>
</section>
<section class="dashboard-section" aria-labelledby="instances-heading">
+1
View File
@@ -9,6 +9,7 @@
· DoGaMa
</title>
<link rel="stylesheet" href="/static/app.css">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body class="app-body">
{{template "sidebar" .}}
@@ -9,6 +9,7 @@
· DoGaMa
</title>
<link rel="stylesheet" href="/static/app.css">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body class="app-body">
{{template "sidebar" .}}
+1
View File
@@ -8,6 +8,7 @@
Users · DoGaMa
</title>
<link rel="stylesheet" href="/static/app.css">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body class="app-body">
{{template "sidebar" .}}