/** * @file UsersSettings.tsx * @description Settings → Users, server mode only and only for an admin or * analyst (docs/SERVER-MODE.md): every account with its role, state, * workspaces, sessions and the tokens/$ it used in the last 7 and 30 days * (`GET /api/users`), and the audit log of staff reads of members' sessions * (`GET /api/users/audit`). Read-only — accounts are managed with * `agenthub users …` on the host. * @author Nguyễn Ngọc Trí Vĩ */ import { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { api, type ServerUserUsage, type AuditEntry } from "../../lib/api"; import { fmt, fmtCost, formatDateTime } from "../../lib/format"; import { SettingsSection } from "./SettingsRow"; export function UsersSettings() { const { t } = useTranslation("settings"); const [users, setUsers] = useState(null); const [audit, setAudit] = useState(null); const [error, setError] = useState(null); useEffect(() => { api.users .list() .then((r) => setUsers(r.users)) .catch((e: Error) => setError(e.message)); api.users .audit() .then((r) => setAudit(r.entries)) .catch(() => setAudit([])); }, []); return ( <> {error && (

{error}

)} {users && (
{users.map((u) => ( ))}
{t("users.name")} {t("users.role")} {t("users.workspaces")} {t("users.sessions")} {t("users.last7d")} {t("users.last30d")}
{u.username} {u.disabled && ( ({t("users.disabled")}) )} {u.role} {u.workspaces} {u.sessions} {fmtCost(u.last7d.cost)} {fmtCost(u.last30d.cost)}
)}

{t("users.manageHint")}

{audit?.length === 0 && (

{t("users.auditEmpty")}

)} {audit && audit.length > 0 && (
    {audit.map((a) => (
  • {formatDateTime(a.at)} {a.reader} → {a.owner} {a.path}
  • ))}
)}
); }