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 { 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>`
} }

View File

@@ -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
}
}

View File

@@ -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
} }

View File

@@ -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;
}
} }