add delete
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { describeRepo, listRecordsRaw, getRecordRaw, fetchLexicon, resolveHandle, getServiceInfo } from '../lib/api.js'
|
import { describeRepo, listRecordsRaw, getRecordRaw, fetchLexicon, resolveHandle, getServiceInfo } from '../lib/api.js'
|
||||||
|
import { deleteRecord } from '../lib/auth.js'
|
||||||
|
|
||||||
function extractRkey(uri: string): string {
|
function extractRkey(uri: string): string {
|
||||||
const parts = uri.split('/')
|
const parts = uri.split('/')
|
||||||
@@ -82,7 +83,7 @@ async function renderRecordList(did: string, handle: string, collection: string)
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
async function renderRecordDetail(did: string, handle: string, collection: string, rkey: string): Promise<string> {
|
async function renderRecordDetail(did: string, handle: string, collection: string, rkey: string, canDelete: boolean): Promise<string> {
|
||||||
const record = await getRecordRaw(did, collection, rkey)
|
const record = await getRecordRaw(did, collection, rkey)
|
||||||
|
|
||||||
if (!record) {
|
if (!record) {
|
||||||
@@ -94,6 +95,10 @@ async function renderRecordDetail(did: string, handle: string, collection: strin
|
|||||||
const schemaLabel = lexicon ? '✓ Schema' : '○ No schema'
|
const schemaLabel = lexicon ? '✓ Schema' : '○ No schema'
|
||||||
const json = JSON.stringify(record, null, 2)
|
const json = JSON.stringify(record, null, 2)
|
||||||
|
|
||||||
|
const deleteBtn = canDelete
|
||||||
|
? `<button class="delete-btn" data-collection="${collection}" data-rkey="${rkey}">Delete</button>`
|
||||||
|
: ''
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<div class="record-detail">
|
<div class="record-detail">
|
||||||
<div class="record-header">
|
<div class="record-header">
|
||||||
@@ -101,6 +106,7 @@ async function renderRecordDetail(did: string, handle: string, collection: strin
|
|||||||
<p class="record-uri">${record.uri}</p>
|
<p class="record-uri">${record.uri}</p>
|
||||||
<p class="record-cid">CID: ${record.cid}</p>
|
<p class="record-cid">CID: ${record.cid}</p>
|
||||||
<span class="schema-status schema-${schemaStatus}">${schemaLabel}</span>
|
<span class="schema-status schema-${schemaStatus}">${schemaLabel}</span>
|
||||||
|
${deleteBtn}
|
||||||
</div>
|
</div>
|
||||||
<div class="json-view">
|
<div class="json-view">
|
||||||
<pre><code>${escapeHtml(json)}</code></pre>
|
<pre><code>${escapeHtml(json)}</code></pre>
|
||||||
@@ -113,19 +119,21 @@ export async function mountAtBrowser(
|
|||||||
container: HTMLElement,
|
container: HTMLElement,
|
||||||
handle: string,
|
handle: string,
|
||||||
collection: string | null,
|
collection: string | null,
|
||||||
rkey: string | null
|
rkey: string | null,
|
||||||
|
loginDid: string | null = null
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
container.innerHTML = '<p class="loading">Loading...</p>'
|
container.innerHTML = '<p class="loading">Loading...</p>'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const did = handle.startsWith('did:') ? handle : await resolveHandle(handle)
|
const did = handle.startsWith('did:') ? handle : await resolveHandle(handle)
|
||||||
|
const canDelete = loginDid !== null && loginDid === did
|
||||||
|
|
||||||
let content: string
|
let content: string
|
||||||
let nav = ''
|
let nav = ''
|
||||||
|
|
||||||
if (collection && rkey) {
|
if (collection && rkey) {
|
||||||
nav = `<a href="?mode=browser&handle=${handle}&collection=${encodeURIComponent(collection)}" class="back-link">← Back</a>`
|
nav = `<a href="?mode=browser&handle=${handle}&collection=${encodeURIComponent(collection)}" class="back-link">← Back</a>`
|
||||||
content = await renderRecordDetail(did, handle, collection, rkey)
|
content = await renderRecordDetail(did, handle, collection, rkey, canDelete)
|
||||||
} else if (collection) {
|
} else if (collection) {
|
||||||
nav = `<a href="?mode=browser&handle=${handle}" class="back-link">← Collections</a>`
|
nav = `<a href="?mode=browser&handle=${handle}" class="back-link">← Collections</a>`
|
||||||
content = await renderRecordList(did, handle, collection)
|
content = await renderRecordList(did, handle, collection)
|
||||||
@@ -134,6 +142,33 @@ export async function mountAtBrowser(
|
|||||||
}
|
}
|
||||||
|
|
||||||
container.innerHTML = nav + content
|
container.innerHTML = nav + content
|
||||||
|
|
||||||
|
// Add delete button handler
|
||||||
|
const deleteBtn = container.querySelector('.delete-btn')
|
||||||
|
if (deleteBtn) {
|
||||||
|
deleteBtn.addEventListener('click', async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
const btn = e.target as HTMLButtonElement
|
||||||
|
const col = btn.dataset.collection
|
||||||
|
const rk = btn.dataset.rkey
|
||||||
|
|
||||||
|
if (!col || !rk) return
|
||||||
|
|
||||||
|
if (!confirm('Delete this record?')) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
btn.disabled = true
|
||||||
|
btn.textContent = 'Deleting...'
|
||||||
|
await deleteRecord(col, rk)
|
||||||
|
// Go back to collection
|
||||||
|
window.location.href = `?mode=browser&handle=${handle}&collection=${encodeURIComponent(col)}`
|
||||||
|
} catch (err) {
|
||||||
|
alert('Delete failed: ' + err)
|
||||||
|
btn.disabled = false
|
||||||
|
btn.textContent = 'Delete'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
container.innerHTML = `<p class="error">Failed to load: ${err}</p>`
|
container.innerHTML = `<p class="error">Failed to load: ${err}</p>`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,3 +145,19 @@ export async function createPost(collection: string, title: string, content: str
|
|||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function deleteRecord(collection: string, rkey: string): Promise<boolean> {
|
||||||
|
if (!agent) return false
|
||||||
|
|
||||||
|
try {
|
||||||
|
await agent.com.atproto.repo.deleteRecord({
|
||||||
|
repo: agent.assertDid,
|
||||||
|
collection,
|
||||||
|
rkey,
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Delete record error:', err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -125,7 +125,8 @@ async function init(): Promise<void> {
|
|||||||
// AT Browser mode
|
// AT Browser mode
|
||||||
if (mode === 'browser') {
|
if (mode === 'browser') {
|
||||||
profileEl.innerHTML = renderTabs(handle, mode, isLoggedIn)
|
profileEl.innerHTML = renderTabs(handle, mode, isLoggedIn)
|
||||||
await mountAtBrowser(contentEl, handle, collection, rkey)
|
const loginDid = authSession?.did || null
|
||||||
|
await mountAtBrowser(contentEl, handle, collection, rkey, loginDid)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -475,6 +475,27 @@ body {
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
background: #dc3545;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn:hover {
|
||||||
|
background: #c82333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn:disabled {
|
||||||
|
background: #999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
/* JSON View */
|
/* JSON View */
|
||||||
.json-view {
|
.json-view {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
@@ -554,4 +575,10 @@ body {
|
|||||||
background: #2a2a2a;
|
background: #2a2a2a;
|
||||||
color: #888;
|
color: #888;
|
||||||
}
|
}
|
||||||
|
.delete-btn {
|
||||||
|
background: #dc3545;
|
||||||
|
}
|
||||||
|
.delete-btn:hover {
|
||||||
|
background: #c82333;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user