Add Prettier and ESLint tooling (Refs #77)
This commit is contained in:
@@ -1,42 +1,164 @@
|
||||
<script lang="ts">
|
||||
import type { Host } from '$lib/hosts.js';
|
||||
import { contextHref } from '$lib/navigation-context.js';
|
||||
import { hostListStatus, hostReadingsStale, hostCpuUsage, hostUsedSpace } from '$ui/host-overview.js';
|
||||
import {
|
||||
hostListStatus,
|
||||
hostReadingsStale,
|
||||
hostCpuUsage,
|
||||
hostUsedSpace
|
||||
} from '$ui/host-overview.js';
|
||||
import { plural } from '$ui/plural.js';
|
||||
import Badge from './primitives/Badge.svelte';
|
||||
let { hosts, now, returnTo = '/hosts' }: { hosts: (Host & { serverCount: number; playerCount: number; unreportedInstances: number })[]; now: number; returnTo?: string } = $props();
|
||||
let {
|
||||
hosts,
|
||||
now,
|
||||
returnTo = '/hosts'
|
||||
}: {
|
||||
hosts: (Host & { serverCount: number; playerCount: number; unreportedInstances: number })[];
|
||||
now: number;
|
||||
returnTo?: string;
|
||||
} = $props();
|
||||
</script>
|
||||
|
||||
<div class="table-wrap"><table>
|
||||
<thead><tr><th>Host</th><th>Status</th><th title="Assigned servers, including stopped servers">Servers</th><th title="Players reported by online servers">Players</th><th>CPU</th><th>Memory <span>used / total</span></th><th>Disk <span>used / total</span></th></tr></thead>
|
||||
<tbody>{#each hosts as host (host.id)}
|
||||
{@const status = hostListStatus(host, now)}
|
||||
{@const stale = hostReadingsStale(host, now)}
|
||||
<tr>
|
||||
<td><a class="name" href={contextHref(`/hosts/${host.id}`, returnTo)}>{host.name}</a>{#if host.hostname && host.hostname !== host.name}<span class="secondary">{host.hostname}</span>{/if}
|
||||
{#if stale && host.lastHeartbeat}<span class="secondary">Resource readings stale</span>{/if}</td>
|
||||
<td class="status"><Badge variant={status.tone}>{status.label}</Badge>{#if status.detail}<a class="reason" href={contextHref(`/hosts/${host.id}?tab=${status.tab}`, returnTo)}>{status.detail}</a>{/if}</td>
|
||||
<td><a href={contextHref(`/hosts/${host.id}?tab=servers`, returnTo)} aria-label={`${host.serverCount} assigned ${plural(host.serverCount, 'server')} on ${host.name}`}>{host.serverCount}</a></td>
|
||||
<td title={host.unreportedInstances ? `Player counts unavailable for ${host.unreportedInstances} of ${host.serverCount} ${plural(host.serverCount, 'server')}` : 'Players reported by online servers'}>{host.unreportedInstances === host.serverCount && host.serverCount > 0 ? '—' : `${host.playerCount}${host.unreportedInstances ? '+' : ''}`}</td>
|
||||
<td class:stale>{hostCpuUsage(host.inventory.cpuUsagePercent)}</td>
|
||||
<td class:stale>{hostUsedSpace(host.inventory.memoryTotal, host.inventory.memoryAvailable)}</td>
|
||||
<td class:stale>{hostUsedSpace(host.inventory.storageTotal, host.inventory.storageAvailable)}</td>
|
||||
</tr>
|
||||
{/each}</tbody>
|
||||
</table></div>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead
|
||||
><tr
|
||||
><th>Host</th><th>Status</th><th title="Assigned servers, including stopped servers"
|
||||
>Servers</th
|
||||
><th title="Players reported by online servers">Players</th><th>CPU</th><th
|
||||
>Memory <span>used / total</span></th
|
||||
><th>Disk <span>used / total</span></th></tr
|
||||
></thead
|
||||
>
|
||||
<tbody
|
||||
>{#each hosts as host (host.id)}
|
||||
{@const status = hostListStatus(host, now)}
|
||||
{@const stale = hostReadingsStale(host, now)}
|
||||
<tr>
|
||||
<td
|
||||
><a class="name" href={contextHref(`/hosts/${host.id}`, returnTo)}
|
||||
>{host.name}</a
|
||||
>{#if host.hostname && host.hostname !== host.name}<span class="secondary"
|
||||
>{host.hostname}</span
|
||||
>{/if}
|
||||
{#if stale && host.lastHeartbeat}<span class="secondary"
|
||||
>Resource readings stale</span
|
||||
>{/if}</td
|
||||
>
|
||||
<td class="status"
|
||||
><Badge variant={status.tone}>{status.label}</Badge>{#if status.detail}<a
|
||||
class="reason"
|
||||
href={contextHref(`/hosts/${host.id}?tab=${status.tab}`, returnTo)}
|
||||
>{status.detail}</a
|
||||
>{/if}</td
|
||||
>
|
||||
<td
|
||||
><a
|
||||
href={contextHref(`/hosts/${host.id}?tab=servers`, returnTo)}
|
||||
aria-label={`${host.serverCount} assigned ${plural(host.serverCount, 'server')} on ${host.name}`}
|
||||
>{host.serverCount}</a
|
||||
></td
|
||||
>
|
||||
<td
|
||||
title={host.unreportedInstances
|
||||
? `Player counts unavailable for ${host.unreportedInstances} of ${host.serverCount} ${plural(host.serverCount, 'server')}`
|
||||
: 'Players reported by online servers'}
|
||||
>{host.unreportedInstances === host.serverCount && host.serverCount > 0
|
||||
? '—'
|
||||
: `${host.playerCount}${host.unreportedInstances ? '+' : ''}`}</td
|
||||
>
|
||||
<td class:stale>{hostCpuUsage(host.inventory.cpuUsagePercent)}</td>
|
||||
<td class:stale
|
||||
>{hostUsedSpace(
|
||||
host.inventory.memoryTotal,
|
||||
host.inventory.memoryAvailable
|
||||
)}</td
|
||||
>
|
||||
<td class:stale
|
||||
>{hostUsedSpace(
|
||||
host.inventory.storageTotal,
|
||||
host.inventory.storageAvailable
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
{/each}</tbody
|
||||
>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.table-wrap { overflow-x:auto; border:1px solid var(--border-subtle); border-radius:var(--radius-md); }
|
||||
table { width:100%; min-width:850px; border-collapse:collapse; text-align:left; font-size:var(--text-sm); }
|
||||
th { padding:12px 16px; color:var(--text-secondary); background:var(--surface-sunken); font-weight:500; font-size:var(--text-xs); }
|
||||
th span { display:block; font-weight:400; margin-top:3px; }
|
||||
td { padding:16px; background:var(--surface); border-top:1px solid var(--border-subtle); font-variant-numeric:tabular-nums; }
|
||||
tr:hover td { background:var(--surface-raised); }
|
||||
a { color:var(--accent-primary-hover); } .name { color:var(--text-primary); font-weight:600; text-decoration:none; overflow-wrap:anywhere; }
|
||||
.name:hover { color:var(--accent-primary-hover); text-decoration:underline; }
|
||||
.status { max-width:330px; min-width:140px; }
|
||||
.secondary,.reason { display:block; font-size:var(--text-xs); color:var(--text-secondary); margin-top:6px; line-height:1.5; }
|
||||
.reason { overflow-wrap:anywhere; text-decoration:none; } .reason:hover { text-decoration:underline; color:var(--accent-primary-hover); }
|
||||
.stale { color:var(--text-secondary); }
|
||||
a:focus-visible { outline:2px solid var(--accent-primary); outline-offset:3px; }
|
||||
.table-wrap {
|
||||
overflow-x: auto;
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
min-width: 850px;
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
font-size: var(--text-sm);
|
||||
}
|
||||
th {
|
||||
padding: 12px 16px;
|
||||
color: var(--text-secondary);
|
||||
background: var(--surface-sunken);
|
||||
font-weight: 500;
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
th span {
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
margin-top: 3px;
|
||||
}
|
||||
td {
|
||||
padding: 16px;
|
||||
background: var(--surface);
|
||||
border-top: 1px solid var(--border-subtle);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
tr:hover td {
|
||||
background: var(--surface-raised);
|
||||
}
|
||||
a {
|
||||
color: var(--accent-primary-hover);
|
||||
}
|
||||
.name {
|
||||
color: var(--text-primary);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.name:hover {
|
||||
color: var(--accent-primary-hover);
|
||||
text-decoration: underline;
|
||||
}
|
||||
.status {
|
||||
max-width: 330px;
|
||||
min-width: 140px;
|
||||
}
|
||||
.secondary,
|
||||
.reason {
|
||||
display: block;
|
||||
font-size: var(--text-xs);
|
||||
color: var(--text-secondary);
|
||||
margin-top: 6px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.reason {
|
||||
overflow-wrap: anywhere;
|
||||
text-decoration: none;
|
||||
}
|
||||
.reason:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--accent-primary-hover);
|
||||
}
|
||||
.stale {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
a:focus-visible {
|
||||
outline: 2px solid var(--accent-primary);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user