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