Something went wrong. Try again.
An easy to set up and operate PDS admin panel.
Something went wrong. Try again.
3.3 kB · 114 lines
TSX
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115import { useCallback, useEffect, useState } from "react";import { api } from "./api.js";
interface Operator { did: string; handle: string; avatar?: string; addedAt: number; enrolledAt: number | null; passkeys: number;}
export function OperatorsPanel() { const [operators, setOperators] = useState<Operator[]>([]); const [handle, setHandle] = useState(""); const [busy, setBusy] = useState(false); const [error, setError] = useState<string | null>(null); const [confirmDid, setConfirmDid] = useState<string | null>(null);
const refresh = useCallback(() => { api .operators() .then((r) => setOperators(r.operators)) .catch((e) => setError(e.message)); }, []);
useEffect(refresh, [refresh]);
const add = async () => { setBusy(true); setError(null); try { await api.operatorAdd(handle.trim()); setHandle(""); refresh(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); } };
const remove = async (did: string) => { setBusy(true); setError(null); setConfirmDid(null); try { await api.operatorRemove(did); refresh(); } catch (e) { setError((e as Error).message); } finally { setBusy(false); } };
return ( <div className="panel"> <h2>Admins</h2> {error && <div className="error-text">{error}</div>} {operators.length === 0 && ( <p className="mono-dim empty-state"> no admins yet. add one by handle and have them sign in using the new admin button to create a passkey. </p> )} {operators.map((o) => ( <div key={o.did} className="passkey-row"> <span className="handle-cell"> {o.avatar ? ( <img className="avatar" src={o.avatar} alt="" loading="lazy" /> ) : ( <span className="avatar" aria-hidden="true" /> )} {o.handle} {o.enrolledAt == null && <span className="mono-dim">invited</span>} </span> <span className="mono-dim"> {o.enrolledAt != null ? `enrolled ${new Date(o.enrolledAt).toLocaleDateString()}` : `added ${new Date(o.addedAt).toLocaleDateString()}`} </span> {confirmDid === o.did ? ( <span className="invite-actions"> <button className="danger" disabled={busy} onClick={() => remove(o.did)}> confirm remove </button> <button disabled={busy} onClick={() => setConfirmDid(null)}> cancel </button> </span> ) : ( <button disabled={busy} onClick={() => setConfirmDid(o.did)}> remove </button> )} </div> ))} <div className="passkey-add"> <input placeholder="handle (e.g. alice.bsky.social)" value={handle} onChange={(e) => setHandle(e.target.value)} /> <button disabled={busy || !handle.trim()} onClick={add}> add admin </button> </div> <p className="mono-dim panel-note"> removing and re-adding an admin resets their enrollment (deletes their passkeys). </p> </div> );}