Improve application responsiveness and background processing
This commit is contained in:
+21
-17
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
let { data }: { data: import('./$types').PageData } = $props();
|
||||
const snapshot = $derived($fleet.receivedAt ? $fleet : data.fleetSnapshot);
|
||||
const visibleFleet = $derived($fleet.receivedAt ? $fleetServers : data.fleetSnapshot.servers);
|
||||
import { onMount, untrack } from 'svelte';
|
||||
import { afterNavigate, replaceState } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
@@ -60,7 +63,7 @@
|
||||
} catch { /* Preferences also work when storage is disabled. */ }
|
||||
readViewUrl();
|
||||
preferencesReady = true;
|
||||
void refreshFleet();
|
||||
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
@@ -75,25 +78,26 @@
|
||||
if (url.href !== window.location.href) replaceState(url, $page.state);
|
||||
});
|
||||
});
|
||||
const snapshotAge = $derived.by(() => { $uiNow; return Math.max(0, Math.floor((Date.now() - $fleet.receivedAt) / 1000)); });
|
||||
const snapshotAge = $derived.by(() => { $uiNow; return Math.max(0, Math.floor((Date.now() - ($fleet.receivedAt || data.fleetSnapshot.serverNow)) / 1000)); });
|
||||
const integrations = $derived($fleetIntegrations ?? data.fleetSnapshot.integrations);
|
||||
|
||||
let servers = $derived($fleetServers.map(server => server.health === 'online' && !freshServer(server, $uiNow)
|
||||
? { ...server, health: 'stale' as const } : server));
|
||||
let activeOperations = $derived($fleet.operations.filter(op => op.state !== 'done'));
|
||||
let servers = $derived(visibleFleet);
|
||||
const observationNow = () => untrack(() => $fleet.receivedAt ? $uiNow : data.fleetSnapshot.serverNow);
|
||||
let activeOperations = $derived(snapshot.operations.filter(op => op.state !== 'done'));
|
||||
let attentionOperations = $derived(activeOperations.filter(op => op.state === 'attention'));
|
||||
let campaigns = $derived(new Set(activeOperations.filter(op => op.kind === 'campaign').map(op => op.group)).size);
|
||||
let healthy = $derived(servers.filter(server => freshServer(server, $uiNow)));
|
||||
let healthy = $derived(servers.filter(server => freshServer(server, observationNow())));
|
||||
let players = $derived(healthy.reduce((sum, server) => sum + (server.last_players ?? 0), 0));
|
||||
let empty = $derived(healthy.filter(server => server.last_players === 0).length);
|
||||
let problems = $derived(servers.filter(server => server.health === 'offline' || server.health === 'stale'));
|
||||
let starting = $derived(servers.filter(server => server.health === 'starting').length);
|
||||
let provisioning = $derived(servers.filter(server => server.health === 'provisioning').length);
|
||||
let filtered = $derived(servers.filter(server => matchesFleet(server, query, filter, game, pinned, activeOperations, $uiNow))
|
||||
let filtered = $derived(servers.filter(server => matchesFleet(server, query, filter, game, pinned, activeOperations, observationNow()))
|
||||
.sort((a, b) => {
|
||||
const pinOrder = Number(pinned.includes(b.name)) - Number(pinned.includes(a.name));
|
||||
if (pinOrder) return pinOrder;
|
||||
const rank = (server: FleetServer) => sort === 'players' ? (freshServer(server, $uiNow) ? server.last_players ?? -1 : -1)
|
||||
: sort === 'round' ? currentRound(server, $telemetryByServer.get(server.name), $uiNow) ?? -1
|
||||
const rank = (server: FleetServer) => sort === 'players' ? (freshServer(server, observationNow()) ? server.last_players ?? -1 : -1)
|
||||
: sort === 'round' ? currentRound(server, $telemetryByServer.get(server.name), observationNow()) ?? -1
|
||||
: sort === 'duration' ? matchDuration(server) : 0;
|
||||
return rank(b) - rank(a) || serverTitle(a.name).localeCompare(serverTitle(b.name), undefined, { numeric: true });
|
||||
}));
|
||||
@@ -109,12 +113,12 @@
|
||||
}
|
||||
return [...result.entries()].sort(([, a], [, b]) => a.title.localeCompare(b.title));
|
||||
});
|
||||
let spotlight = $derived(servers.filter(server => currentRound(server, $telemetryByServer.get(server.name), $uiNow) !== null)
|
||||
let spotlight = $derived(servers.filter(server => currentRound(server, $telemetryByServer.get(server.name), observationNow()) !== null)
|
||||
.sort((a, b) => matchDuration(b) - matchDuration(a))[0]);
|
||||
|
||||
function matchDuration(server: FleetServer): number {
|
||||
return freshServer(server, $uiNow) && server.active_since && server.game_started_at && !server.game_ended_at
|
||||
&& (server.last_players ?? 0) > 0 ? Math.max(0, $uiNow - Date.parse(server.game_started_at)) : -1;
|
||||
return freshServer(server, observationNow()) && server.active_since && server.game_started_at && !server.game_ended_at
|
||||
&& (server.last_players ?? 0) > 0 ? Math.max(0, observationNow() - Date.parse(server.game_started_at)) : -1;
|
||||
}
|
||||
function togglePin(name: string) { pinned = pinned.includes(name) ? pinned.filter(item => item !== name) : [...pinned, name]; }
|
||||
function launch(selection: { game: ZombieGame; slug: string } | null = null) {
|
||||
@@ -139,7 +143,7 @@
|
||||
<button onclick={() => void refreshFleet()}>Retry now</button></div>
|
||||
{/if}
|
||||
|
||||
{#if !$fleet.receivedAt}
|
||||
{#if !$fleet.receivedAt && !data.fleetSnapshot}
|
||||
{#if !$fleetError}<div class="loading" role="status">Loading your fleet…</div>{/if}
|
||||
{:else}
|
||||
{#if servers.length}<div class="overview" aria-label="Fleet summary">
|
||||
@@ -149,10 +153,10 @@
|
||||
<a class="metric-link" class:no-campaigns={!campaigns} href="/campaigns"><strong>{campaigns}</strong> active campaigns</a>
|
||||
<span class="freshness">{$fleetError ? 'Reconnecting' : 'Updated'} · {snapshotAge < 60 ? `${snapshotAge}s` : `${Math.floor(snapshotAge / 60)}m`} ago</span>
|
||||
</div>{/if}
|
||||
{#if $fleetIntegrations?.native && !$fleetIntegrations.hostsReady}
|
||||
<div class="setup-note"><span><strong>Prepare a game host</strong> · {$fleetIntegrations.hostsTotal ? 'Hosts are connected or enrolled but need setup before new deployments.' : 'Add a host, prepare its runtime, and download game files.'}</span><a href="/hosts">Review hosts →</a></div>
|
||||
{:else if $page.data.user?.role === 'admin' && $fleetIntegrations && !$fleetIntegrations.native && (!$fleetIntegrations.komodo || !$fleetIntegrations.rcon)}
|
||||
<div class="setup-note"><span><strong>Finish system setup</strong> · {!$fleetIntegrations.komodo ? 'Komodo' : ''}{!$fleetIntegrations.komodo && !$fleetIntegrations.rcon ? ' and ' : ''}{!$fleetIntegrations.rcon ? 'RCON' : ''} not configured.</span><a href="/settings">Review setup →</a></div>
|
||||
{#if integrations?.native && !integrations.hostsReady}
|
||||
<div class="setup-note"><span><strong>Prepare a game host</strong> · {integrations.hostsTotal ? 'Hosts are connected or enrolled but need setup before new deployments.' : 'Add a host, prepare its runtime, and download game files.'}</span><a href="/hosts">Review hosts →</a></div>
|
||||
{:else if $page.data.user?.role === 'admin' && $fleetIntegrations && !integrations.native && (!integrations.komodo || !integrations.rcon)}
|
||||
<div class="setup-note"><span><strong>Finish system setup</strong> · {!integrations.komodo ? 'Komodo' : ''}{!integrations.komodo && !integrations.rcon ? ' and ' : ''}{!integrations.rcon ? 'RCON' : ''} not configured.</span><a href="/settings">Review setup →</a></div>
|
||||
{/if}
|
||||
|
||||
{#if problems.length || attentionOperations.length || starting || provisioning}
|
||||
|
||||
Reference in New Issue
Block a user