← back to Marketing Command Center
board UX: add 'Clear staged' — dismisses stale staged/pending/failed cards (keeps posted history) via new POST /api/channels/outbox/clear; Compose links to Composer
2888aa46b4eeecce14854692b9dec704743eff8e · 2026-07-17 08:55:50 -0700 · Steve Abrams
Files touched
M modules/channels/index.jsM public/panels/board.htmlM public/panels/board.js
Diff
commit 2888aa46b4eeecce14854692b9dec704743eff8e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Jul 17 08:55:50 2026 -0700
board UX: add 'Clear staged' — dismisses stale staged/pending/failed cards (keeps posted history) via new POST /api/channels/outbox/clear; Compose links to Composer
---
modules/channels/index.js | 17 +++++++++++++++++
public/panels/board.html | 3 ++-
public/panels/board.js | 13 +++++++++++++
3 files changed, 32 insertions(+), 1 deletion(-)
diff --git a/modules/channels/index.js b/modules/channels/index.js
index 1bee6f9..e43cd20 100644
--- a/modules/channels/index.js
+++ b/modules/channels/index.js
@@ -503,6 +503,23 @@ module.exports = {
res.json({ platforms: st, connectedCount: connected, total: Object.keys(st).length, outbox: readOutbox().length });
});
router.get('/outbox', (_req, res) => res.json({ items: readOutbox().slice(-100).reverse() }));
+ // Clear outbox cards. Body: { scope } — 'staged' (default) drops everything that
+ // never went live (staged / pending-connection / failed), keeping real 'posted'
+ // history; 'all' wipes everything; { channel } limits it to one channel. Lets the
+ // board dismiss stale seed/staged cards (e.g. old pending-connection demo posts).
+ router.post('/outbox/clear', (req, res) => {
+ const { scope = 'staged', channel } = req.body || {};
+ const keptPosted = it => it.status === 'posted';
+ let items = readOutbox();
+ const before = items.length;
+ items = items.filter(it => {
+ if (channel && (it.channel || '').toLowerCase() !== String(channel).toLowerCase()) return true; // untouched
+ if (scope === 'all') return false;
+ return keptPosted(it); // 'staged' scope → keep only posted
+ });
+ writeOutbox(items);
+ res.json({ ok: true, removed: before - items.length, remaining: items.length });
+ });
// The Page picker's data source: the user's FB Pages (+ linked IG), discovered
// from /me/accounts. Tokens are STRIPPED before sending to the browser. Pass
diff --git a/public/panels/board.html b/public/panels/board.html
index 72c2358..cf888fa 100644
--- a/public/panels/board.html
+++ b/public/panels/board.html
@@ -10,7 +10,8 @@
<label class="muted" style="font-size:12px">Width
<input id="bd-width" type="range" min="240" max="420" step="10" value="300" style="vertical-align:middle">
</label>
- <a class="btn gold" href="#channels" style="text-decoration:none;font-size:12.5px;padding:6px 12px">✍️ Compose</a>
+ <a class="btn gold" href="#composer" style="text-decoration:none;font-size:12.5px;padding:6px 12px">✍️ Compose</a>
+ <button class="btn ghost" id="bd-clear" style="font-size:12.5px;padding:6px 12px" title="Remove staged / pending / failed cards (keeps posted history)">🗑 Clear staged</button>
<button class="btn ghost" id="bd-refresh" style="font-size:12.5px;padding:6px 12px">↻ Refresh</button>
</div>
</div>
diff --git a/public/panels/board.js b/public/panels/board.js
index 381a6ca..90f03ae 100644
--- a/public/panels/board.js
+++ b/public/panels/board.js
@@ -136,6 +136,19 @@ window.MCC_PANELS['board'] = {
$('#bd-width').addEventListener('input', e => { WIDTH = +e.target.value; setWidth(WIDTH); localStorage.setItem('mcc_board_w', WIDTH); });
$('#bd-sort').addEventListener('change', e => { SORT = e.target.value; localStorage.setItem('mcc_board_sort', SORT); render(); });
$('#bd-refresh').addEventListener('click', load);
+ // Clear staged/pending/failed cards (keeps posted history), then reload the board.
+ $('#bd-clear').addEventListener('click', async () => {
+ const btn = $('#bd-clear'); const label = btn.textContent;
+ if (!confirm('Remove all staged / pending / failed cards? (Posted history is kept.)')) return;
+ btn.disabled = true; btn.textContent = '…clearing';
+ try {
+ const r = await fetch(ORIGIN + '/api/channels/outbox/clear', {
+ method: 'POST', credentials: 'same-origin',
+ headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ scope: 'staged' }),
+ });
+ await r.json().catch(() => ({}));
+ } finally { btn.disabled = false; btn.textContent = label; await load(); }
+ });
await load();
},
← 075ec0c Vendor IG Reporting: render last 3 posts inline per vendor (
·
back to Marketing Command Center
·
deploy: exclude live-authoritative runtime data (outbox/toke 8738173 →