https://domlink.deployments.hotsocket.fyi/

tangled issue list (search next?)

+21
src/domlink.ts
··· 65 65 this.wraps.classList.add("LRow"); 66 66 } 67 67 } 68 + export class Table extends Node { 69 + constructor() { 70 + let table = document.createElement("table"); 71 + table.classList.add("LTable"); 72 + super(table); 73 + } 74 + } 75 + export class TableRow extends Node { 76 + constructor() { 77 + let tr = document.createElement("tr"); 78 + tr.classList.add("LTableRow"); 79 + super(tr); 80 + } 81 + } 82 + export class TableCell extends Node { 83 + constructor() { 84 + let td = document.createElement("td"); 85 + td.classList.add("LTableCell"); 86 + super(td); 87 + } 88 + } 68 89 export class Text extends Node { 69 90 private _text: string = ""; 70 91 get text() {
+148
src/issuesearch.ts
··· 1 + import { Body, Button, Column, Input, Label, Row, Table, TableCell, TableRow } from "./domlink.js"; 2 + 3 + type issueRecord = { 4 + body: string; 5 + createdAt: string; 6 + issueId: number; 7 + owner: string; 8 + repo: string; 9 + title: string; 10 + }; 11 + type constellationRecordItem = { 12 + did: string; 13 + collection: string; 14 + rkey: string; 15 + }; 16 + type constellationResponse = { 17 + total: number; 18 + linking_records: [constellationRecordItem]; 19 + cursor: string; 20 + }; 21 + type slingshotResponse<T> = { 22 + cid: string; 23 + uri: string; 24 + value: T; 25 + }; 26 + type miniDoc = { 27 + did: string; 28 + handle: string; 29 + pds: string; 30 + signing_key: string; 31 + }; 32 + type repoRecord = { 33 + knot: string; 34 + name: string; 35 + owner: string; 36 + createdAt: string; 37 + }; 38 + type recordListingItem<T> = { 39 + uri: string; 40 + cid: string; 41 + value: T; 42 + }; 43 + type recordListing<T> = { 44 + cursor: string; 45 + records: [recordListingItem<T>]; 46 + }; 47 + 48 + async function xcall(host: string, method: string, params: Record<string, string | number> | null = null): Promise<unknown> { 49 + let url = `${host}/xrpc/${method}`; 50 + if (params) { 51 + let usp = new URLSearchParams(); 52 + for (let key in params) { 53 + usp.append(key, params[key].toString()); 54 + } 55 + url += "?" + usp.toString(); 56 + } 57 + return await (await fetch(url)).json(); 58 + } 59 + 60 + const SLINGSHOT = "https://slingshot.microcosm.blue"; 61 + async function listIssues(repo: string) { 62 + let repoUrl = new URL(repo); 63 + let repoUrlSplat = repoUrl.pathname.split("/"); 64 + let repoOwnerHandle = repoUrlSplat[1].substring(1); 65 + let repoName = repoUrlSplat[2]; 66 + let repoOwnerDoc = await xcall(SLINGSHOT, "com.bad-example.identity.resolveMiniDoc", {identifier: repoOwnerHandle}) as miniDoc; 67 + let ownedRepos = await xcall(repoOwnerDoc.pds, "com.atproto.repo.listRecords", { repo: repoOwnerDoc.did, collection: "sh.tangled.repo" }) as recordListing<repoRecord>; 68 + let repoRecord = ownedRepos.records.find(x=>x.value.name == repoName)!; 69 + let encodedRepoUri = encodeURIComponent(repoRecord.uri); 70 + let view_issues_list = new Table().add( 71 + new TableRow().with( 72 + new TableCell().add("Handle"), 73 + new TableCell().add("Issue#"), 74 + new TableCell().add("Title") 75 + ) 76 + ); 77 + Body.add(view_issues_list); 78 + let irsp = await (await fetch(`https://constellation.microcosm.blue/links?target=${encodedRepoUri}&collection=sh.tangled.repo.issue&path=.repo`)).json() as constellationResponse; 79 + let allIssueRefs: constellationRecordItem[] = irsp.linking_records; 80 + let nextCursor = irsp.cursor; 81 + while (allIssueRefs.length < irsp.total && nextCursor != null) { 82 + let rsp = await (await fetch(`https://constellation.microcosm.blue/links?target=${encodedRepoUri}&collection=sh.tangled.repo.issue&path=.repo&cursor=${nextCursor}`)).json() as constellationResponse; 83 + nextCursor = rsp.cursor; 84 + allIssueRefs = allIssueRefs.concat(rsp.linking_records); 85 + if (nextCursor == null) break; 86 + } 87 + let sortedIssues = (await Promise.all(allIssueRefs.map(async (issueRef) => { 88 + let rsp = await xcall(SLINGSHOT, "com.atproto.repo.getRecord", { 89 + repo: issueRef.did, 90 + collection: issueRef.collection, 91 + rkey: issueRef.rkey 92 + }) as slingshotResponse<issueRecord>; 93 + let issue = rsp.value; 94 + let doc; 95 + try { 96 + doc = await xcall(SLINGSHOT, "com.bad-example.identity.resolveMiniDoc", { identifier: issue.owner }) as miniDoc; 97 + } catch (error) { 98 + return null; 99 + } 100 + let handle = doc.handle; 101 + return { 102 + handle: handle, 103 + issue: issue 104 + }; 105 + }))).sort((a,b)=>{ 106 + let x = 0; 107 + if (a && b) { 108 + x = b.issue.issueId-a.issue.issueId 109 + } 110 + return x; 111 + }); 112 + sortedIssues.forEach(that =>{ 113 + if (that) { 114 + let view_issue_row = new TableRow(); 115 + view_issue_row.with( 116 + new TableCell().add(that.handle), 117 + new TableCell().add(that.issue.issueId.toString()), 118 + new TableCell().add(that.issue.title) 119 + ); 120 + view_issues_list.add(view_issue_row); 121 + } 122 + }); 123 + return view_issues_list; 124 + } 125 + 126 + 127 + let repoUrl = new Input(); 128 + let last: any; 129 + let statusText = new Label("waiting"); 130 + let runButton = new Button("GO!",async ()=>{ 131 + (runButton.wraps as HTMLButtonElement).disabled = true; 132 + if (last) { 133 + Body.remove(last); 134 + } 135 + try { 136 + last = await listIssues(repoUrl.value); 137 + } catch (e) { 138 + last = new Label("Failed"); 139 + Body.add(last); 140 + } 141 + console.log(last); 142 + (runButton.wraps as HTMLButtonElement).disabled = false; 143 + }); 144 + Body.add(new Row().with( 145 + "List issues for repo: ", 146 + repoUrl, 147 + runButton 148 + ));
+12
static/issuesearch.css
··· 1 + tr:nth-child(1) { 2 + font-weight: bold; 3 + } 4 + tr:nth-child(1)>* { 5 + text-align: center !important; 6 + } 7 + td { 8 + padding-right: 2ch; 9 + } 10 + td:nth-child(1) { 11 + text-align: right; 12 + }
+15
static/issuesearch.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>issuesearch</title> 7 + <link rel="stylesheet" href="styles/domlink.css"> 8 + <link rel="stylesheet" href="pds.css"> 9 + <link rel="stylesheet" href="issuesearch.css"> 10 + </head> 11 + <body> 12 + <noscript>enable js or fukc off</noscript> 13 + <script src="issuesearch.js" type="module"></script> 14 + </body> 15 + </html>