1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/** @jsxImportSource npm:hono/jsx */
import { api } from "https://esm.town/v/pomdtr/api";
import { extractValInfo } from "https://esm.town/v/pomdtr/extractValInfo";
import { Island } from "https://esm.town/v/pomdtr/hono_island";
import { Test } from "https://esm.town/v/pomdtr/test";
import {
createHistory,
type HistoryEntry,
readHistory,
writeHistory,
} from "https://esm.town/v/pomdtr/test_explorer_history";
import TestExplorer, { type Test as TestType } from "https://esm.town/v/pomdtr/test_explorer_ui";
import { Hono } from "npm:hono@4.0.8";
import stripAnsi from "npm:strip-ansi@7.1.0";
const router = new Hono();
const { author } = extractValInfo(import.meta.url);
router.get("/", async (c) => {
try {
const tests = await loadTests();
return c.html(
<html>
<head>
<link rel="icon" href="https://fav.farm/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.colors.min.css"
/>
<style
dangerouslySetInnerHTML={{
__html: `ul li { list-style: none; }`,
}}
>
</style>
<script src="https://esm.town/v/pomdtr/hydrate_hono_islands" type="module" defer></script>
</head>
<body>
<Island src="pomdtr/test_explorer_ui">
<TestExplorer tests={tests} />
</Island>
</body>
</html>,
);
} catch (e) {
return new Response(`${e.message} ${e.stack}`, { status: 500 });
}
});
router.post("/api/refresh", async () => {
const tests = await loadTests();
return Response.json(tests);
});
async function loadTests(): Promise<TestType[]> {
const query = `https://esm.town/v/${author}/test_explorer`;
const { data: vals } = await api(`/v1/search/vals?query=${query}`, { authenticated: true });
const tests = {};
for (const val of vals) {
const mod = await import(`https://esm.town/v/${val.author.username}/${val.name}`);
for (const [name, value] of Object.entries(mod)) {
if (value instanceof Test) {
tests[`${val.author.username}/${val.name}/${name}`] = { val, name };
}
}
}
const history = await loadHistory();
for (const entry of history) {
const key = `${entry.val_slug}/${entry.test_name}`;
const test = tests[key];
if (!test) {
continue;
}
test.status = entry.status;
test.last_run_at = entry.last_run_at;
}
return Object.values(tests);
}
async function loadHistory(): Promise<HistoryEntry[]> {
try {
const entries = await readHistory();
return entries;
} catch (err) {
if (err.message.includes("no such table")) {
await createHistory();
return [];
}
throw err;
Val Town is a social website to write and deploy JavaScript.
Build APIs and schedule functions from your browser.
Comments
Nobody has commented on this val yet: be the first!
v0
June 26, 2024