fixes: tag assign stale body, board placeholder, plugin pending, bucket activate

- Context menu tag toggle reads fresh body from state.cards — was
  overwriting with stale snapshot, dropping existing tags (e.g. #done)
- Board empty-state centered with flex (vertical + horizontal)
- Plugin settings: batch toggles via Apply button, single reload
  instead of one reload per toggle
- New bucket creation activates it directly on the board

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
thandClaude Opus 4.6 committed 2026-04-14 16:13:46 +02:00
1 parent 3cca14a3c6
commit 002562b1d3
6 files changed
+105 -70

No files matched your search

+26 -18
View File
@@ -195,36 +195,44 @@ export function showContextMenu(x, y, card) {
</button>` : '');
tagList.querySelectorAll('[data-ctx-tag]').forEach(btn => btn.addEventListener('click', async e => {
e.stopPropagation();
e.stopPropagation(); e.preventDefault();
const targetId = card.id;
const tag = btn.dataset.ctxTag;
const has = cardTags.includes(tag);
let newBody = card.body || '';
// Re-read the current card from state to avoid stale body
const fresh = state.cards.find(x => x.id == targetId) || card;
const freshTags = parseTags(fresh);
const has = freshTags.includes(tag);
let newBody = fresh.body || '';
if (has) {
newBody = newBody.replace(new RegExp('\\s*#' + tag.replace(/[.*+?^${}()|[\]\\\/]/g, '\\$&') + '(?=\\s|$)', 'm'), '');
cardTags.splice(cardTags.indexOf(tag), 1);
} else {
newBody = newBody.trimEnd() + ' #' + tag;
cardTags.push(tag);
}
card.body = newBody;
await api(`api/cards/${card.id}`, { method: 'PATCH', body: { body: newBody } });
const c = state.cards.find(x => x.id == card.id);
if (c) { c.body = newBody; c.tags = cardTags.join(','); }
const updated = await api(`api/cards/${targetId}`, { method: 'PATCH', body: { body: newBody } });
// Trust the server's response for the new tags string
const c = state.cards.find(x => x.id == targetId);
if (c) { c.body = updated?.body ?? newBody; c.tags = updated?.tags ?? ''; }
// Update our local working copy
card.body = c?.body ?? newBody;
cardTags.length = 0;
cardTags.push(...parseTags(c || { tags: updated?.tags || '' }));
renderCtxTags(tagInput.value);
window._renderBoard();
}));
tagList.querySelectorAll('[data-ctx-tag-new]').forEach(btn => btn.addEventListener('click', async e => {
e.stopPropagation();
e.stopPropagation(); e.preventDefault();
const targetId = card.id;
const tag = btn.dataset.ctxTagNew;
const newBody = (card.body || '').trimEnd() + ' #' + tag;
card.body = newBody;
cardTags.push(tag);
allTags.push(tag);
allTags.sort();
await api(`api/cards/${card.id}`, { method: 'PATCH', body: { body: newBody } });
const c = state.cards.find(x => x.id == card.id);
if (c) { c.body = newBody; c.tags = cardTags.join(','); }
const fresh = state.cards.find(x => x.id == targetId) || card;
const newBody = (fresh.body || '').trimEnd() + ' #' + tag;
const updated = await api(`api/cards/${targetId}`, { method: 'PATCH', body: { body: newBody } });
const c = state.cards.find(x => x.id == targetId);
if (c) { c.body = updated?.body ?? newBody; c.tags = updated?.tags ?? ''; }
card.body = c?.body ?? newBody;
cardTags.length = 0;
cardTags.push(...parseTags(c || { tags: updated?.tags || '' }));
if (!allTags.includes(tag)) { allTags.push(tag); allTags.sort(); }
tagInput.value = '';
renderCtxTags('');
window._renderBoard();