frontend: hide radio-bot pool controls from non-admins (server-26#213 item 4)
GET /tokens and PUT /tokens/{id}/prefer became platform-admin only in #216
(server-26#204 item 6). Three frontend surfaces still offered them to
operators:
- systems page "Preferred Bot Token" panel: now rendered for admins only.
No non-admin listing endpoint was added: the write behind the picker is
admin-only too, so a list would only feed a control that 403s on save.
The panel also no longer turns a fetch error into "No tokens in pool."
- /tokens page: admin-only (operators are sent to /network).
- /network hub: the Bot Tokens card is shown to admins only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
dc1df72c86
commit
e574bd924a
@@ -1220,13 +1220,16 @@ function PreferredTokenPanel({ systemId, initialTokenId }: { systemId: string; i
|
||||
const [tokens, setTokens] = useState<TokenOption[] | null>(null);
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
async function load() {
|
||||
if (tokens !== null) return;
|
||||
try {
|
||||
const data = await c2api.getTokens();
|
||||
setTokens(data as TokenOption[]);
|
||||
} catch {
|
||||
} catch (err) {
|
||||
// An error used to render as "No tokens in pool." — a false empty state.
|
||||
setError(err instanceof Error ? err.message : "Could not load radio bots.");
|
||||
setTokens([]);
|
||||
}
|
||||
}
|
||||
@@ -1241,6 +1244,8 @@ function PreferredTokenPanel({ systemId, initialTokenId }: { systemId: string; i
|
||||
try {
|
||||
await c2api.setPreferredToken(tokenId, systemId);
|
||||
setPreferredId(tokenId);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Could not save the preference.");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -1252,6 +1257,8 @@ function PreferredTokenPanel({ systemId, initialTokenId }: { systemId: string; i
|
||||
try {
|
||||
await c2api.setPreferredToken(preferredId, "_none");
|
||||
setPreferredId(null);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Could not clear the preference.");
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
@@ -1276,6 +1283,8 @@ function PreferredTokenPanel({ systemId, initialTokenId }: { systemId: string; i
|
||||
<div className="mt-3 space-y-2 font-mono text-xs">
|
||||
{tokens === null ? (
|
||||
<p className="text-gray-600 italic">Loading tokens…</p>
|
||||
) : error ? (
|
||||
<p className="text-red-400">{error}</p>
|
||||
) : tokens.length === 0 ? (
|
||||
<p className="text-gray-600 italic">No tokens in pool.</p>
|
||||
) : (
|
||||
@@ -2016,7 +2025,10 @@ export default function SystemsPage() {
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
<PreferredTokenPanel systemId={s.system_id} initialTokenId={s.preferred_token_id} />
|
||||
{/* GET /tokens and PUT /tokens/{id}/prefer are platform-admin only
|
||||
(server-26#204 item 6), so for anyone else this panel could
|
||||
neither list the pool nor save a choice (server-26#213 item 4). */}
|
||||
{isAdmin && <PreferredTokenPanel systemId={s.system_id} initialTokenId={s.preferred_token_id} />}
|
||||
<AiFlagsPanel systemId={s.system_id} initial={(s as unknown as { ai_flags?: SystemAiFlags }).ai_flags ?? {}} />
|
||||
<AreaContextPanel systemId={s.system_id} />
|
||||
<TalkgroupPendingPanel systemId={s.system_id} />
|
||||
|
||||
Reference in New Issue
Block a user