This commit is contained in:
2026-08-29 10:29:48 +05:00
parent eaa9a7bef2
commit 069b51a84c
16 changed files with 949 additions and 471 deletions
+72
View File
@@ -0,0 +1,72 @@
import { useState } from "preact/hooks";
import { createClient } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
import { X, Play } from "lucide-preact";
import type { Item } from "../gen/homelab/v1/homelab_pb";
import { HomelabService } from "../gen/homelab/v1/homelab_pb";
const client = createClient(HomelabService, createConnectTransport({ baseUrl: "" }));
/** Карточка response-скрипта: форма по количеству аргументов; результат — в модалке. */
export function ScriptCard({ s }: { s: Item }) {
const [args, setArgs] = useState<string[]>(Array(s.args).fill(""));
const [output, setOutput] = useState<string | null>(null);
const [error, setError] = useState("");
const [running, setRunning] = useState(false);
const run = async () => {
setRunning(true);
try {
setOutput((await client.runScript({ name: s.name, args })).output);
setError("");
} catch (e) {
setError(String(e));
} finally {
setRunning(false);
}
};
return (
<div class="card bg-base-200 shadow">
<div class="card-body p-4">
<h2 class="card-title text-sm font-medium text-base-content/60">
<Play size={14} /> {s.name}
</h2>
{error && <div role="alert" class="alert alert-error text-sm">{error}</div>}
<div class="flex flex-wrap gap-2 items-center">
{s.argTypes.map((t, i) => (
<input
class="input input-bordered w-full sm:w-32"
type={t === "number" ? "number" : "text"}
placeholder={t}
value={args[i]}
onInput={(e) =>
setArgs((a) => {
const next = [...a];
next[i] = (e.target as HTMLInputElement).value;
return next;
})
}
/>
))}
<button class="btn btn-primary btn-sm" disabled={running} onClick={run}>
<Play size={14} /> Run
</button>
</div>
</div>
{output != null && (
<div class="modal modal-open">
<div class="modal-box">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" onClick={() => setOutput(null)}>
<X size={16} />
</button>
<h3 class="font-bold text-lg">{s.name}</h3>
<pre class="bg-base-300 rounded-box p-3 mt-3 text-sm whitespace-pre-wrap">{output}</pre>
</div>
<div class="modal-backdrop" onClick={() => setOutput(null)} />
</div>
)}
</div>
);
}