Skip to content

Commit cf56502

Browse files
committed
Redesign sandbox pages as dark ops console
1 parent 0ccc0ab commit cf56502

11 files changed

Lines changed: 1359 additions & 420 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
export type OutcomeKind = "idle" | "success" | "error" | "warning" | "pending";
2+
3+
export interface OutcomeState {
4+
kind: OutcomeKind;
5+
message: string;
6+
at?: string;
7+
}
8+
9+
export function renderJson(target: HTMLElement, value: unknown): void {
10+
target.textContent = JSON.stringify(value, null, 2);
11+
}
12+
13+
export function formatTimestamp(timestamp: string | undefined): string {
14+
if (!timestamp) {
15+
return "Waiting for activity";
16+
}
17+
18+
const date = new Date(timestamp);
19+
20+
if (Number.isNaN(date.getTime())) {
21+
return "Waiting for activity";
22+
}
23+
24+
const deltaMs = Date.now() - date.getTime();
25+
26+
if (Math.abs(deltaMs) < 10_000) {
27+
return "Updated just now";
28+
}
29+
30+
return `Updated ${date.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", second: "2-digit" })}`;
31+
}
32+
33+
export function extractErrorMessage(body: unknown, fallback: string): string {
34+
if (typeof body === "string" && body.trim()) {
35+
return body;
36+
}
37+
38+
if (typeof body !== "object" || body === null) {
39+
return fallback;
40+
}
41+
42+
if ("error" in body) {
43+
const error = body.error;
44+
45+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
46+
return error.message;
47+
}
48+
}
49+
50+
if ("detail" in body && typeof body.detail === "string") {
51+
return body.detail;
52+
}
53+
54+
return fallback;
55+
}
56+
57+
export function setButtonBusy(
58+
button: HTMLButtonElement,
59+
isBusy: boolean,
60+
busyLabel: string,
61+
): void {
62+
if (!button.dataset.defaultLabel) {
63+
button.dataset.defaultLabel = button.textContent?.trim() ?? "";
64+
}
65+
66+
button.dataset.busy = String(isBusy);
67+
button.disabled = isBusy;
68+
button.textContent = isBusy ? busyLabel : button.dataset.defaultLabel;
69+
}

0 commit comments

Comments
 (0)