diff --git a/CHANGELOG.md b/CHANGELOG.md index c5b4f27..eac930d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,7 @@ Version numbers follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html ### Changed -- **Redacted and deleted cards stay in the grid until the next scan** — previously redacting (✏) or deleting (🗑) a card removed it from the grid and from `S.flaggedData`/`S.filteredData` immediately. Now the item is kept and marked: the card is greyed (`card-resolved` styling), shows a `✏ Redacted` (green) or `🗑 Deleted` (red) badge, and its action buttons are hidden so it can't be re-processed. The operator can see what was handled during the session; the grid is rebuilt on the next scan run, which clears the markers. Implemented with `_redacted` / `_deleted` flags in `results.js` (`appendCard` + `redactItem` / `deleteItem`); no server change. +- **Redacted and deleted cards stay in the grid until the next scan** — previously redacting (✏) or deleting (🗑) a card — or running a bulk delete — removed the affected cards from the grid and from `S.flaggedData`/`S.filteredData` immediately. Now each item is kept and marked: the card is greyed (`card-resolved` styling), shows a `✏ Redacted` (green) or `🗑 Deleted` (red) badge, and its action buttons are hidden so it can't be re-processed. The operator can see what was handled during the session; the grid is rebuilt on the next scan run, which clears the markers. Implemented with `_redacted` / `_deleted` flags in `results.js` (`appendCard`, `redactItem`, `deleteItem`, `executeBulkDelete`); handled items are also excluded from the bulk-delete match set. `POST /api/delete_bulk` now returns `deleted_ids` so the grid marks exactly the items the server actually deleted (partial failures stay active). ### Fixed diff --git a/routes/export.py b/routes/export.py index 446f151..cb2030d 100644 --- a/routes/export.py +++ b/routes/export.py @@ -1758,10 +1758,11 @@ def delete_bulk(): except Exception: pass return jsonify({ - "ok": True, - "deleted": len(deleted_ids), - "failed": len(failed_items), - "errors": failed_items[:10], # cap error list + "ok": True, + "deleted": len(deleted_ids), + "deleted_ids": deleted_ids, # so the grid can mark exactly these + "failed": len(failed_items), + "errors": failed_items[:10], # cap error list }) diff --git a/static/js/results.js b/static/js/results.js index 13ae0dd..0729c32 100644 --- a/static/js/results.js +++ b/static/js/results.js @@ -680,6 +680,7 @@ function _bdFilters() { function _bdMatches() { const f = _bdFilters(); return S.flaggedData.filter(x => { + if (x._deleted || x._redacted) return false; // already handled this session if (f.source_type && x.source_type !== f.source_type) return false; if (x.cpr_count < f.min_cpr) return false; if (f.older_than_date && x.modified > f.older_than_date) return false; @@ -885,9 +886,12 @@ async function executeBulkDelete() { }); const d = await r.json(); if (d.ok) { - const deletedSet = new Set(matches.map(x => x.id)); - S.flaggedData = S.flaggedData.filter(x => !deletedSet.has(x.id)); - S.filteredData = S.filteredData.filter(x => !deletedSet.has(x.id)); + // Keep the deleted items in the grid (marked, greyed, buttons hidden) + // until the next scan run — only those the server actually deleted. + const deletedSet = new Set(d.deleted_ids || matches.map(x => x.id)); + const _mark = (x) => { if (deletedSet.has(x.id)) x._deleted = true; }; + S.flaggedData.forEach(_mark); + S.filteredData.forEach(_mark); renderGrid(S.filteredData.length ? S.filteredData : S.flaggedData); updateStats(); prog.innerHTML = `✓ ${d.deleted} ${t('m365_bulk_deleted', 'deleted')}` +