feat: make the Users tab operational, drop the degraded empty state
With user management now wired through the control-plane API, the Users
tab is always functional against a live gateway. Remove the "Gestión de
users no disponible" alert and the writable gating (button disabled,
revoke hidden) that were driven by the old users_backend === "none"
case. The backend badge now reads the wiring in use ("control-plane" or
"sqlite"). Add user (handle + 64-hex sign-pub + role) and revoke (with
explicit confirmation) consume the gateway REST unchanged. Includes the
rebuilt SPA bundle embedded by the binary.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Vendored
+158
File diff suppressed because one or more lines are too long
Vendored
-163
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>unibus · admin</title>
|
||||
<script type="module" crossorigin src="/assets/index-D7Qf15Sh.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-CGRScjCy.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-ndvieWwa.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
+10
-18
@@ -1,7 +1,6 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
ActionIcon,
|
||||
Alert,
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
@@ -18,7 +17,7 @@ import {
|
||||
} from "@mantine/core";
|
||||
import { useDisclosure } from "@mantine/hooks";
|
||||
import { notifications } from "@mantine/notifications";
|
||||
import { IconPlus, IconRefresh, IconUserOff, IconInfoCircle } from "@tabler/icons-react";
|
||||
import { IconPlus, IconRefresh, IconUserOff } from "@tabler/icons-react";
|
||||
import { api, ApiError } from "../api";
|
||||
import type { UserView } from "../types";
|
||||
import { fmtTime, trunc } from "../util";
|
||||
@@ -32,7 +31,6 @@ export function UsersPage({ usersBackend }: { usersBackend: string }) {
|
||||
const [err, setErr] = useState<string | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [addOpen, addCtl] = useDisclosure(false);
|
||||
const writable = usersBackend !== "none";
|
||||
|
||||
const load = useCallback(() => {
|
||||
setLoading(true);
|
||||
@@ -62,9 +60,11 @@ export function UsersPage({ usersBackend }: { usersBackend: string }) {
|
||||
<Group gap="sm">
|
||||
<Title order={3}>Users</Title>
|
||||
{users && <Badge color="brand" variant="light">{users.length}</Badge>}
|
||||
<Badge variant="outline" color={writable ? "teal" : "gray"} style={{ textTransform: "none" }}>
|
||||
store: {usersBackend}
|
||||
</Badge>
|
||||
<Tooltip label="Vía de gestión de la allowlist del bus">
|
||||
<Badge variant="outline" color="teal" style={{ textTransform: "none" }}>
|
||||
backend: {usersBackend}
|
||||
</Badge>
|
||||
</Tooltip>
|
||||
</Group>
|
||||
<Group gap="xs">
|
||||
<Tooltip label="Refrescar">
|
||||
@@ -72,22 +72,14 @@ export function UsersPage({ usersBackend }: { usersBackend: string }) {
|
||||
<IconRefresh size={18} />
|
||||
</ActionIcon>
|
||||
</Tooltip>
|
||||
<Button leftSection={<IconPlus size={16} />} onClick={addCtl.open} disabled={!writable}>
|
||||
<Button leftSection={<IconPlus size={16} />} onClick={addCtl.open}>
|
||||
Añadir user
|
||||
</Button>
|
||||
</Group>
|
||||
</Group>
|
||||
|
||||
{!writable && (
|
||||
<Alert icon={<IconInfoCircle size={18} />} color="yellow" variant="light" title="Gestión de users no disponible">
|
||||
El plano de control no expone endpoint de users; viven solo en el store. Arranca el gateway con <code>--db</code>
|
||||
(single-node) o con acceso KV admin del cluster para listar/dar de alta/revocar. Coordinar con la vía KV que
|
||||
añade <code>quick/0011-deploy-gaps</code>.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{err && writable && <Text c="red">{err}</Text>}
|
||||
{!users && !err && writable && <Loader color="brand" />}
|
||||
{err && <Text c="red">{err}</Text>}
|
||||
{!users && !err && <Loader color="brand" />}
|
||||
|
||||
{users && (
|
||||
<Card withBorder bg="dark.7" p={0} radius="md">
|
||||
@@ -117,7 +109,7 @@ export function UsersPage({ usersBackend }: { usersBackend: string }) {
|
||||
</Table.Td>
|
||||
<Table.Td><Text size="xs" c="dimmed">{fmtTime(u.created_at)}</Text></Table.Td>
|
||||
<Table.Td>
|
||||
{writable && u.status === "active" && (
|
||||
{u.status === "active" && (
|
||||
<Tooltip label="Revocar acceso">
|
||||
<ActionIcon variant="subtle" color="red" onClick={() => revoke(u)}>
|
||||
<IconUserOff size={16} />
|
||||
|
||||
Reference in New Issue
Block a user