90742837fc
- 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
77 lines
2.7 KiB
TypeScript
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>
|
|
);
|
|
}
|