Knot server viewer. knotview.srv.rbrt.fr
tangled knot
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove unimplemented list repo

ref: https://tangled.org/tangled.org/core/pulls/903

+46 -133
-10
api.js
··· 1 1 const API = (() => { 2 2 const ENDPOINTS = { 3 3 owner: "sh.tangled.owner", 4 - list: "sh.tangled.repo.list", 5 4 tree: "sh.tangled.repo.tree", 6 5 blob: "sh.tangled.repo.blob", 7 6 branches: "sh.tangled.repo.branches", ··· 46 45 return response.json(); 47 46 } 48 47 49 - async function listRepos() { 50 - const url = `${baseUrl}/xrpc/${ENDPOINTS.list}`; 51 - const response = await fetch(url); 52 - if (!response.ok) throw new Error(`HTTP ${response.status}`); 53 - return response.json(); 54 - } 55 - 56 48 async function getDefaultBranch(repo) { 57 49 const url = `${baseUrl}/xrpc/${ENDPOINTS.defaultBranch}?repo=${encodeURIComponent(repo)}`; 58 50 const response = await fetch(url); ··· 96 88 97 89 const didDocument = await response.json(); 98 90 99 - // Extract handle from alsoKnownAs field 100 91 if (didDocument.alsoKnownAs && didDocument.alsoKnownAs.length > 0) { 101 92 const handle = didDocument.alsoKnownAs[0].replace(/^at:\/\//, ""); 102 93 return handle; ··· 113 104 setBaseUrl, 114 105 getBaseUrl, 115 106 getOwner, 116 - listRepos, 117 107 getDefaultBranch, 118 108 getBranches, 119 109 getTree,
+3 -43
app.js
··· 15 15 currentPath: "", 16 16 resolvedHandle: null, 17 17 }, 18 - users: [], 19 18 branches: [], 20 - view: "empty", // empty, repoList, tree, file 19 + view: "empty", // empty, tree, file 21 20 loading: false, 22 21 loadingMessage: "", 23 22 error: null, ··· 108 107 this.isConnected = true; 109 108 110 109 this.updateURL(); 111 - await this.loadUsersAndRepos(); 112 110 } catch (error) { 113 111 this.showStatus(`Connection failed: ${error.message}`, "error"); 114 - } 115 - }, 116 - 117 - async loadUsersAndRepos() { 118 - try { 119 - this.showLoading("Loading repositories..."); 120 - 121 - const data = await API.listRepos(); 122 - 123 - // Resolve handles for all users 124 - if (data.users && data.users.length > 0) { 125 - for (const user of data.users) { 126 - const handle = await API.resolveDID(user.did); 127 - if (handle) { 128 - user.handle = handle; 129 - } 130 - } 131 - } 132 - 133 - this.users = data.users || []; 134 - this.view = "repoList"; 135 - this.loading = false; 136 - this.showStatus( 137 - `Found ${this.users.length} users with repositories`, 138 - "success", 139 - ); 140 - } catch (error) { 141 - this.users = []; 142 - this.view = "repoList"; 143 - this.loading = false; 144 - this.showStatus( 145 - "Server doesn't support repository listing. Please enter repository path manually.", 146 - "error", 147 - ); 148 112 } 149 113 }, 150 114 ··· 440 404 }, 441 405 442 406 // Actions 443 - showUsersList() { 407 + showConnectView() { 444 408 this.state.currentRepo = null; 445 409 this.state.currentBranch = "main"; 446 410 this.state.currentPath = ""; 447 411 this.state.resolvedHandle = null; 448 412 this.branches = []; 449 - this.view = "repoList"; 413 + this.view = "empty"; 450 414 this.updateURL(); 451 415 }, 452 416 ··· 558 522 await this.loadBranches(); 559 523 560 524 if (path) { 561 - // Check if path is a file or directory 562 525 try { 563 526 await this.loadFile(path); 564 527 } catch (error) { ··· 568 531 await this.loadTree(); 569 532 } 570 533 571 - this.updateURL(true); 572 - } else { 573 - await this.loadUsersAndRepos(); 574 534 this.updateURL(true); 575 535 } 576 536
+43 -77
index.html
··· 58 58 <h2> 59 59 Repository 60 60 <button 61 - @click="showUsersList" 61 + @click="showConnectView" 62 62 class="secondary" 63 63 style="padding: 6px 12px; font-size: 12px" 64 64 > ··· 195 195 <li> 196 196 Click "Connect" to connect to the server 197 197 </li> 198 - <li>Select a repository from the list</li> 198 + <li>Enter a repository path (did:plc:xxx/repo-name)</li> 199 199 <li> 200 - Browse files, switch branches, and explore 201 - even if Tangled AppView is down! 200 + Browse files, switch branches, and explore! 202 201 </li> 203 202 </ol> 204 203 </div> 205 204 </div> 206 205 207 - <!-- Users/Repos List --> 206 + <!-- Manual Repo Entry --> 208 207 <div 209 - x-show="!loading && !error && view === 'repoList'" 210 - style="padding: 20px" 208 + x-show="!loading && !error && isConnected && !state.currentRepo" 209 + class="empty-state" 211 210 > 212 - <template x-for="user in users" :key="user.did"> 213 - <div class="user-item"> 214 - <div 215 - class="user-header" 216 - x-text="user.handle || user.did" 217 - ></div> 218 - <template 219 - x-for="repo in user.repos" 220 - :key="repo.fullPath" 221 - > 222 - <div 223 - class="repo-item" 224 - @click="selectRepository(repo)" 225 - > 226 - <strong x-text="repo.name"></strong> 227 - <small x-text="repo.fullPath"></small> 228 - </div> 229 - </template> 230 - </div> 231 - </template> 232 - 233 - <!-- Manual Entry Fallback --> 211 + <svg 212 + xmlns="http://www.w3.org/2000/svg" 213 + fill="none" 214 + viewBox="0 0 24 24" 215 + stroke="currentColor" 216 + > 217 + <path 218 + stroke-linecap="round" 219 + stroke-linejoin="round" 220 + stroke-width="2" 221 + d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" 222 + /> 223 + </svg> 224 + <h3>Open a Repository</h3> 225 + <p>Enter the repository path to browse its contents.</p> 234 226 <div 235 - x-show="users.length === 0 && !loading" 236 - class="empty-state" 227 + style=" 228 + margin-top: 20px; 229 + max-width: 400px; 230 + margin-left: auto; 231 + margin-right: auto; 232 + " 237 233 > 238 - <svg 239 - xmlns="http://www.w3.org/2000/svg" 240 - fill="none" 241 - viewBox="0 0 24 24" 242 - stroke="currentColor" 243 - > 244 - <path 245 - stroke-linecap="round" 246 - stroke-linejoin="round" 247 - stroke-width="2" 248 - d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" 249 - /> 250 - </svg> 251 - <h3>Repository List Not Available</h3> 252 - <p> 253 - This server doesn't support automatic repository 254 - listing. 255 - </p> 256 - <p style="margin-top: 20px"> 257 - Please enter repository path manually: 258 - </p> 259 - <div 234 + <input 235 + type="text" 236 + x-model="manualRepoPath" 237 + placeholder="did:plc:xxx.../repo-name" 260 238 style=" 261 - margin-top: 20px; 262 - max-width: 400px; 263 - margin-left: auto; 264 - margin-right: auto; 239 + width: 100%; 240 + margin-bottom: 10px; 241 + padding: 10px; 242 + border: 1px solid #cbd5e1; 243 + border-radius: 6px; 265 244 " 245 + @keyup.enter="loadManualRepo" 246 + /> 247 + <button 248 + @click="loadManualRepo" 249 + style="width: 100%" 266 250 > 267 - <input 268 - type="text" 269 - x-model="manualRepoPath" 270 - placeholder="did:plc:xxx.../repo-name" 271 - style=" 272 - width: 100%; 273 - margin-bottom: 10px; 274 - padding: 10px; 275 - border: 1px solid #cbd5e1; 276 - border-radius: 6px; 277 - " 278 - @keyup.enter="loadManualRepo" 279 - /> 280 - <button 281 - @click="loadManualRepo" 282 - style="width: 100%" 283 - > 284 - Load Repository 285 - </button> 286 - </div> 251 + Open Repository 252 + </button> 287 253 </div> 288 254 </div> 289 255
-3
readme.md
··· 6 6 7 7 ## Note 8 8 9 - Once PR [#903](https://tangled.org/tangled.org/core/pulls/903) is merged in tangled/core, the UX of browsing a knot will be better. 10 - In the meantime, you need to know the did and the repo name of the repository you want to browse. 11 - 12 9 In case of CORS issues, configure the Knot server to allow CORS requests from the domain hosting KnotView. Or simply use a browser extension to disable CORS check on the domain. 13 10 14 11 ## License