Add manual 'Save result' to all tools — replaces auto-save

All tool results can now be saved to My Case manually. Users click
'Save result', type a description, and confirm. This replaces the
previous silent auto-save on barnevernet/timeline/etc., giving users
control over what stays and what it's called (supports multiple runs
of the same tool with different titles).

- CaseResults: extend ELIGIBLE_TOOLS to include summarize, ask, redact,
  transcribe; add toolLabel/toolIcon entries; support explicit title
  via meta['title'] in save()
- api/case/save-result.php: new client-initiated save endpoint;
  accepts tool + title + input_payload + output_payload + meta
- Remove CaseResults::save() auto-save from barnevernet, deep-research,
  discrepancy, korrespond, timeline API endpoints
- tools.js: add showSaveResultButton() (exposed as window.dbnShowSaveResultButton);
  wire for ask, redact, timeline, transcribe (both file-upload and
  stored-audio paths)
- barnevernet.js: wire save button after final result render
- summarize.js: wire save button after renderFinal(); passes sumResults
  container so widget appears in the correct #sumResults div
- case-result.php: rich tool-specific rendering for summarize, ask,
  redact, transcribe, timeline; update re-run link map to include all
  new tools
- tools.css: styles for .save-result-widget and its states (idle,
  prompt, done, error)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-24 01:27:26 +02:00
parent 0fcfed1a86
commit 2013648ee0
12 changed files with 473 additions and 80 deletions
+11
View File
@@ -25,6 +25,7 @@
// ── State ─────────────────────────────────────────────────────────────────
var _extractedFiles = []; // [{ name, text, chars }]
var _currentLang = 'en';
var _lastPayload = null;
// ── Lang switcher ─────────────────────────────────────────────────────────
document.querySelectorAll('.sum-lang-btn').forEach(function (btn) {
@@ -177,6 +178,7 @@
slices: slices,
};
if (docIds.length) payload.doc_ids = docIds;
_lastPayload = payload;
setBusy(true);
setStatus('Running…');
@@ -218,6 +220,15 @@
setStatus(data.detail || '');
} else if (data.event === 'final') {
renderFinal(data);
if (typeof window.dbnShowSaveResultButton === 'function') {
window.dbnShowSaveResultButton(
'summarize',
_lastPayload || {},
data,
{ model: data.engine || null, latency_ms: data.latency_ms || 0 },
resultsEl
);
}
if (data.balance != null) {
var credEl = document.getElementById('creditsRemaining');
if (credEl) credEl.textContent = data.balance;