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 (
);
}
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}
>
);
}
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}
>
);
}
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
输出
{output && latency !== null && outputBytes !== null && outputFormat && (
{outputBytes} B · {outputFormat.format}
{outputFormat.automatic ? " · 自动" : ""}
{latency} ms
)}
{running ? "invoking..." : output || "等待调用"}
);
}