import { useEffect, useState } from "react";
import { useDataProvider, useList } from "../../shared/hooks/dataHooks.js";
import { Alert } from "../../components/ui/alert";
import { Button } from "../../components/ui/button";
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from "../../components/ui/dialog";
import { Input } from "../../components/ui/input";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../../components/ui/table";
import { ConfirmDialog, Field, PageHeader, PageState } from "../../shared/ui/ui.jsx";
import { useTitle } from "../../shared/hooks/hooks.js";
const namePattern = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
const tokenPattern = /^[A-Za-z0-9][A-Za-z0-9._-]{15,127}$/;
function TokenCell({ token, name }) {
const [visible, setVisible] = useState(false);
return (
{visible ? token : "••••••••••••"}
{visible ? (
) : null}
);
}
function GatewayFormModal({ open, onClose, onSubmit, busy, error, initial }) {
const editing = initial !== null;
const [form, setForm] = useState({ name: "", endpoint: "", token: "" });
useEffect(() => {
if (!open) return;
setForm(
editing
? { name: initial.name, endpoint: initial.endpoint, token: "" }
: { name: "", endpoint: "", token: "" },
);
}, [editing, initial, open]);
const update = (key, value) =>
setForm((current) => ({ ...current, [key]: value }));
const token = form.token.trim();
const valid =
namePattern.test(form.name) &&
/^https?:\/\/\S+$/.test(form.endpoint) &&
(token === "" || tokenPattern.test(token));
const nameInvalid = form.name !== "" && !namePattern.test(form.name);
const endpointInvalid =
form.endpoint !== "" && !/^https?:\/\/\S+$/.test(form.endpoint);
const tokenInvalid = token !== "" && !tokenPattern.test(token);
const mode = editing ? "edit" : "create";
async function submit(event) {
event.preventDefault();
if (!valid) return;
if (
await onSubmit({
name: form.name,
endpoint: form.endpoint,
token,
})
) {
setForm({ name: "", endpoint: "", token: "" });
onClose();
}
}
return (
);
}
export function GatewayList() {
const dataProvider = useDataProvider()("default");
const { result, query } = useList({ resource: "gateways" });
const error = query.error;
const isPending = query.isPending;
const gateways = result.data ?? [];
const [createOpen, setCreateOpen] = useState(false);
const [busy, setBusy] = useState("");
const [createError, setCreateError] = useState(null);
const [created, setCreated] = useState(null);
const [editing, setEditing] = useState(null);
const [editError, setEditError] = useState(null);
const [deleting, setDeleting] = useState(null);
useTitle("CreatorHub · 网关管理");
async function createGateway(data) {
setBusy("create");
setCreateError(null);
try {
const { data: record } = await dataProvider.create({
resource: "gateways",
variables: data,
});
setCreated(record);
await query.refetch();
return true;
} catch (reason) {
setCreateError(reason);
return false;
} finally {
setBusy("");
}
}
async function updateGateway(data) {
const currentName = editing.name;
setBusy("edit");
setEditError(null);
try {
await dataProvider.update({
resource: "gateways",
id: currentName,
variables: data,
});
await query.refetch();
setEditing(null);
return true;
} catch (reason) {
setEditError(reason);
return false;
} finally {
setBusy("");
}
}
async function removeGateway() {
const gateway = deleting;
setBusy(gateway.name);
try {
await dataProvider.deleteOne({ resource: "gateways", id: gateway.name });
await query.refetch();
setDeleting(null);
} finally {
setBusy("");
}
}
return (
{created ? (
网关 {created.name} 已注册。
令牌 {created.token}
) : null}
{error ? (
{error.message}
) : null}
名称
Endpoint
令牌
操作
{gateways.map((gateway) => (
{gateway.name}
{gateway.endpoint}
))}
{
setCreateOpen(false);
setCreateError(null);
}}
onSubmit={createGateway}
busy={busy === "create"}
error={createError}
/>
{
setEditing(null);
setEditError(null);
}}
onSubmit={updateGateway}
busy={busy === "edit"}
error={editError}
/>
setDeleting(null)}
onConfirm={removeGateway}
title="删除网关"
confirmLabel="确认删除"
busy={busy === deleting?.name}
body={`删除网关 ${deleting?.name}?仍被环境引用时删除会被拒绝。`}
/>
);
}