feat(panel): GameProfile registry + real-data dashboard (remove all mock/fake data)
DashboardView now renders the REAL server from useServerStore (connection/config + live WebSocket stats) + real 24h history from /analytics/timeseries, with honest EmptyStates ('install the companion agent') when there is no data. DELETED _dashboardMock.ts (the fake 8-server fleet/feed/wipes). PlayersChart hardened: removed the DEFAULT_SERIES fallback, renders an 'awaiting telemetry' empty state instead of a fabricated curve. New gameProfiles.ts: real per-game capability/terminology/stat registry (rust/conan/soulmask/dune; dune managementModel=docker-compose), ready to wire when the backend gains a per-license game field. No fake data. Build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
191
frontend/src/config/gameProfiles.ts
Normal file
191
frontend/src/config/gameProfiles.ts
Normal file
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* `game` column to `licenses` (or `server_config`), the frontend only needs to
|
||||
* read that field and call `useGameProfile(id)` — no component changes required.
|
||||
*
|
||||
* To add a new game: add a GameId union member and a corresponding entry in
|
||||
* GAME_PROFILES. Nothing else changes.
|
||||
*/
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Union types — exhaustive, never widen to string
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Every supported game identifier. */
|
||||
export type GameId = 'rust' | 'conan' | 'soulmask' | 'dune'
|
||||
|
||||
/** How the server process is managed. */
|
||||
export type ManagementModel = 'process+rcon' | 'docker-compose'
|
||||
|
||||
/** Mod ecosystem the game uses. */
|
||||
export type ModSystem = 'umod' | 'workshop' | 'none'
|
||||
|
||||
/** Primary console / remote-admin interface. */
|
||||
export type ConsoleType = 'rcon' | 'rcon+ingame' | 'rcon+gm' | 'rabbitmq'
|
||||
|
||||
/**
|
||||
* How a "reset" is performed — each value maps to a distinct wipe code path.
|
||||
* Pipe-delimited strings intentionally encode composite operations.
|
||||
*/
|
||||
export type ResetModel =
|
||||
| 'map-bp-wipe'
|
||||
| 'wipe-world-structures+decay'
|
||||
| 'worlddb-delete+decay'
|
||||
| 'deep-desert-coriolis-seed'
|
||||
|
||||
/** Cross-server or character-sharing mechanism. */
|
||||
export type ClusteringModel = 'none' | 'character-transfer' | 'main-client' | 'battlegroup'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// GameProfile shape
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface GameTerminology {
|
||||
/** What the operator calls a reset / wipe. */
|
||||
reset: string
|
||||
/** What the operator calls plugins / mods (null if no mod system). */
|
||||
mods: string | null
|
||||
/** What the operator calls a player group / faction. */
|
||||
group: string
|
||||
}
|
||||
|
||||
export interface GamePorts {
|
||||
game: number
|
||||
query: number
|
||||
rcon: number
|
||||
cluster?: number
|
||||
}
|
||||
|
||||
export interface GameProfile {
|
||||
/** Human-readable game name. */
|
||||
label: string
|
||||
/** CSS design-token key — maps to data-game attr and --accent token. */
|
||||
accent: string
|
||||
managementModel: ManagementModel
|
||||
steamAppId: number | { windows: number; linux: number }
|
||||
/** Default ports (game-specific defaults; operator can override). */
|
||||
ports?: GamePorts
|
||||
mods: ModSystem
|
||||
console: ConsoleType
|
||||
resetModel: ResetModel
|
||||
clustering: ClusteringModel
|
||||
/** Available map names, if the game ships with named maps. */
|
||||
maps?: string[]
|
||||
terminology: GameTerminology
|
||||
/** Notable game-specific mechanics that affect server administration. */
|
||||
special?: string[]
|
||||
/**
|
||||
* Stat field labels shown on server cards and the dashboard.
|
||||
* First entry is always Players; subsequent entries are game-specific.
|
||||
*/
|
||||
statFields: [string, string, string]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registry
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const GAME_PROFILES: Record<GameId, GameProfile> = {
|
||||
rust: {
|
||||
label: 'Rust',
|
||||
accent: 'rust',
|
||||
managementModel: 'process+rcon',
|
||||
steamAppId: 258550,
|
||||
mods: 'umod',
|
||||
console: 'rcon',
|
||||
resetModel: 'map-bp-wipe',
|
||||
clustering: 'none',
|
||||
terminology: {
|
||||
reset: 'Wipe',
|
||||
mods: 'Plugins',
|
||||
group: 'Team',
|
||||
},
|
||||
statFields: ['Players', 'uMod', 'Wipe'],
|
||||
},
|
||||
|
||||
conan: {
|
||||
label: 'Conan Exiles',
|
||||
accent: 'conan',
|
||||
managementModel: 'process+rcon',
|
||||
steamAppId: 443030,
|
||||
ports: { game: 7777, query: 27015, rcon: 25575 },
|
||||
mods: 'workshop',
|
||||
console: 'rcon+ingame',
|
||||
// Player progress persists across world wipes — only structures are cleared.
|
||||
resetModel: 'wipe-world-structures+decay',
|
||||
clustering: 'character-transfer',
|
||||
maps: ['Exiled Lands', 'Isle of Siptah'],
|
||||
terminology: {
|
||||
reset: 'Wipe World',
|
||||
mods: 'Mods',
|
||||
group: 'Clan',
|
||||
},
|
||||
special: ['Clans', 'Thralls', 'Avatars', 'Purge', 'PvP windows'],
|
||||
statFields: ['Players', 'Clans', 'Purge'],
|
||||
},
|
||||
|
||||
soulmask: {
|
||||
label: 'Soulmask',
|
||||
accent: 'soulmask',
|
||||
managementModel: 'process+rcon',
|
||||
// Different Steam app IDs per OS (uncommon — store this explicitly).
|
||||
steamAppId: { windows: 3017310, linux: 3017300 },
|
||||
ports: { game: 8777, query: 27015, rcon: 19000, cluster: 20000 },
|
||||
mods: 'workshop',
|
||||
console: 'rcon+gm',
|
||||
resetModel: 'worlddb-delete+decay',
|
||||
clustering: 'main-client',
|
||||
maps: ['Cloud Mist Forest', 'Shifting Sands'],
|
||||
terminology: {
|
||||
reset: 'World Reset',
|
||||
mods: 'Workshop Mods',
|
||||
group: 'Tribe',
|
||||
},
|
||||
special: ['Cluster', 'Tribes'],
|
||||
statFields: ['Players', 'Tribe', 'Mask'],
|
||||
},
|
||||
|
||||
dune: {
|
||||
label: 'Dune: Awakening',
|
||||
accent: 'dune',
|
||||
managementModel: 'docker-compose',
|
||||
steamAppId: 4754530,
|
||||
mods: 'none',
|
||||
// Dune uses RabbitMQ for its admin messaging — not a standard RCON port.
|
||||
console: 'rabbitmq',
|
||||
resetModel: 'deep-desert-coriolis-seed',
|
||||
clustering: 'battlegroup',
|
||||
terminology: {
|
||||
reset: 'Deep Desert reset',
|
||||
mods: null,
|
||||
group: 'Guild',
|
||||
},
|
||||
special: ['Sietches', 'Deep Desert', 'Bases', 'Landsraad'],
|
||||
statFields: ['Players', 'Sietches', 'Control'],
|
||||
},
|
||||
} as const
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helper
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the GameProfile for the given id, falling back to Rust if the id is
|
||||
* unknown (forward-compatibility: unknown games show Rust defaults until their
|
||||
* profile is added).
|
||||
*
|
||||
* @example
|
||||
* const profile = useGameProfile('rust')
|
||||
* console.log(profile.terminology.reset) // 'Wipe'
|
||||
*/
|
||||
export function useGameProfile(id: string): GameProfile {
|
||||
return (GAME_PROFILES as Record<string, GameProfile>)[id] ?? GAME_PROFILES.rust
|
||||
}
|
||||
Reference in New Issue
Block a user