diff --git a/web/src/app/(dashboard)/network-lexicons/page.tsx b/web/src/app/(dashboard)/network-lexicons/page.tsx new file mode 100644 index 0000000..638c6fe --- /dev/null +++ b/web/src/app/(dashboard)/network-lexicons/page.tsx @@ -0,0 +1,199 @@ +"use client" + +import { useCallback, useEffect, useState } from "react" + +import { useAuth } from "@/lib/auth-context" +import { + addNetworkLexicon, + deleteNetworkLexicon, + getNetworkLexicons, + type NetworkLexiconSummary, +} from "@/lib/api" +import { SiteHeader } from "@/components/site-header" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table" + +export default function NetworkLexiconsPage() { + const { token } = useAuth() + const [items, setItems] = useState([]) + const [error, setError] = useState(null) + + const load = useCallback(() => { + if (!token) return + getNetworkLexicons(token).then(setItems).catch((e) => setError(e.message)) + }, [token]) + + useEffect(() => { + load() + }, [load]) + + async function handleDelete(nsid: string) { + if (!token) return + try { + await deleteNetworkLexicon(token, nsid) + load() + } catch (e: unknown) { + setError(e instanceof Error ? e.message : String(e)) + } + } + + return ( + <> + +
+ {error &&

{error}

} + +
+

Tracked Network Lexicons

+ +
+ +
+ + + + NSID + Authority DID + Target Collection + Last Fetched + Actions + + + + {items.length === 0 && ( + + + No network lexicons tracked yet. + + + )} + {items.map((item) => ( + + + {item.nsid} + + + {item.authority_did} + + + {item.target_collection ?? "--"} + + + {item.last_fetched_at + ? new Date(item.last_fetched_at).toLocaleString() + : "Never"} + + + + + + ))} + +
+
+
+ + ) +} + +function AddDialog({ + token, + onSuccess, +}: { + token: string + onSuccess: () => void +}) { + const [nsid, setNsid] = useState("") + const [targetCollection, setTargetCollection] = useState("") + const [error, setError] = useState(null) + const [open, setOpen] = useState(false) + + async function handleAdd() { + setError(null) + try { + await addNetworkLexicon(token, { + nsid, + target_collection: targetCollection || undefined, + }) + setNsid("") + setTargetCollection("") + setOpen(false) + onSuccess() + } catch (e: unknown) { + setError(e instanceof Error ? e.message : String(e)) + } + } + + return ( + + + + + + + Add Network Lexicon + + Track a lexicon from the ATProto network by its NSID. + + +
+ {error &&

{error}

} +
+ + setNsid(e.target.value)} + placeholder="com.example.record" + /> +
+
+ + setTargetCollection(e.target.value)} + placeholder="com.example.record" + /> +
+
+ + + + + + +
+
+ ) +}