Files
wasmeld/crates/wasmeld-console/web/src/pages/services/index.tsx
T
Maofeng 90742837fc feat(console-web): replace TanStack UI with Solid host pages
- move the management frontend under the wasmeld-console crate\n- use a persistent Host shell with disposable iframe page documents\n- version Host/Page postMessage state and command contracts\n- migrate runtime, service, WIT, invocation, and settings workflows\n- add Tailwind CSS v4, responsive layouts, and Host-owned dialogs\n- emit a dependency-free PWA worker with API cache exclusions\n- remove the superseded root TanStack Start application
2026-07-30 09:21:55 +08:00

77 lines
2.7 KiB
TypeScript

import { CloudUpload, Filter, RefreshCw } from "lucide-solid";
import { createMemo, createSignal, Show } from "solid-js";
import { PageHeading } from "../../components/ui/page-heading";
import { ServiceTable } from "../../components/ui/service-table";
import { servicesFrom } from "../../lib/view-state";
import type { ServiceStatus } from "../../lib/model";
import type { PageProps } from "../types";
export default function ServicesPage(props: PageProps) {
const [status, setStatus] = createSignal<"all" | ServiceStatus>("all");
const services = createMemo(() => servicesFrom(props.state()));
const filtered = createMemo(() => {
const query = props.state()?.query.trim().toLowerCase() ?? "";
return services().filter(
(service) =>
(status() === "all" || service.status === status()) &&
(!query ||
service.id.toLowerCase().includes(query) ||
service.revision.toLowerCase().includes(query) ||
service.artifact.toLowerCase().includes(query)),
);
});
return (
<main class="page">
<PageHeading
eyebrow="COMPONENTS"
title="服务版本"
description="管理不可变 Component Revision、Actor 状态和对外 Deployment。"
actions={
<>
<label class="relative">
<Filter
class="pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted"
size={14}
/>
<select
class="select w-36 pl-9"
value={status()}
onChange={(event) => setStatus(event.currentTarget.value as "all" | ServiceStatus)}
>
<option value="all">全部状态</option>
<option value="running">运行中</option>
<option value="stopped">已停止</option>
<option value="faulted">故障</option>
</select>
</label>
<button
class="btn btn-primary"
onClick={() => props.command({ type: "open-register" })}
>
<CloudUpload size={16} />
注册组件
</button>
</>
}
/>
<section class="panel">
<div class="panel-header">
<div>
<h2>已注册版本</h2>
<p>{filtered().length} 个匹配项</p>
</div>
<button class="icon-btn" title="刷新" onClick={() => props.command({ type: "refresh" })}>
<RefreshCw size={16} />
</button>
</div>
<Show when={props.state()}>
{(state) => (
<ServiceTable services={filtered()} state={state()} command={props.command} />
)}
</Show>
</section>
</main>
);
}