+3
bun.lock
+3
bun.lock
···
6
6
"dependencies": {
7
7
"@tailwindcss/vite": "^4.1.16",
8
8
"date-fns": "^4.1.0",
9
+
"lodash": "^4.17.21",
9
10
"numeral": "^2.0.6",
10
11
"tailwindcss": "^4.1.16",
11
12
},
···
330
331
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.30.2", "", { "os": "win32", "cpu": "x64" }, "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw=="],
331
332
332
333
"locate-character": ["locate-character@3.0.0", "", {}, "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="],
334
+
335
+
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
333
336
334
337
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
335
338
+1
package.json
+1
package.json
+10
-7
src/App.svelte
+10
-7
src/App.svelte
···
2
2
import { onMount } from 'svelte';
3
3
import { formatDistanceToNow, addSeconds, formatDate, formatISO9075 } from 'date-fns';
4
4
import { Progress, Switch } from '@skeletonlabs/skeleton-svelte';
5
+
import orderBy from "lodash/orderBy";
5
6
import instancesData from './instances.json';
6
7
import numeral from 'numeral';
7
8
···
26
27
let canRefresh = $state(true)
27
28
let lastUpdated = $state(new Date())
28
29
let autoRefreshEnabled = $state(true)
29
-
let instances = $state(instancesData)
30
-
let instancesSorted = $derived(instances.sort((a, b) => a.status?.responseTime > b.status?.responseTime ? 1 : -1))
30
+
let instances = $state(instancesData.sort(() => Math.random() - 0.5))
31
+
32
+
const instanceOrderBy = [['status.head', 'status.latency'], ['desc', 'asc']]
31
33
32
34
function formatNumber(n: number) {
33
35
return numeral(n).format()
···
56
58
}
57
59
}
58
60
if (statusResp) {
59
-
statusResp.responseTime = performance.now() - start;
61
+
statusResp.latency = performance.now() - start;
60
62
}
61
63
return statusResp
62
64
}
···
71
73
await Promise.all(instances.map(async (instance) => {
72
74
const status = await getStatus(instance)
73
75
74
-
if (status?.bundles?.last_bundle > lastKnownBundle.number) {
76
+
instance.status = status
77
+
instance.status.head = status?.bundles?.last_bundle > lastKnownBundle.number
78
+
if (instance.status.head) {
75
79
lastKnownBundle.number = status?.bundles?.last_bundle
76
80
lastKnownBundle.hash = status?.bundles?.head_hash
77
81
lastKnownBundle.time = status?.bundles?.end_time
···
82
86
lastKnownBundle.etaNext = addSeconds(new Date(), status?.mempool?.eta_next_bundle_seconds)
83
87
}
84
88
}
85
-
instance.status = status
86
89
lastUpdated = new Date()
87
90
}))
88
91
isUpdating = false
···
173
176
</tr>
174
177
</thead>
175
178
<tbody>
176
-
{#each instances as instance}
179
+
{#each orderBy(instances, ...instanceOrderBy) as instance}
177
180
<tr>
178
181
<td><a href={instance.url} target="_blank" class="font-semibold">{instance.url.replace("https://", "")}</a></td>
179
182
<td>{#if instance.status?.bundles?.last_bundle === lastKnownBundle.number}✅{:else if instance.status}🔄{:else}⌛{/if}</td>
···
182
185
<td><span class="font-mono text-xs">{#if instance.status?.bundles?.head_hash}{instance.status?.bundles?.head_hash.slice(0, 7)}{/if}</span></td>
183
186
<td><span class="font-mono text-xs">{#if instance.status?.bundles?.root_hash}{instance.status?.bundles?.root_hash.slice(0, 7)}{/if}</span></td>
184
187
<td>{#if instance.status?.server?.version}{instance.status?.server?.version}{/if}</td>
185
-
<td class="opacity-50">{#if instance.status?.responseTime}{Math.round(instance.status?.responseTime)}ms{/if}</td>
188
+
<td class="opacity-50">{#if instance.status?.latency}{Math.round(instance.status?.latency)}ms{/if}</td>
186
189
</tr>
187
190
{/each}
188
191
</tbody>