Retain host and server scope during investigations

This commit is contained in:
2026-10-05 19:05:07 -04:00
parent 056fbd7517
commit cd577b646c
12 changed files with 95 additions and 29 deletions
+8 -5
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { contextHref } from '$lib/navigation-context.js';
import BackLink from '$ui/components/BackLink.svelte';
let { data }: { data: import('./$types').PageData } = $props();
import RuntimeVersion from '$ui/components/RuntimeVersion.svelte';
@@ -284,7 +285,7 @@
{#if hasDiagnosticIssue}
<section class="connection-issue" aria-label="Server connection issue">
<div><strong>{effectiveHealth === 'stale' ? 'Server report is outdated' : 'Server is not responding'}</strong><p>Player count is unknown. {effectiveSeen ? `Last successful report ${ago(effectiveSeen, $uiNow)}.` : 'No successful report has been received.'} {native && !server.host?.connected ? 'The host agent is offline; the game may still be running.' : ''}</p></div>
<div class="issue-actions"><Button size="sm" onclick={() => changeTab('diagnostics')}>Diagnose connection</Button><Button size="sm" variant="ghost" onclick={() => changeTab('logs')}>Open logs</Button>{#if native && server.host_id}<Button size="sm" href={`/hosts/${server.host_id}`}>Check host</Button>{:else}<Button size="sm" href="/settings">Check system setup</Button>{/if}</div>
<div class="issue-actions"><Button size="sm" onclick={() => changeTab('diagnostics')}>Diagnose connection</Button><Button size="sm" variant="ghost" onclick={() => changeTab('logs')}>Open logs</Button>{#if native && server.host_id}<Button size="sm" href={contextHref(`/hosts/${server.host_id}`, $page.url)}>Check host</Button>{:else}<Button size="sm" href="/settings">Check system setup</Button>{/if}</div>
</section>
{/if}
<div class="tabs-row">
@@ -384,7 +385,7 @@
{native ? 'Probe RCON through agent' : 'Probe RCON'}
</Button>
{/if}
{#if server.host_id}<Button variant="secondary" size="sm" href={`/hosts/${server.host_id}`}>Inspect host</Button>{/if}
{#if server.host_id}<Button variant="secondary" size="sm" href={contextHref(`/hosts/${server.host_id}`, $page.url)}>Inspect host</Button>{/if}
</div>
{#if rconProbe?.ok}
@@ -402,7 +403,7 @@
<h2>Configuration</h2>
</div>
<div class="diag-grid">
{#if native}<div class="kv"><span class="k">Host</span><span class="v"><a href={`/hosts/${server.host_id}`}>{server.host?.name ?? server.host_id}</a></span></div><div class="kv"><span class="k">Instance</span><span class="v mono">{server.native_instance_id}</span></div><div class="kv"><span class="k">Generation</span><span class="v mono">{server.instance_generation}</span></div><div class="kv"><span class="k">Game-file version</span><span class="v mono"><a href="/game-files">{server.game_library_id}</a></span></div>{#if server.network}<div class="kv"><span class="k">Local UDP binding</span><span class="v mono">{server.network.bindAddress}:{server.network.localPort}</span></div><div class="kv"><span class="k">Public / NAT endpoint</span><span class="v mono">{server.network.publicAddress || server.host?.publicAddress || server.host?.hostname || 'Not configured'}:{server.network.publicPort ?? server.network.localPort}</span></div>{/if}
{#if native}<div class="kv"><span class="k">Host</span><span class="v"><a href={contextHref(`/hosts/${server.host_id}`, $page.url)}>{server.host?.name ?? server.host_id}</a></span></div><div class="kv"><span class="k">Instance</span><span class="v mono">{server.native_instance_id}</span></div><div class="kv"><span class="k">Generation</span><span class="v mono">{server.instance_generation}</span></div><div class="kv"><span class="k">Game-file version</span><span class="v mono"><a href="/game-files">{server.game_library_id}</a></span></div>{#if server.network}<div class="kv"><span class="k">Local UDP binding</span><span class="v mono">{server.network.bindAddress}:{server.network.localPort}</span></div><div class="kv"><span class="k">Public / NAT endpoint</span><span class="v mono">{server.network.publicAddress || server.host?.publicAddress || server.host?.hostname || 'Not configured'}:{server.network.publicPort ?? server.network.localPort}</span></div>{/if}
{/if}
<div class="kv"><span class="k">Game port</span><span class="v mono">{server.game_port ?? '(unresolved)'}</span></div>
<div class="kv"><span class="k">Game</span><span class="v mono">{server.game ?? '(unset)'}</span></div>
@@ -416,6 +417,7 @@
{:else if activeTab === 'matches'}
{#key name}<MatchHistory server={name} />{/key}
{:else if activeTab === 'history'}
<div class="history-links"><Button href={contextHref(`/provisioning?view=history&server=${encodeURIComponent(name)}`, $page.url)}>Provisioning history</Button><Button href={contextHref(`/hosts/operations?server=${encodeURIComponent(name)}`, $page.url)}>Host operation history</Button></div>
{#if operations.length}
<Card padding="lg">
<div class="panel-head">
@@ -424,7 +426,7 @@
</div>
<div class="server-operations">
{#each operations as operation (operation.key)}
<a href={operation.href}>
<a href={contextHref(operation.href, $page.url)}>
<strong>{operation.label}</strong>
<span>{operation.detail}</span>
<StatusBadge state={operation.state} />
@@ -447,7 +449,7 @@
<div class="history">
{#each history.slice(0,historyLimit) as d (d.id)}
{@const mine = d.servers.find((s) => s.server === name)!}
<a class="hist-row s-{mine.restart_state}" href="/campaigns/{d.id}">
<a class="hist-row s-{mine.restart_state}" href={contextHref(`/campaigns/${d.id}`, $page.url)}>
<span class="hist-action">{d.action}</span>
<span class="hist-state">
<StatusBadge state={mine.restart_state} />
@@ -476,6 +478,7 @@
{/if}
<style>
.history-links { display:flex; flex-wrap:wrap; gap:12px; }
.server-actions { text-align: right; }
.server-actions summary { cursor: pointer; padding: 9px 12px; border: 1px solid var(--border-strong); border-radius: var(--radius-md); font-size: var(--text-sm); }
.server-actions[open] summary { margin-bottom: 10px; }