atproto explorer

refetch record after editing

+30 -41
+2 -2
src/components/create.tsx
··· 11 11 import { Modal } from "./modal.jsx"; 12 12 import { Button } from "./button.jsx"; 13 13 14 - export const RecordEditor = (props: { create: boolean; record?: any }) => { 14 + export const RecordEditor = (props: { create: boolean; record?: any; refetch?: any }) => { 15 15 const navigate = useNavigate(); 16 16 const params = useParams(); 17 17 const [openDialog, setOpenDialog] = createSignal(false); ··· 119 119 } 120 120 } 121 121 setOpenDialog(false); 122 - window.location.reload(); 122 + props.refetch(); 123 123 } catch (err: any) { 124 124 setNotice(err.message); 125 125 }
+5 -8
src/views/blob.tsx
··· 8 8 const [cursor, setCursor] = createSignal<string>(); 9 9 let rpc: Client; 10 10 11 - const listBlobs = (did: string, cursor: string | undefined) => 12 - rpc.get("com.atproto.sync.listBlobs", { 11 + const fetchBlobs = async () => { 12 + if (!rpc) rpc = new Client({ handler: new CredentialManager({ service: props.pds }) }); 13 + const res = await rpc.get("com.atproto.sync.listBlobs", { 13 14 params: { 14 - did: did as `did:${string}:${string}`, 15 + did: props.repo as `did:${string}:${string}`, 15 16 limit: LIMIT, 16 - cursor: cursor, 17 + cursor: cursor(), 17 18 }, 18 19 }); 19 - 20 - const fetchBlobs = async () => { 21 - if (!rpc) rpc = new Client({ handler: new CredentialManager({ service: props.pds }) }); 22 - const res = await listBlobs(props.repo, cursor()); 23 20 if (!res.ok) throw new Error(res.data.error); 24 21 if (!res.data.cids) return []; 25 22 setCursor(res.data.cids.length < LIMIT ? undefined : res.data.cursor);
+6 -9
src/views/collection.tsx
··· 75 75 let pds: string; 76 76 let rpc: Client; 77 77 78 - const listRecords = (did: string, collection: string, cursor: string | undefined) => 79 - rpc.get("com.atproto.repo.listRecords", { 78 + const fetchRecords = async () => { 79 + if (!pds) pds = await resolvePDS(did); 80 + if (!rpc) rpc = new Client({ handler: new CredentialManager({ service: pds }) }); 81 + const res = await rpc.get("com.atproto.repo.listRecords", { 80 82 params: { 81 83 repo: did as ActorIdentifier, 82 - collection: collection as `${string}.${string}.${string}`, 84 + collection: params.collection as `${string}.${string}.${string}`, 83 85 limit: LIMIT, 84 - cursor: cursor, 86 + cursor: cursor(), 85 87 reverse: reverse(), 86 88 }, 87 89 }); 88 - 89 - const fetchRecords = async () => { 90 - if (!pds) pds = await resolvePDS(did); 91 - if (!rpc) rpc = new Client({ handler: new CredentialManager({ service: pds }) }); 92 - const res = await listRecords(did, params.collection, cursor()); 93 90 if (!res.ok) throw new Error(res.data.error); 94 91 setCursor(res.data.records.length < LIMIT ? undefined : res.data.cursor); 95 92 const tmpRecords: AtprotoRecord[] = [];
+1 -3
src/views/pds.tsx
··· 28 28 setVersion((res.data as any).version); 29 29 }; 30 30 31 - const fetchRepos = async (): Promise< 32 - InferXRPCBodyOutput<ComAtprotoSyncListRepos.mainSchema["output"]> 33 - > => { 31 + const fetchRepos = async () => { 34 32 await getVersion(); 35 33 const describeRes = await rpc.get("com.atproto.server.describeServer"); 36 34 if (!describeRes.ok) console.error(describeRes.data.error);
+16 -19
src/views/record.tsx
··· 1 1 import { CredentialManager, Client } from "@atcute/client"; 2 2 3 3 import { useNavigate, useParams } from "@solidjs/router"; 4 - import { createSignal, ErrorBoundary, onMount, Show, Suspense } from "solid-js"; 4 + import { createResource, createSignal, ErrorBoundary, Show, Suspense } from "solid-js"; 5 5 6 6 import { Backlinks } from "../components/backlinks.jsx"; 7 7 import { JSONValue } from "../components/json.jsx"; ··· 11 11 import { didDocCache, resolvePDS } from "../utils/api.js"; 12 12 import { AtUri, uriTemplates } from "../utils/templates.js"; 13 13 import { verifyRecord } from "../utils/verify.js"; 14 - import { ActorIdentifier, InferXRPCBodyOutput, is } from "@atcute/lexicons"; 14 + import { ActorIdentifier, is } from "@atcute/lexicons"; 15 15 import { lexiconDoc } from "@atcute/lexicon-doc"; 16 - import { ComAtprotoRepoGetRecord } from "@atcute/atproto"; 17 16 import { lexicons } from "../utils/types/lexicons.js"; 18 17 import { RecordEditor } from "../components/create.jsx"; 19 18 import { addToClipboard } from "../utils/copy.js"; ··· 24 23 export const RecordView = () => { 25 24 const navigate = useNavigate(); 26 25 const params = useParams(); 27 - const [record, setRecord] = 28 - createSignal<InferXRPCBodyOutput<ComAtprotoRepoGetRecord.mainSchema["output"]>>(); 29 26 const [openDelete, setOpenDelete] = createSignal(false); 30 27 const [notice, setNotice] = createSignal(""); 31 28 const [showBacklinks, setShowBacklinks] = createSignal(false); ··· 35 32 const did = params.repo; 36 33 let rpc: Client; 37 34 38 - onMount(async () => { 35 + const fetchRecord = async () => { 39 36 setCID(undefined); 40 37 setValidRecord(undefined); 41 38 setValidSchema(undefined); ··· 53 50 setNotice(res.data.error); 54 51 throw new Error(res.data.error); 55 52 } 56 - setRecord(res.data); 57 53 setCID(res.data.cid); 58 54 setExternalLink(checkUri(res.data.uri, res.data.value)); 59 55 ··· 87 83 console.error(err); 88 84 setValidRecord(false); 89 85 } 90 - }); 86 + 87 + return res.data; 88 + }; 89 + 90 + const [record, { refetch }] = createResource(fetchRecord); 91 91 92 92 const deleteRecord = async () => { 93 93 rpc = new Client({ handler: agent()! }); ··· 112 112 }; 113 113 114 114 return ( 115 - <div class="flex w-full flex-col items-center"> 116 - <Show when={record() === undefined && validRecord() !== false}> 117 - <div class="iconify lucide--loader-circle mt-3 animate-spin text-xl" /> 118 - </Show> 119 - <Show when={validRecord() === false}> 120 - <div class="mt-3 break-words text-red-500 dark:text-red-400">{notice()}</div> 121 - </Show> 122 - <Show when={record()}> 115 + <Show when={record()} keyed> 116 + <div class="flex w-full flex-col items-center"> 123 117 <div class="dark:shadow-dark-900/80 dark:bg-dark-300 my-3 flex w-[22rem] justify-between rounded-lg bg-white px-2 py-1.5 shadow-sm sm:w-[24rem]"> 124 118 <div class="flex gap-3 text-sm"> 125 119 <button ··· 147 141 </div> 148 142 <div class="flex gap-1"> 149 143 <Show when={agent() && agent()?.sub === record()?.uri.split("/")[2]}> 150 - <RecordEditor create={false} record={record()?.value} /> 144 + <RecordEditor create={false} record={record()?.value} refetch={refetch} /> 151 145 <Tooltip text="Delete"> 152 146 <button 153 147 class="flex items-center rounded-sm p-1 hover:bg-neutral-100 active:bg-neutral-100 dark:hover:bg-neutral-600 dark:active:bg-neutral-600" ··· 204 198 </div> 205 199 </div> 206 200 <Show when={!showBacklinks()}> 201 + <Show when={validRecord() === false}> 202 + <div class="mb-2 break-words text-red-500 dark:text-red-400">{notice()}</div> 203 + </Show> 207 204 <div class="w-[22rem] font-mono text-xs wrap-anywhere whitespace-pre-wrap sm:w-full sm:text-sm"> 208 205 <JSONValue data={record()?.value as any} repo={record()!.uri.split("/")[2]} /> 209 206 </div> ··· 219 216 </Suspense> 220 217 </ErrorBoundary> 221 218 </Show> 222 - </Show> 223 - </div> 219 + </div> 220 + </Show> 224 221 ); 225 222 };