Files
dobetternorge-tools/assets/js/corpus-save.js
T
daveadmin b014638f39 feat(corpus): add save-to-corpus + private corpus search scope
- POST /api/save-to-corpus.php — saves tool output text to user's default CaveauAI corpus via ClientRagPipeline
- api/case/upload.php — dual-writes uploaded PDFs to CaveauAI client_documents (best-effort)
- assets/js/corpus-save.js — shared <dialog> handler for .js-save-corpus buttons on all tool pages
- includes/layout_footer.php — injects corpus-save.js + shared save dialog markup
- korrespond/deep-research/barnevernet/discrepancy JS — save-to-corpus buttons on output sections
- api/search.php + LegalTools::search() — corpus_scope param ('shared'|'private'|'both'), merges personal CaveauAI corpus with shared legal library when 'both'
- includes/tool_form.php + assets/js/tools.js — corpus scope radio toggle shown on search tab
- api/user-docs.php — add POST upload method for non-SSO authenticated users

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 17:50:32 +02:00

107 lines
3.1 KiB
JavaScript

/**
* corpus-save.js — "Save to corpus" shared handler for all DBN tool pages.
*
* Buttons that trigger a save must have:
* class="js-save-corpus"
* data-content-id="<id of element containing the text to save>"
* data-tool="<source_tool slug, e.g. korrespond>"
* data-suggested-title="<pre-filled title string>" (optional)
*/
(function () {
'use strict';
const dlg = document.getElementById('save-corpus-dialog');
const form = document.getElementById('save-corpus-form');
const titleIn = document.getElementById('save-corpus-title');
const tagsIn = document.getElementById('save-corpus-tags');
const cancelBtn = document.getElementById('save-corpus-cancel');
if (!dlg || !form) return; // dialog not present (e.g. not logged in)
cancelBtn?.addEventListener('click', () => dlg.close());
let _pendingBtn = null;
let _pendingContent = '';
let _pendingTool = '';
// Delegated click — catches buttons added dynamically by tool JS
document.addEventListener('click', (e) => {
const btn = e.target.closest('.js-save-corpus');
if (!btn) return;
const contentId = btn.dataset.contentId;
const el = contentId ? document.getElementById(contentId) : null;
const content = (el ? (el.value ?? el.textContent) : '').trim();
if (!content || content.length < 30) {
btn.textContent = 'Nothing to save';
setTimeout(() => { btn.textContent = 'Save to corpus'; }, 2000);
return;
}
_pendingBtn = btn;
_pendingContent = content;
_pendingTool = btn.dataset.tool ?? '';
titleIn.value = btn.dataset.suggestedTitle ?? '';
tagsIn.value = '';
dlg.showModal();
titleIn.focus();
titleIn.select();
});
// Form submit inside dialog
form.addEventListener('submit', async (e) => {
e.preventDefault();
dlg.close();
const btn = _pendingBtn;
const content = _pendingContent;
const title = titleIn.value.trim();
const tags = tagsIn.value.trim();
const tool = _pendingTool;
if (!title || !content) return;
if (btn) {
btn.disabled = true;
btn.textContent = 'Saving…';
}
try {
const resp = await fetch('api/save-to-corpus.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ title, content, source_tool: tool, tags }),
});
const data = await resp.json().catch(() => ({}));
if (resp.ok && data.ok) {
if (btn) {
btn.textContent = '✓ Saved to corpus';
btn.classList.add('js-save-corpus--saved');
}
} else {
const msg = data.error ?? `Error ${resp.status}`;
if (btn) {
btn.textContent = 'Save failed';
btn.disabled = false;
btn.title = msg;
}
console.error('[corpus-save] Save failed:', msg);
}
} catch (err) {
if (btn) {
btn.textContent = 'Network error';
btn.disabled = false;
}
console.error('[corpus-save] Network error:', err);
}
_pendingBtn = null;
_pendingContent = '';
});
}());