Candidates: inline rename (fix a name typo without reject + re-add)
A staged candidate could only be renamed by rejecting and re-adding it, which
churns the queue and discards the preview just to fix a typo. Add an inline
Rename on each candidate: a "Rename" pill swaps the name for an input
(Enter saves · Esc cancels), POST /api/admin/candidates/{id}/rename →
sources.rename_candidate(). Empty clears the name (promote then derives one
from the feed host). Preview is preserved; the fixed name carries into promotion.
Tests: test_candidate_rename (rename in place keeps preview, promotes with the
new name, gated + 404). 225 pytest + 11 vitest green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -293,6 +293,12 @@
|
||||
Object.assign(c, res, { _deep: false });
|
||||
} catch (e) { c._err = e?.message || 'Deep preview failed.'; c._deep = false; }
|
||||
}
|
||||
function startRename(c) { c._editName = c.name || ''; c._editing = true; c._err = ''; }
|
||||
async function saveRename(c) {
|
||||
try {
|
||||
Object.assign(c, await postJSON(`/api/admin/candidates/${c.id}/rename`, { name: (c._editName || '').trim() }), { _editing: false });
|
||||
} catch (e) { c._err = e?.message || 'Rename failed.'; }
|
||||
}
|
||||
async function promoteCandidate(c) {
|
||||
c._err = '';
|
||||
try {
|
||||
@@ -570,8 +576,16 @@
|
||||
{#each pendingCandidates as c (c.id)}
|
||||
<li>
|
||||
<div class="chead">
|
||||
<span class="cname">{c.name || c.feed_url}</span>
|
||||
<span class="cstatus">{c.status}</span>
|
||||
{#if c._editing}
|
||||
<input class="crename" bind:value={c._editName} placeholder="Source name"
|
||||
onkeydown={(e) => (e.key === 'Enter' ? saveRename(c) : e.key === 'Escape' ? (c._editing = false) : null)} />
|
||||
<button class="act" onclick={() => saveRename(c)}>Save</button>
|
||||
<button class="act" onclick={() => (c._editing = false)}>Cancel</button>
|
||||
{:else}
|
||||
<span class="cname">{c.name || c.feed_url}</span>
|
||||
<button class="act mini" onclick={() => startRename(c)}>Rename</button>
|
||||
<span class="cstatus">{c.status}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="curl">{c.feed_url}</div>
|
||||
{#if c.preview}
|
||||
@@ -1102,9 +1116,15 @@
|
||||
.addrow input:focus { outline: none; border-color: var(--accent); }
|
||||
ul.candlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
|
||||
ul.candlist li { background: var(--surface); border: 1px solid var(--line); border-radius: 12px; padding: 12px 14px; }
|
||||
.chead { display: flex; align-items: baseline; gap: 10px; }
|
||||
.chead { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
|
||||
.chead .cname { font-weight: 600; color: var(--ink); }
|
||||
.chead .cstatus { font-size: 0.72rem; color: var(--muted); text-transform: capitalize; }
|
||||
.chead .crename { font: inherit; font-size: 0.9rem; font-weight: 600; padding: 4px 9px;
|
||||
border: 1px solid var(--accent); border-radius: 8px; background: var(--bg); color: var(--ink); }
|
||||
.chead .crename:focus { outline: none; }
|
||||
.act.mini { font-size: 0.72rem; padding: 2px 8px; color: var(--accent-deep);
|
||||
background: none; border: 1px solid var(--line); border-radius: 999px; cursor: pointer; }
|
||||
.act.mini:hover { border-color: var(--accent); }
|
||||
.curl { font-size: 0.76rem; color: var(--muted); word-break: break-all; margin-top: 2px; }
|
||||
.cprev { font-size: 0.84rem; color: var(--ink); margin-top: 7px; }
|
||||
.cprev .cex { color: var(--muted); font-size: 0.8rem; margin-top: 2px; font-style: italic; }
|
||||
|
||||
Reference in New Issue
Block a user