diff --git a/console/.oxfmtrc.json b/console/.oxfmtrc.json deleted file mode 100644 index fce110d..0000000 --- a/console/.oxfmtrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "$schema": "./node_modules/oxfmt/configuration_schema.json", - "ignorePatterns": ["src/routeTree.gen.ts"] -} diff --git a/console/.oxlintrc.json b/console/.oxlintrc.json deleted file mode 100644 index 5f58139..0000000 --- a/console/.oxlintrc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": ["typescript", "unicorn", "oxc", "react", "jsx-a11y", "node"], - "categories": { - "correctness": "error" - }, - "rules": {}, - "ignorePatterns": ["src/routeTree.gen.ts"], - "env": { - "builtin": true, - "browser": true, - "node": true - } -} diff --git a/console/README.md b/console/README.md deleted file mode 100644 index ffa25b5..0000000 --- a/console/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Wasmeld Console - -WebAssembly Runtime 的管理控制台,使用 TanStack Start、TanStack Router、 -React 和 srvx 构建,通过 Node.js 运行。页面只调用 `wasmeld-console` HTTP API, -不直接访问数据库或 Wasmeld Runtime。 - -运行概览可以启动、停止和重启整个 Runtime;服务版本与运行实例页面负责管理单个 -Wasm Actor。停止 Runtime 不会断开管理 API。 - -## Development - -```bash -npm install -npm run dev -``` - -默认访问 `http://localhost:3000`。 - -管理 API 默认使用 `http://127.0.0.1:8080`。可以在控制台的“运行设置”中修改, -或在构建时设置 `VITE_WASMELD_API_URL`。 - -## Validation - -```bash -npm run format:check -npm run lint -npm test -``` - -生产构建完成后可以运行: - -```bash -npm start -``` - -`npm test` 会生成 Node.js 生产构建,并验证 srvx 服务端渲染和静态资源。 diff --git a/console/package.json b/console/package.json deleted file mode 100644 index 2482b22..0000000 --- a/console/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "wasmeld-console", - "version": "0.1.0", - "private": true, - "type": "module", - "scripts": { - "dev": "vite dev", - "build": "vite build && tsc --noEmit", - "start": "srvx serve --prod --entry dist/server/server.js --static ../client", - "preview": "vite preview", - "test": "npm run build && node --test tests/rendered-html.test.mjs", - "lint": "oxlint . --deny-warnings", - "format": "oxfmt .", - "format:check": "oxfmt --check ." - }, - "dependencies": { - "@tanstack/react-router": "^1.170.18", - "@tanstack/react-start": "^1.168.32", - "lucide-react": "^1.27.0", - "react": "19.2.6", - "react-dom": "19.2.6", - "srvx": "^0.12.4" - }, - "devDependencies": { - "@types/node": "22.19.19", - "@types/react": "19.2.14", - "@types/react-dom": "19.2.3", - "@vitejs/plugin-react": "6.0.2", - "oxfmt": "^0.60.0", - "oxlint": "^1.75.0", - "typescript": "5.9.3", - "vite": "^8.1.5" - }, - "engines": { - "node": ">=22.13.0" - } -} diff --git a/console/src/components/dialogs.tsx b/console/src/components/dialogs.tsx deleted file mode 100644 index 65c79c6..0000000 --- a/console/src/components/dialogs.tsx +++ /dev/null @@ -1,379 +0,0 @@ -import { - ArrowRight, - Clock3, - CloudUpload, - FileCode2, - Package, - Play, - RadioTower, - RefreshCw, - ShieldCheck, - SquareTerminal, - X, -} from "lucide-react"; -import { FormEvent, ReactNode, useState } from "react"; -import { InvokeResult, RegisterComponentInput } from "../api"; -import { - FormattedInvocationOutput, - Service, - formatInvocationOutput, - invocationInputSize, - parseInvocationInput, -} from "../console-model"; - -function DialogFrame({ - title, - description, - icon, - onClose, - closeDisabled = false, - children, -}: { - title: string; - description: string; - icon: ReactNode; - onClose: () => void; - closeDisabled?: boolean; - children: ReactNode; -}) { - return ( -
- { - if (closeDisabled) event.preventDefault(); - else onClose(); - }} - onKeyDown={(event) => { - if (event.key === "Escape" && !closeDisabled) onClose(); - }} - > -
-
- {icon} -
-

{title}

-

{description}

-
-
- -
- {children} -
-
- ); -} - -export function ActivateDeploymentDialog({ - service, - currentRevision, - submitting, - onClose, - onConfirm, -}: { - service: Service; - currentRevision: string | null; - submitting: boolean; - onClose: () => void; - onConfirm: () => void; -}) { - return ( - } - onClose={onClose} - closeDisabled={submitting} - > -
-
-
- 当前版本 - {currentRevision ?? "尚未部署"} -
- -
- 目标版本 - {service.revision} -
-
-

- Wasmeld 将先确认 {service.id}@{service.revision} 的 Actor 可用,再更新对外路由。 -

-
-
- - -
-
- ); -} - -export function DeployDialog({ - onClose, - onRegister, -}: { - onClose: () => void; - onRegister: (input: RegisterComponentInput) => Promise; -}) { - const [file, setFile] = useState(null); - const [submitting, setSubmitting] = useState(false); - const [error, setError] = useState(""); - const fileName = file?.name ?? ""; - - async function submit(event: FormEvent) { - event.preventDefault(); - if (!file) return; - if (!file.name.toLowerCase().endsWith(".wasmpkg")) { - setError("请选择 .wasmpkg 组件包"); - return; - } - setSubmitting(true); - setError(""); - try { - await onRegister({ file }); - } catch (submitError) { - setError(submitError instanceof Error ? submitError.message : "组件注册失败"); - setSubmitting(false); - } - } - - return ( - } - onClose={onClose} - > -
- - - {error &&
{error}
} - -
- - -
-
-
- ); -} - -export function WitPackageDialog({ - onClose, - onPublish, -}: { - onClose: () => void; - onPublish: (file: File) => Promise; -}) { - const [file, setFile] = useState(null); - const [submitting, setSubmitting] = useState(false); - const [error, setError] = useState(""); - const fileName = file?.name ?? ""; - - async function submit(event: FormEvent) { - event.preventDefault(); - if (!file) return; - if (!file.name.toLowerCase().endsWith(".wasm")) { - setError("请选择由 wasmeld wit build 生成的 .wasm 文件"); - return; - } - if (file.size > 4 * 1024 * 1024) { - setError("WIT 包不能超过 4 MB"); - return; - } - setSubmitting(true); - setError(""); - try { - await onPublish(file); - } catch (submitError) { - setError(submitError instanceof Error ? submitError.message : "WIT 包发布失败"); - setSubmitting(false); - } - } - - return ( - } - onClose={onClose} - > -
- - - {error &&
{error}
} - -
- - -
-
-
- ); -} - -export function InvokeDialog({ - service, - onClose, - onInvoke, -}: { - service: Service; - onClose: () => void; - onInvoke: (service: Service, input: Uint8Array) => Promise; -}) { - const [input, setInput] = useState(service.id === "echo" ? "hello wasm" : ""); - const [format, setFormat] = useState<"utf8" | "hex">("utf8"); - const [output, setOutput] = useState(""); - const [outputBytes, setOutputBytes] = useState(null); - const [outputFormat, setOutputFormat] = useState(null); - const [running, setRunning] = useState(false); - const [failed, setFailed] = useState(false); - const [latency, setLatency] = useState(null); - - async function invoke() { - setRunning(true); - setOutput(""); - setOutputBytes(null); - setOutputFormat(null); - setFailed(false); - setLatency(null); - try { - const result = await onInvoke(service, parseInvocationInput(input, format)); - const formatted = formatInvocationOutput(service, result.output, format); - setOutput(formatted.text); - setOutputBytes(result.outputBytes); - setOutputFormat(formatted); - setLatency(result.latencyMs); - } catch (invokeError) { - setFailed(true); - setOutput(invokeError instanceof Error ? invokeError.message : "组件调用失败"); - } finally { - setRunning(false); - } - } - - return ( - } - onClose={onClose} - > -
-
-
- - -
- {invocationInputSize(input, format)} B -
-