Add the games, runtime, and engine-version pages over the existing lobby,
runtime, and engine-version services (no new business logic).
- GET/POST /_gm/games list + create public game
- GET /_gm/games/{id} detail incl. runtime snapshot
- POST /_gm/games/{id}/force-start|stop game state actions
- POST /_gm/games/{id}/ban-member ban a member (uuid + reason)
- POST /_gm/games/{id}/runtime/restart|patch|force-next-turn
- GET/POST /_gm/engine-versions registry + register
- POST /_gm/engine-versions/{ver}/disable disable a version
Console depends on GameAdmin / RuntimeAdmin / EngineVersionAdmin interfaces
(satisfied by the concrete services) so the pages render in tests without a
database. Collection-mutating POSTs are mounted on the collection path to avoid
a static-vs-param route conflict in gin. Writes flow through the CSRF guard and
redirect back; the create form parses datetime-local as UTC.
Tests: list/detail (with and without a runtime), create (visibility/owner/time
assertions), force-start (+ bad-CSRF), ban-member (+ bad uuid), runtime patch
(+ missing version), engine-version list/register/disable, and unavailable.
Docs: backend/docs/admin-console.md page inventory extended.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
{{define "content" -}}
|
||||
{{$csrf := .CSRFToken}}
|
||||
{{with .Data}}
|
||||
<p><a href="/_gm/games">« all games</a></p>
|
||||
<h1>{{if .GameName}}{{.GameName}}{{else}}(unnamed){{end}}</h1>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Game</h2>
|
||||
<ul class="kv">
|
||||
<li>Game ID: <code>{{.GameID}}</code></li>
|
||||
<li>Visibility: {{.Visibility}}</li>
|
||||
<li>Status: {{.Status}}</li>
|
||||
<li>Owner: {{.Owner}}</li>
|
||||
<li>Players: {{.MinPlayers}}–{{.MaxPlayers}}</li>
|
||||
<li>Start gap: {{.StartGapHours}}h / {{.StartGapPlayers}} players</li>
|
||||
<li>Turn schedule: {{.TurnSchedule}}</li>
|
||||
<li>Target engine: {{.TargetEngineVersion}}</li>
|
||||
<li>Enrollment ends: {{.EnrollmentEndsAt}}</li>
|
||||
<li>Created: {{.CreatedAt}}</li>
|
||||
<li>Started: {{if .StartedAt}}{{.StartedAt}}{{else}}—{{end}}</li>
|
||||
<li>Finished: {{if .FinishedAt}}{{.FinishedAt}}{{else}}—{{end}}</li>
|
||||
</ul>
|
||||
{{if .Description}}<p>{{.Description}}</p>{{end}}
|
||||
<div class="actions">
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/force-start" onsubmit="return confirm('Force-start this game?');"><input type="hidden" name="_csrf" value="{{$csrf}}"><button type="submit">Force start</button></form>
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/force-stop" onsubmit="return confirm('Force-stop this game?');"><input type="hidden" name="_csrf" value="{{$csrf}}"><button type="submit" class="danger">Force stop</button></form>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Runtime</h2>
|
||||
{{if .HasRuntime}}
|
||||
<ul class="kv">
|
||||
<li>Status: {{.RuntimeStatus}}</li>
|
||||
<li>Engine version: {{.CurrentEngineVersion}}</li>
|
||||
<li>Engine health: {{.EngineHealth}}</li>
|
||||
<li>Current turn: {{.CurrentTurn}}</li>
|
||||
<li>Next generation: {{if .NextGenerationAt}}{{.NextGenerationAt}}{{else}}—{{end}}</li>
|
||||
<li>Paused: {{if .Paused}}yes{{else}}no{{end}}</li>
|
||||
</ul>
|
||||
<div class="actions">
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/runtime/restart" onsubmit="return confirm('Restart the engine container?');"><input type="hidden" name="_csrf" value="{{$csrf}}"><button type="submit">Restart</button></form>
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/runtime/force-next-turn" onsubmit="return confirm('Force the next turn now?');"><input type="hidden" name="_csrf" value="{{$csrf}}"><button type="submit">Force next turn</button></form>
|
||||
</div>
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/runtime/patch" class="form">
|
||||
<input type="hidden" name="_csrf" value="{{$csrf}}">
|
||||
<label>Patch to version <input type="text" name="target_version" placeholder="e.g. 0.1.1" required></label>
|
||||
<button type="submit">Patch</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<p class="note">No runtime record for this game yet.</p>
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<h2>Ban member</h2>
|
||||
<form method="post" action="/_gm/games/{{.GameID}}/ban-member" class="form" onsubmit="return confirm('Ban this member from the game?');">
|
||||
<input type="hidden" name="_csrf" value="{{$csrf}}">
|
||||
<label>User ID <input type="text" name="user_id" required></label>
|
||||
<label>Reason <input type="text" name="reason"></label>
|
||||
<button type="submit" class="danger">Ban member</button>
|
||||
</form>
|
||||
</section>
|
||||
{{end}}
|
||||
{{- end}}
|
||||
Reference in New Issue
Block a user