add delete

This commit is contained in:
2026-01-15 17:28:04 +09:00
parent cf46369cd0
commit 64457460eb
4 changed files with 83 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
import { describeRepo, listRecordsRaw, getRecordRaw, fetchLexicon, resolveHandle, getServiceInfo } from '../lib/api.js'
import { deleteRecord } from '../lib/auth.js'
function extractRkey(uri: string): string {
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)
if (!record) {
@@ -94,6 +95,10 @@ async function renderRecordDetail(did: string, handle: string, collection: strin
const schemaLabel = lexicon ? '✓ Schema' : '○ No schema'
const json = JSON.stringify(record, null, 2)
const deleteBtn = canDelete
? `<button class="delete-btn" data-collection="${collection}" data-rkey="${rkey}">Delete</button>`
: ''
return `
<div class="record-detail">
<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-cid">CID: ${record.cid}</p>
<span class="schema-status schema-${schemaStatus}">${schemaLabel}</span>
${deleteBtn}
</div>
<div class="json-view">
<pre><code>${escapeHtml(json)}</code></pre>
@@ -113,19 +119,21 @@ export async function mountAtBrowser(
container: HTMLElement,
handle: string,
collection: string | null,
rkey: string | null
rkey: string | null,
loginDid: string | null = null
): Promise<void> {
container.innerHTML = '<p class="loading">Loading...</p>'
try {
const did = handle.startsWith('did:') ? handle : await resolveHandle(handle)
const canDelete = loginDid !== null && loginDid === did
let content: string
let nav = ''
if (collection && rkey) {
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) {
nav = `<a href="?mode=browser&handle=${handle}" class="back-link">← Collections</a>`
content = await renderRecordList(did, handle, collection)
@@ -134,6 +142,33 @@ export async function mountAtBrowser(
}
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) {
container.innerHTML = `<p class="error">Failed to load: ${err}</p>`
}

View File

@@ -145,3 +145,19 @@ export async function createPost(collection: string, title: string, content: str
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
}
}

View File

@@ -125,7 +125,8 @@ async function init(): Promise<void> {
// AT Browser mode
if (mode === 'browser') {
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
}

View File

@@ -475,6 +475,27 @@ body {
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 {
background: #f5f5f5;
@@ -554,4 +575,10 @@ body {
background: #2a2a2a;
color: #888;
}
.delete-btn {
background: #dc3545;
}
.delete-btn:hover {
background: #c82333;
}
}