+6
-6
src/App.svelte
+6
-6
src/App.svelte
···
1
1
<script lang="ts">
2
2
import { onMount } from 'svelte';
3
-
import { formatDistanceToNow, addSeconds, formatDate, formatISO9075 } from 'date-fns';
3
+
import { formatDistanceToNow, addSeconds, subSeconds, formatDate, formatISO9075 } from 'date-fns';
4
4
import { Progress, Switch } from '@skeletonlabs/skeleton-svelte';
5
5
import orderBy from "lodash/orderBy";
6
+
import { formatNumber, formatUptime } from './lib/utils';
6
7
import instancesData from './instances.json';
7
-
import numeral from 'numeral';
8
8
9
9
const APP_TITLE = 'plcbundle instances'
10
10
const PLC_DIRECTORY = 'plc.directory'
···
34
34
let instances = $state(instancesData.sort(() => Math.random() - 0.5))
35
35
36
36
const instanceOrderBy = [['_head', 'status.latency'], ['desc', 'asc']]
37
-
38
-
function formatNumber(n: number) {
39
-
return numeral(n).format()
40
-
}
41
37
42
38
async function getStatus(instance: Instance) {
43
39
let statusResp: object | undefined;
···
206
202
<th>head</th>
207
203
<th>root</th>
208
204
<th>version</th>
205
+
<th>ws?</th>
206
+
<th>uptime</th>
209
207
<th>latency</th>
210
208
</tr>
211
209
</thead>
···
219
217
<td><span class="font-mono text-xs {instance._head ? (isConflict ? 'text-error-600' : 'text-success-600') : 'opacity-50'}">{#if instance.status?.bundles?.head_hash}{instance.status?.bundles?.head_hash.slice(0, 7)}{/if}</span></td>
220
218
<td><span class="font-mono text-xs {instance.status ? (instance.status?.bundles?.root_hash === ROOT ? 'text-success-600' : 'text-error-600') : ''}">{#if instance.status?.bundles?.root_hash}{instance.status?.bundles?.root_hash.slice(0, 7)}{/if}</span></td>
221
219
<td>{#if instance.status?.server?.version}{instance.status?.server?.version}{/if}</td>
220
+
<td>{#if instance.status?.server?.websocket_enabled}✔︎{:else if instance.status}<span class="opacity-25">-</span>{/if}</td>
221
+
<td class="text-xs">{#if instance.status?.server?.uptime_seconds}{formatUptime(instance.status?.server?.uptime_seconds)}{/if}</td>
222
222
<td class="opacity-50">{#if instance.status?.latency}{Math.round(instance.status?.latency)}ms{/if}</td>
223
223
</tr>
224
224
{/each}
+3
-1
src/instances.json
+3
-1
src/instances.json
+53
src/lib/utils.ts
+53
src/lib/utils.ts
···
1
+
import numeral from 'numeral';
2
+
3
+
export function formatNumber(n: number) {
4
+
return numeral(n).format()
5
+
}
6
+
7
+
export function formatUptime(totalSeconds: number): string {
8
+
if (totalSeconds < 0) {
9
+
return "Invalid input: seconds cannot be negative";
10
+
}
11
+
if (totalSeconds === 0) {
12
+
return "0s";
13
+
}
14
+
15
+
let parts: string[] = [];
16
+
let displayUnits: [string, number][];
17
+
18
+
const SECONDS_IN_MINUTE = 60;
19
+
const SECONDS_IN_HOUR = 3600; // 60 minutes * 60 seconds/minute
20
+
const SECONDS_IN_DAY = 24 * SECONDS_IN_HOUR;
21
+
22
+
if (totalSeconds > SECONDS_IN_DAY) { // If uptime is bigger than 1 day
23
+
displayUnits = [
24
+
['d', SECONDS_IN_DAY],
25
+
['h', SECONDS_IN_HOUR],
26
+
];
27
+
} else if (totalSeconds > SECONDS_IN_MINUTE) { // If uptime is bigger than 60 seconds but not bigger than 60 minutes
28
+
displayUnits = [
29
+
['d', SECONDS_IN_DAY],
30
+
['h', SECONDS_IN_HOUR],
31
+
['m', SECONDS_IN_MINUTE],
32
+
];
33
+
} else { // If uptime is 60 seconds or less
34
+
displayUnits = [
35
+
['d', SECONDS_IN_DAY],
36
+
['h', SECONDS_IN_HOUR],
37
+
['m', SECONDS_IN_MINUTE],
38
+
['s', 1],
39
+
];
40
+
}
41
+
42
+
let remainingSeconds = totalSeconds;
43
+
44
+
for (const [unitChar, unitSeconds] of displayUnits) {
45
+
if (remainingSeconds >= unitSeconds) {
46
+
const value = Math.floor(remainingSeconds / unitSeconds);
47
+
parts.push(`${value}${unitChar}`);
48
+
remainingSeconds %= unitSeconds;
49
+
}
50
+
}
51
+
52
+
return parts.join("");
53
+
}