127 lines
5.4 KiB
TypeScript
127 lines
5.4 KiB
TypeScript
import { useState } from "react";
|
|
import { Pencil, Trash2 } from "lucide-react";
|
|
import Link from "@/src/components/twui/layout/Link";
|
|
import Row from "@/src/components/twui/layout/Row";
|
|
import Span from "@/src/components/twui/layout/Span";
|
|
import formatUnixTimestamp from "@/src/utils/format-unix-timestamp";
|
|
import adminCrudHandler from "@/src/functions/frontend/admin-crud-handler";
|
|
import type {
|
|
BUN_SQLITE_WGUI_CLIENTS,
|
|
BUN_SQLITE_WGUI_CLIENT_RULES,
|
|
} from "@/db/types/db";
|
|
import deriveClientAccessLabel from "@/src/functions/frontend/derive-client-access-label";
|
|
|
|
type Props = {
|
|
client: BUN_SQLITE_WGUI_CLIENTS;
|
|
rules?: BUN_SQLITE_WGUI_CLIENT_RULES[];
|
|
};
|
|
|
|
export default function ClientRow({ client, rules }: Props) {
|
|
const [deleting, setDeleting] = useState(false);
|
|
|
|
const host_id = Number(client.host_id || 0);
|
|
const access = deriveClientAccessLabel({ rules });
|
|
|
|
async function handleDelete() {
|
|
if (
|
|
!window.confirm(
|
|
`Delete client "${client?.name || `#${client?.id}`}"? The client will be removed from the host and its config file deleted.`,
|
|
)
|
|
) {
|
|
return;
|
|
}
|
|
|
|
setDeleting(true);
|
|
|
|
const res = await adminCrudHandler({
|
|
action: "delete",
|
|
table: "clients",
|
|
id: client?.id,
|
|
});
|
|
|
|
if (!res.success) {
|
|
setDeleting(false);
|
|
window.alert(res.msg || "Could not delete client");
|
|
return;
|
|
}
|
|
|
|
window.location.reload();
|
|
}
|
|
|
|
return (
|
|
<tr className="border-b border-slate-200/60 dark:border-white/5 last:border-b-0 hover:bg-foreground-light/[0.02] dark:hover:bg-foreground-dark/[0.02] transition-colors">
|
|
<td className="px-4 py-[9px]">
|
|
<Link
|
|
href={`/admin/hosts/${host_id}/clients/${client.id}`}
|
|
className="text-[13.5px] font-medium text-foreground-light dark:text-foreground-dark hover:text-secondary dark:hover:text-secondary"
|
|
>
|
|
{client.name || "—"}
|
|
</Link>
|
|
</td>
|
|
<td className="px-4 py-[9px]">
|
|
{typeof host_id == "number" ? (
|
|
<Link
|
|
href={`/admin/hosts/${host_id}`}
|
|
className="tabular text-[13px] text-foreground-light/60 dark:text-foreground-dark/60 hover:text-secondary dark:hover:text-secondary whitespace-nowrap"
|
|
>
|
|
{host_id == 0 ? "Main" : `Host #${host_id}`}
|
|
</Link>
|
|
) : (
|
|
<Span className="tabular text-[13px] text-foreground-light/40 dark:text-foreground-dark/40 whitespace-nowrap">
|
|
—
|
|
</Span>
|
|
)}
|
|
</td>
|
|
<td className="px-4 py-[9px] tabular text-[13px] text-foreground-light/60 dark:text-foreground-dark/60 whitespace-nowrap">
|
|
{client.wg_ip_address || "—"}
|
|
</td>
|
|
<td className="px-4 py-[9px] tabular text-[13px] text-foreground-light/45 dark:text-foreground-dark/45 whitespace-nowrap">
|
|
{client.allowed_ips || "—"}
|
|
</td>
|
|
<td className="px-4 py-[9px] whitespace-nowrap">
|
|
<Span
|
|
className={
|
|
access.kind == "none"
|
|
? "text-[12.5px] text-error/80"
|
|
: "text-[12.5px] text-foreground-light/60 dark:text-foreground-dark/60"
|
|
}
|
|
>
|
|
{access.text}
|
|
</Span>
|
|
</td>
|
|
<td className="px-4 py-[9px]">
|
|
<Span className="font-mono text-[12px] text-foreground-light/45 dark:text-foreground-dark/45 whitespace-nowrap">
|
|
{client.public_key
|
|
? `${client.public_key.slice(0, 16)}…`
|
|
: "—"}
|
|
</Span>
|
|
</td>
|
|
<td className="px-4 py-[9px] tabular text-[12px] text-foreground-light/40 dark:text-foreground-dark/40 text-right whitespace-nowrap">
|
|
{formatUnixTimestamp({ timestamp: client.created_at })}
|
|
</td>
|
|
<td className="px-4 py-[9px] text-right">
|
|
<Row className="gap-1.5 items-center justify-end">
|
|
<Link
|
|
href={`/admin/hosts/${host_id}/clients/${client.id}/edit`}
|
|
title={`Edit client ${client.name || `#${client.id}`}`}
|
|
aria-label={`Edit client ${client.name || `#${client.id}`}`}
|
|
className="p-1.5 text-foreground-light/40 dark:text-foreground-dark/40 hover:text-foreground-light dark:hover:text-foreground-dark focus:outline-2"
|
|
>
|
|
<Pencil size={14} />
|
|
</Link>
|
|
<button
|
|
type="button"
|
|
title={`Delete client ${client.name || `#${client.id}`}`}
|
|
aria-label={`Delete client ${client.name || `#${client.id}`}`}
|
|
disabled={deleting}
|
|
onClick={handleDelete}
|
|
className="p-1.5 text-error hover:bg-error/10 focus:outline-2 transition-colors duration-150"
|
|
>
|
|
<Trash2 size={14} />
|
|
</button>
|
|
</Row>
|
|
</td>
|
|
</tr>
|
|
);
|
|
}
|