refactor: use original dashboard UI primitives
This commit is contained in:
@@ -1,16 +1,11 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDataProvider, useList } from "../../shared/hooks/dataHooks.js";
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
ConfirmDialog,
|
||||
Field,
|
||||
Input,
|
||||
Modal,
|
||||
PageHeader,
|
||||
PageState,
|
||||
Table,
|
||||
} from "../../shared/ui/ui.jsx";
|
||||
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}$/;
|
||||
@@ -22,26 +17,25 @@ function TokenCell({ token, name }) {
|
||||
<code className="anywhere font-mono text-[13px]">
|
||||
{visible ? token : "••••••••••••"}
|
||||
</code>
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
aria-label={visible ? `隐藏 ${name} 的令牌` : `显示 ${name} 的令牌`}
|
||||
onClick={() => setVisible((current) => !current)}
|
||||
className="rounded p-1 text-muted hover:text-primary"
|
||||
>
|
||||
<i
|
||||
className={visible ? "ri-eye-off-line" : "ri-eye-line"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
<i className={visible ? "ri-eye-off-line" : "ri-eye-line"} aria-hidden="true" />
|
||||
</Button>
|
||||
{visible ? (
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
aria-label={`复制 ${token}`}
|
||||
onClick={() => navigator.clipboard?.writeText(token)}
|
||||
className="rounded p-1 text-muted hover:text-primary"
|
||||
>
|
||||
<i className="ri-file-copy-line" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
@@ -87,30 +81,10 @@ function GatewayFormModal({ open, onClose, onSubmit, busy, error, initial }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
title={editing ? "编辑网关" : "注册网关"}
|
||||
labelledBy={`gateway-${mode}-title`}
|
||||
footer={
|
||||
<>
|
||||
<Button onClick={onClose} disabled={busy}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
form={`gateway-${mode}-form`}
|
||||
busy={busy}
|
||||
busyText={editing ? "保存中…" : "注册中…"}
|
||||
disabled={!valid}
|
||||
>
|
||||
{editing ? "保存" : "注册网关"}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<form id={`gateway-${mode}-form`} onSubmit={submit} noValidate>
|
||||
<Dialog open={open} onOpenChange={(nextOpen) => { if (!nextOpen) onClose() }}>
|
||||
<DialogContent>
|
||||
<DialogHeader><DialogTitle>{editing ? "编辑网关" : "注册网关"}</DialogTitle></DialogHeader>
|
||||
<form id={`gateway-${mode}-form`} onSubmit={submit} noValidate>
|
||||
{error ? (
|
||||
<Alert variant="destructive" className="mb-4">
|
||||
{error.message}
|
||||
@@ -135,7 +109,7 @@ function GatewayFormModal({ open, onClose, onSubmit, busy, error, initial }) {
|
||||
value={form.name}
|
||||
onChange={(event) => update("name", event.target.value)}
|
||||
placeholder="如 gw-main"
|
||||
invalid={nameInvalid}
|
||||
aria-invalid={nameInvalid || undefined}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
@@ -151,7 +125,7 @@ function GatewayFormModal({ open, onClose, onSubmit, busy, error, initial }) {
|
||||
value={form.endpoint}
|
||||
onChange={(event) => update("endpoint", event.target.value)}
|
||||
placeholder="http://127.0.0.1:8081"
|
||||
invalid={endpointInvalid}
|
||||
aria-invalid={endpointInvalid || undefined}
|
||||
/>
|
||||
</Field>
|
||||
<Field
|
||||
@@ -172,12 +146,19 @@ function GatewayFormModal({ open, onClose, onSubmit, busy, error, initial }) {
|
||||
value={form.token}
|
||||
onChange={(event) => update("token", event.target.value)}
|
||||
placeholder={editing ? "留空保持现有令牌" : "留空由平台生成"}
|
||||
invalid={tokenInvalid}
|
||||
aria-invalid={tokenInvalid || undefined}
|
||||
/>
|
||||
</Field>
|
||||
</div>
|
||||
</form>
|
||||
</Modal>
|
||||
<DialogFooter>
|
||||
<Button type="button" variant="outline" onClick={onClose} disabled={busy}>取消</Button>
|
||||
<Button variant="default" type="submit" form={`gateway-${mode}-form`} disabled={!valid || busy}>
|
||||
{busy ? (editing ? "保存中…" : "注册中…") : editing ? "保存" : "注册网关"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -255,27 +236,25 @@ export function GatewayList() {
|
||||
title="网关管理"
|
||||
description="注册宿主机 native browser gateway;令牌须与 gateway 进程的 GATEWAY_TOKEN 一致"
|
||||
>
|
||||
<Button
|
||||
variant="primary"
|
||||
icon="ri-add-line"
|
||||
onClick={() => setCreateOpen(true)}
|
||||
>
|
||||
<Button variant="default" onClick={() => setCreateOpen(true)}>
|
||||
<i className="ri-add-line" aria-hidden="true" />
|
||||
注册网关
|
||||
</Button>
|
||||
</PageHeader>
|
||||
{created ? (
|
||||
<Alert variant="success" className="mb-4">
|
||||
<Alert variant="default" className="mb-4">
|
||||
网关 {created.name} 已注册。
|
||||
<span className="ml-1 inline-flex items-center gap-1">
|
||||
令牌 <code className="font-mono">{created.token}</code>
|
||||
<button
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon-sm"
|
||||
aria-label={`复制 ${created.token}`}
|
||||
onClick={() => navigator.clipboard?.writeText(created.token)}
|
||||
className="rounded p-1 text-muted hover:text-primary"
|
||||
>
|
||||
<i className="ri-file-copy-line" aria-hidden="true" />
|
||||
</button>
|
||||
</Button>
|
||||
</span>
|
||||
<Button size="sm" onClick={() => setCreated(null)}>
|
||||
知道了
|
||||
@@ -293,65 +272,35 @@ export function GatewayList() {
|
||||
empty={gateways.length === 0}
|
||||
emptyText="暂无网关;注册后环境即可调度到该网关。"
|
||||
>
|
||||
<Table
|
||||
columns={[
|
||||
{
|
||||
header: "名称",
|
||||
width: "20%",
|
||||
render: (gateway) => (
|
||||
<span className="font-semibold">{gateway.name}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "Endpoint",
|
||||
width: "34%",
|
||||
render: (gateway) => (
|
||||
<code className="anywhere font-mono text-[13px]">
|
||||
{gateway.endpoint}
|
||||
</code>
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "令牌",
|
||||
width: "30%",
|
||||
render: (gateway) => (
|
||||
<TokenCell token={gateway.token} name={gateway.name} />
|
||||
),
|
||||
},
|
||||
{
|
||||
header: "操作",
|
||||
width: "16%",
|
||||
align: "right",
|
||||
render: (gateway) => (
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`编辑 ${gateway.name}`}
|
||||
disabled={busy === gateway.name || busy === "edit"}
|
||||
onClick={() => {
|
||||
setEditing(gateway);
|
||||
setEditError(null);
|
||||
}}
|
||||
className="rounded p-1.5 text-muted hover:bg-[#f5f7fa] hover:text-primary disabled:opacity-50"
|
||||
>
|
||||
<i className="ri-edit-line" aria-hidden="true" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={`删除 ${gateway.name}`}
|
||||
disabled={busy === gateway.name || busy === "edit"}
|
||||
onClick={() => setDeleting(gateway)}
|
||||
className="rounded p-1.5 text-danger hover:bg-[#fdf1f0] disabled:opacity-50"
|
||||
>
|
||||
<i className="ri-delete-bin-line" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
]}
|
||||
rows={gateways}
|
||||
rowKey={(gateway) => gateway.name}
|
||||
/>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>名称</TableHead>
|
||||
<TableHead>Endpoint</TableHead>
|
||||
<TableHead>令牌</TableHead>
|
||||
<TableHead>操作</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{gateways.map((gateway) => (
|
||||
<TableRow key={gateway.name}>
|
||||
<TableCell><span className="font-semibold">{gateway.name}</span></TableCell>
|
||||
<TableCell><code className="anywhere font-mono text-[13px]">{gateway.endpoint}</code></TableCell>
|
||||
<TableCell><TokenCell token={gateway.token} name={gateway.name} /></TableCell>
|
||||
<TableCell>
|
||||
<div className="flex items-center gap-1">
|
||||
<Button variant="ghost" size="icon-sm" aria-label={`编辑 ${gateway.name}`} disabled={busy === gateway.name || busy === "edit"} onClick={() => { setEditing(gateway); setEditError(null); }}>
|
||||
<i className="ri-edit-line" aria-hidden="true" />
|
||||
</Button>
|
||||
<Button variant="destructive" size="icon-sm" aria-label={`删除 ${gateway.name}`} disabled={busy === gateway.name || busy === "edit"} onClick={() => setDeleting(gateway)}>
|
||||
<i className="ri-delete-bin-line" aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</PageState>
|
||||
<GatewayFormModal
|
||||
open={createOpen}
|
||||
|
||||
Reference in New Issue
Block a user