feat(panel): per-game UI adaptation — sidebar, Server view, and dashboard transform by selected game
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
All checks were successful
Test Asgard Runner / test (push) Successful in 3s
Drives the panel off the active game (GameSwitcher selection) + the GameProfile registry, so each game visibly differs (not just accent color). Sidebar nav: Rust = full (uMod plugins + plugin configs); Conan/Soulmask/Dune drop uMod + plugin-configs and relabel reset (Wipe World / World Reset / Deep Desert), Dune relabels Console->Broadcast (no RCON) and is Docker-managed. ServerView: management-model badge + game-appropriate panels (Rust deploy + Oxide; Dune Docker/BattleGroup-Sietches; Conan clans/thralls/avatars/purge; Soulmask main-client cluster) with HONEST EmptyStates where no backend data exists yet. Dashboard: per-game reset terminology + stat labels. No invented routes (all map to existing router entries); no fabricated data. Build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2,9 +2,9 @@
|
||||
* gameProfiles.ts — Source of truth for per-game UI adaptation.
|
||||
*
|
||||
* Every game-specific label, terminology, Steam app ID, management model,
|
||||
* and stat field list lives here. The dashboard, server cards, wipe manager,
|
||||
* and any future multi-game surface should key off this registry — never
|
||||
* hard-code game-specific strings in components.
|
||||
* stat field list, AND sidebar nav lives here. The dashboard, server cards,
|
||||
* wipe manager, sidebar, and any future multi-game surface should key off this
|
||||
* registry — never hard-code game-specific strings in components.
|
||||
*
|
||||
* Backend status: the backend has NO game field on licenses yet. Today every
|
||||
* license is implicitly Rust. This registry is ready: when the backend adds a
|
||||
@@ -15,6 +15,26 @@
|
||||
* GAME_PROFILES. Nothing else changes.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Nav structure — drives the per-game sidebar
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** A single sidebar nav item. route must be an existing panel route path. */
|
||||
export interface NavItemDef {
|
||||
label: string
|
||||
route: string
|
||||
icon: string
|
||||
/** Permission key required to show this item (e.g. 'plugins.view'). Null = always visible. */
|
||||
permission: string | null
|
||||
}
|
||||
|
||||
/** A labelled section grouping nav items in the sidebar. */
|
||||
export interface NavSection {
|
||||
/** Section heading (eyebrow text). Empty string = no heading. */
|
||||
label: string
|
||||
items: NavItemDef[]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Union types — exhaustive, never widen to string
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -87,12 +107,67 @@ export interface GameProfile {
|
||||
* First entry is always Players; subsequent entries are game-specific.
|
||||
*/
|
||||
statFields: [string, string, string]
|
||||
/**
|
||||
* Per-game sidebar navigation. Ordered list of sections, each with items.
|
||||
* Items MUST use only existing panel routes (see router/index.ts).
|
||||
* The sidebar renders exactly these sections for the active game.
|
||||
*/
|
||||
nav: NavSection[]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Shared nav building blocks — reused across game nav definitions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const NAV_DASHBOARD: NavItemDef = { label: 'Dashboard', route: '/', icon: 'layout-dashboard', permission: null }
|
||||
const NAV_SERVER: NavItemDef = { label: 'Server', route: '/server', icon: 'server', permission: 'server.view' }
|
||||
const NAV_CONSOLE: NavItemDef = { label: 'Console', route: '/console', icon: 'terminal', permission: 'console.view' }
|
||||
const NAV_PLAYERS: NavItemDef = { label: 'Players', route: '/players', icon: 'users', permission: 'players.view' }
|
||||
const NAV_PLUGINS: NavItemDef = { label: 'Plugins (uMod)', route: '/plugins', icon: 'puzzle', permission: 'plugins.view' }
|
||||
const NAV_FILES: NavItemDef = { label: 'File manager', route: '/files', icon: 'folder-open', permission: 'files.view' }
|
||||
const NAV_PLUGIN_CONFIGS: NavItemDef = { label: 'Plugin configs', route: '/plugin-configs', icon: 'sliders', permission: null }
|
||||
const NAV_SCHEDULES: NavItemDef = { label: 'Schedules', route: '/schedules', icon: 'calendar-clock', permission: 'schedules.view' }
|
||||
const NAV_CHAT: NavItemDef = { label: 'Chat log', route: '/chat', icon: 'message-square', permission: 'chat.view' }
|
||||
const NAV_ANALYTICS: NavItemDef = { label: 'Analytics', route: '/analytics', icon: 'bar-chart-3', permission: 'analytics.view' }
|
||||
const NAV_ALERTS: NavItemDef = { label: 'Alerts', route: '/alerts', icon: 'triangle-alert', permission: 'alerts.view' }
|
||||
const NAV_NOTIFICATIONS: NavItemDef = { label: 'Notifications', route: '/notifications', icon: 'bell', permission: 'notifications.view' }
|
||||
const NAV_TEAM: NavItemDef = { label: 'Team', route: '/team', icon: 'users', permission: null }
|
||||
const NAV_STORE: NavItemDef = { label: 'Store', route: '/store/config', icon: 'shopping-cart', permission: 'store.view' }
|
||||
const NAV_MODULES: NavItemDef = { label: 'Modules', route: '/modules', icon: 'layers', permission: 'modules.view' }
|
||||
const NAV_CHANGELOG: NavItemDef = { label: 'Changelog', route: '/changelog', icon: 'file-text', permission: 'changelog.view' }
|
||||
const NAV_SETTINGS: NavItemDef = { label: 'Settings', route: '/settings', icon: 'settings', permission: 'settings.view' }
|
||||
const NAV_MAPS: NavItemDef = { label: 'Maps', route: '/maps', icon: 'map', permission: 'maps.view' }
|
||||
|
||||
/** Full Rust / 'all' nav — superset used as fallback. */
|
||||
const RUST_NAV: NavSection[] = [
|
||||
{ label: '', items: [NAV_DASHBOARD] },
|
||||
{
|
||||
label: 'Server',
|
||||
items: [NAV_SERVER, NAV_CONSOLE, NAV_PLAYERS, NAV_PLUGINS, NAV_FILES],
|
||||
},
|
||||
{ label: 'Plugin configs', items: [NAV_PLUGIN_CONFIGS] },
|
||||
{
|
||||
label: 'Operations',
|
||||
items: [
|
||||
{ label: 'Wipe', route: '/wipes', icon: 'trash-2', permission: 'wipes.view' },
|
||||
NAV_MAPS,
|
||||
NAV_SCHEDULES,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Monitoring',
|
||||
items: [NAV_CHAT, NAV_ANALYTICS, NAV_ALERTS, NAV_NOTIFICATIONS],
|
||||
},
|
||||
{
|
||||
label: 'Management',
|
||||
items: [NAV_TEAM, NAV_STORE, NAV_MODULES, NAV_CHANGELOG, NAV_SETTINGS],
|
||||
},
|
||||
]
|
||||
|
||||
export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
rust: {
|
||||
label: 'Rust',
|
||||
@@ -109,6 +184,7 @@ export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
group: 'Team',
|
||||
},
|
||||
statFields: ['Players', 'uMod', 'Wipe'],
|
||||
nav: RUST_NAV,
|
||||
},
|
||||
|
||||
conan: {
|
||||
@@ -130,6 +206,30 @@ export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
},
|
||||
special: ['Clans', 'Thralls', 'Avatars', 'Purge', 'PvP windows'],
|
||||
statFields: ['Players', 'Clans', 'Purge'],
|
||||
nav: [
|
||||
{ label: '', items: [NAV_DASHBOARD] },
|
||||
{
|
||||
label: 'Server',
|
||||
// Conan: no uMod/Oxide; has RCON console, maps, players, files
|
||||
items: [NAV_SERVER, NAV_CONSOLE, NAV_PLAYERS, NAV_FILES],
|
||||
},
|
||||
{
|
||||
label: 'Operations',
|
||||
items: [
|
||||
{ label: 'Wipe World', route: '/wipes', icon: 'trash-2', permission: 'wipes.view' },
|
||||
NAV_MAPS,
|
||||
NAV_SCHEDULES,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Monitoring',
|
||||
items: [NAV_CHAT, NAV_ANALYTICS, NAV_ALERTS, NAV_NOTIFICATIONS],
|
||||
},
|
||||
{
|
||||
label: 'Management',
|
||||
items: [NAV_TEAM, NAV_STORE, NAV_MODULES, NAV_CHANGELOG, NAV_SETTINGS],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
soulmask: {
|
||||
@@ -151,6 +251,29 @@ export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
},
|
||||
special: ['Cluster', 'Tribes'],
|
||||
statFields: ['Players', 'Tribe', 'Mask'],
|
||||
nav: [
|
||||
{ label: '', items: [NAV_DASHBOARD] },
|
||||
{
|
||||
label: 'Server',
|
||||
// Soulmask: no uMod/Oxide; has RCON+GM console, players, files
|
||||
items: [NAV_SERVER, NAV_CONSOLE, NAV_PLAYERS, NAV_FILES],
|
||||
},
|
||||
{
|
||||
label: 'Operations',
|
||||
items: [
|
||||
{ label: 'World Reset', route: '/wipes', icon: 'trash-2', permission: 'wipes.view' },
|
||||
NAV_SCHEDULES,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Monitoring',
|
||||
items: [NAV_CHAT, NAV_ANALYTICS, NAV_ALERTS],
|
||||
},
|
||||
{
|
||||
label: 'Management',
|
||||
items: [NAV_TEAM, NAV_STORE, NAV_MODULES, NAV_CHANGELOG, NAV_SETTINGS],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
dune: {
|
||||
@@ -170,6 +293,34 @@ export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
},
|
||||
special: ['Sietches', 'Deep Desert', 'Bases', 'Landsraad'],
|
||||
statFields: ['Players', 'Sietches', 'Control'],
|
||||
nav: [
|
||||
{ label: '', items: [NAV_DASHBOARD] },
|
||||
{
|
||||
label: 'Server',
|
||||
// Dune: no RCON (uses RabbitMQ); label console "Broadcast"; no maps route; no plugins
|
||||
items: [
|
||||
NAV_SERVER,
|
||||
{ label: 'Broadcast', route: '/console', icon: 'radio', permission: 'console.view' },
|
||||
NAV_PLAYERS,
|
||||
NAV_FILES,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Operations',
|
||||
items: [
|
||||
{ label: 'Deep Desert', route: '/wipes', icon: 'wind', permission: 'wipes.view' },
|
||||
NAV_SCHEDULES,
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Monitoring',
|
||||
items: [NAV_ANALYTICS, NAV_ALERTS],
|
||||
},
|
||||
{
|
||||
label: 'Management',
|
||||
items: [NAV_TEAM, NAV_STORE, NAV_CHANGELOG, NAV_SETTINGS],
|
||||
},
|
||||
],
|
||||
},
|
||||
} as const
|
||||
|
||||
|
||||
Reference in New Issue
Block a user