code bridge
@@ -637,6 +634,22 @@ function leaseRow(
`;
}
+function portalHeader(options: PortalHeaderOptions): string {
+ const variant = options.variant || "top";
+ const headerClass = variant === "bar" ? "vnc-bar" : "top";
+ const metaClass = variant === "bar" ? "vnc-meta portal-header-meta" : "portal-header-meta";
+ const actions = options.actions?.trim()
+ ? `
${options.actions.trim()}
`
+ : "";
+ return ``;
+}
+
function leaseOwnership(lease: LeaseRecord, owner: string, org: string): "mine" | "system" {
return lease.owner === owner && lease.org === org ? "mine" : "system";
}
@@ -1052,7 +1065,9 @@ function html(title: string, body: string, status = 200, nonce = ""): Response {
td { font-size:13px; }
td small { display:block; color:var(--muted); margin-top:1px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.top { position:sticky; top:0; z-index:20; display:flex; justify-content:space-between; gap:12px; align-items:center; min-height:38px; margin:0; padding:4px 0; background:linear-gradient(180deg, var(--bg) 72%, color-mix(in srgb, var(--bg) 0%, transparent)); backdrop-filter:blur(10px); }
- .top p { font-size:12px; }
+ .portal-header-meta { min-width:0; }
+ .portal-header-meta h1 { white-space:nowrap; }
+ .portal-header-meta p { font-size:12px; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.top p,.muted,.empty { color:var(--muted); }
.panel { border:1px solid var(--line); border-radius:8px; background:var(--panel); overflow:hidden; }
.section-head { display:flex; justify-content:space-between; align-items:center; min-height:34px; padding:7px 10px; border-bottom:1px solid var(--line); }
@@ -1153,7 +1168,7 @@ function html(title: string, body: string, status = 200, nonce = ""): Response {
.vnc-meta p { display:inline-flex; align-items:center; gap:8px; color:var(--muted); font-size:12px; min-width:0; overflow:hidden; }
.vnc-meta .vnc-id { font-family:var(--mono); font-size:11px; opacity:0.85; }
.vnc-meta .vnc-dot { width:3px; height:3px; border-radius:50%; background:#3a4046; flex-shrink:0; }
- .vnc-actions { display:flex; align-items:center; gap:6px; flex-shrink:0; }
+ .portal-actions { display:flex; align-items:center; gap:6px; flex-shrink:0; }
.status-pill { display:inline-flex; align-items:center; gap:8px; height:32px; padding:0 12px 0 11px; border-radius:8px; background:var(--panel-2); border:1px solid var(--line); font-size:12px; color:var(--muted); white-space:nowrap; transition:color 0.2s, border-color 0.2s; }
.status-pill::before { content:""; width:8px; height:8px; border-radius:50%; background:currentColor; box-shadow:0 0 0 3px color-mix(in srgb, currentColor 18%, transparent); flex-shrink:0; }
.status-pill[data-tone="ok"] { color:var(--ok); border-color:color-mix(in srgb, var(--ok) 35%, var(--line)); }
@@ -1197,8 +1212,8 @@ function html(title: string, body: string, status = 200, nonce = ""): Response {
.vnc-bar { flex-wrap:wrap; gap:8px; min-height:0; padding:6px 10px; margin:0 -12px; }
.vnc-meta { flex-wrap:wrap; gap:4px 10px; }
.vnc-meta p .vnc-id { display:none; }
- .vnc-actions { gap:6px; }
- .vnc-actions .button { min-height:30px; padding:0 10px; }
+ .portal-actions { gap:6px; }
+ .portal-actions .button { min-height:30px; padding:0 10px; }
.vnc-bridge-label { display:none; }
}
diff --git a/worker/test/fleet.test.ts b/worker/test/fleet.test.ts
index 128360f..81553e0 100644
--- a/worker/test/fleet.test.ts
+++ b/worker/test/fleet.test.ts
@@ -648,6 +648,7 @@ describe("fleet lease identity and idle", () => {
const body = await response.text();
expect(body).toContain('class="portal-shell"');
expect(body).toContain("
๐ฆ crabbox
");
+ expect(body).toContain('class="portal-actions"');
expect(body).toContain("table-scroll");
expect(body).toContain(".lease-table th:nth-child(1)");
expect(body).toContain(
@@ -913,6 +914,8 @@ describe("fleet lease identity and idle", () => {
expect(body).toContain("data-copy-command");
expect(body).toContain('querySelector("code")');
expect(body).toContain('class="portal-shell lease-shell"');
+ expect(body).toContain("
๐ฆ crabbox
");
+ expect(body).toContain("blue-lobster ยท hetzner linux lease");
expect(body).toContain('data-search-placeholder="search runs"');
expect(body).toContain(
'data-filter-buttons="succeeded:succeeded,failed:failed,running:running,all:all"',
@@ -950,6 +953,7 @@ describe("fleet lease identity and idle", () => {
expect(runPage.headers.get("content-type")).toBe("text/html; charset=utf-8");
const runBody = await runPage.text();
expect(runBody).toContain('class="portal-shell run-shell"');
+ expect(runBody).toContain("
๐ฆ crabbox
");
expect(runBody).toContain("run_000000000001");
expect(runBody).toContain("go test ./...");
expect(runBody).toContain("data-copy-command");
@@ -1024,6 +1028,8 @@ describe("fleet lease identity and idle", () => {
const pageBody = await page.text();
expect(pageBody).toContain("crabbox code --id blue-lobster --open");
expect(pageBody).toContain('class="vnc-page code-wait-page"');
+ expect(pageBody).toContain("
๐ฆ crabbox
");
+ expect(pageBody).toContain("code blue-lobster");
expect(pageBody).toContain('id="code-status"');
expect(pageBody).toContain('id="code-copy"');
expect(pageBody).toContain("/portal/leases/cbx_000000000001/code/health");
@@ -1134,6 +1140,8 @@ describe("fleet lease identity and idle", () => {
"crabbox webvnc --provider hetzner --target linux --id blue-lobster --open",
);
expect(pageBody).toContain("/portal/assets/novnc/rfb.js");
+ expect(pageBody).toContain("
๐ฆ crabbox
");
+ expect(pageBody).toContain("WebVNC blue-lobster");
expect(pageBody).toContain("function scheduleRetry");
expect(pageBody).toContain("/portal/leases/cbx_000000000001/vnc/status");
expect(pageBody).toContain("vnc-copy");