mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 14:56:25 +00:00
7399315185
Rebuild the bundled web UI as a Next.js (React + TypeScript) static export implementing the Claude Activity Dashboard design: a left-nav "Control Center" hub over Runs, Repositories, Agents, Approvals, Git Servers, Activity, and Shared, styled with the Leeworks design-system tokens (flat, dark, border-led). The dashboard is a pure client of the existing API (same contract as curl): the browser prompts for the token once, stores it in localStorage, attaches it to every call, and renders all API values as React text so agent-authored strings stay inert. Control actions enqueue a command and poll it to a terminal state, matching the worker model. The build output is committed to src/handler/api/static/ so the wheel ships it and FastAPI serves it same-origin. app.py now mounts the export at "/" after the API routers (a non-shadowing fallback: unmatched paths 404, no SPA rewrite). UI-serving tests updated for the export; frontend source lives in frontend/. Claude-Session: https://claude.ai/code/session_01ATgVWRjFzG8nHEnwgZpJWD Co-authored-by: Claude <noreply@anthropic.com>
49 lines
1.5 KiB
TypeScript
49 lines
1.5 KiB
TypeScript
/* Token gate: shown until an API token is supplied. Holds no data. Management actions
|
|
* (spawn, approve, edit repos/servers) need the admin token; read-only views need the
|
|
* plain auth token. The token lives only in localStorage on this device. */
|
|
"use client";
|
|
|
|
import { useState } from "react";
|
|
|
|
export function TokenGate({ error, onSubmit }: { error?: string; onSubmit: (token: string) => void }) {
|
|
const [value, setValue] = useState("");
|
|
|
|
const submit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
const t = value.trim();
|
|
if (t) onSubmit(t);
|
|
};
|
|
|
|
return (
|
|
<div className="gate">
|
|
<form className="gate-card" onSubmit={submit}>
|
|
<div className="gate-brand">
|
|
<span className="logo" style={{ width: 26, height: 26, borderRadius: 7 }} />
|
|
Claude Monitor
|
|
</div>
|
|
<p className="muted" style={{ fontSize: "var(--text-sm)", margin: 0 }}>
|
|
Paste your API token to continue. Management actions require the admin token; read-only
|
|
views work with the plain auth token.
|
|
</p>
|
|
<input
|
|
className="input"
|
|
type="password"
|
|
autoComplete="current-password"
|
|
placeholder="API token"
|
|
value={value}
|
|
onChange={(e) => setValue(e.target.value)}
|
|
autoFocus
|
|
/>
|
|
{error && (
|
|
<p className="callout callout-danger" style={{ margin: 0 }}>
|
|
{error}
|
|
</p>
|
|
)}
|
|
<button className="btn btn-primary" type="submit">
|
|
Continue
|
|
</button>
|
|
</form>
|
|
</div>
|
|
);
|
|
}
|