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
+20 -2
View File
@@ -29,6 +29,10 @@ final class CaseResults
'deep-research',
'discrepancy',
'timeline',
'summarize',
'ask',
'redact',
'transcribe',
];
/** True when the user is on a tier that gets saved results (Plus, Pro, or active Plus trial). */
@@ -71,8 +75,10 @@ final class CaseResults
return 0;
}
// Title default: first 80 chars of the most descriptive input field.
$title = self::deriveTitle($tool, $input);
// Caller may supply an explicit title (e.g. from a manual "Save result" prompt).
$title = isset($meta['title']) && trim((string)$meta['title']) !== ''
? mb_substr(trim((string)$meta['title']), 0, 200, 'UTF-8')
: self::deriveTitle($tool, $input);
$caseDocIds = $meta['case_doc_ids'] ?? [];
if (!is_array($caseDocIds)) {
@@ -228,6 +234,10 @@ final class CaseResults
'deep-research' => 'Dyp analyse',
'discrepancy' => 'Motstrid',
'timeline' => 'Tidslinje',
'summarize' => 'Sammendrag',
'ask' => 'Spørsmål & svar',
'redact' => 'Anonymisering',
'transcribe' => 'Transkripsjon',
][$tool] ?? ucfirst($tool);
}
@@ -241,6 +251,10 @@ final class CaseResults
'deep-research' => '🔬',
'discrepancy' => '🔍',
'timeline' => '📅',
'summarize' => '📝',
'ask' => '💬',
'redact' => '🖊️',
'transcribe' => '🎙️',
][$tool] ?? '📄';
}
@@ -254,6 +268,10 @@ final class CaseResults
'deep-research' => [$input['question'] ?? null, $input['query'] ?? null, $input['topic'] ?? null],
'discrepancy' => [$input['focus'] ?? null, $input['context'] ?? null],
'timeline' => [$input['context'] ?? null, $input['text'] ?? null],
'summarize' => [$input['text'] ?? null],
'ask' => [$input['question'] ?? null],
'redact' => [$input['text'] ?? null],
'transcribe' => [$input['filename'] ?? null],
default => [$input['title'] ?? null, $input['query'] ?? null, $input['text'] ?? null],
};
foreach ($candidates as $c) {