Add My Documents panel to workbench + user-docs API
- api/user-docs.php: GET/DELETE shared dbn_user_docs table (SSO users only) connects to dobetternorge DB via DBN_DB_* env vars - workbench.php: My Documents panel (section 05) for SSO/free-tier users; shows docs uploaded from either AI chat or tools, links to AI Chat for upload - workbench.js: fetch + render doc list, delete with Qdrant cleanup - tools.css: workbench-docs panel + item styles - i18n.php: my_docs_* strings in all 4 languages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -94,3 +94,80 @@
|
||||
});
|
||||
}
|
||||
}());
|
||||
|
||||
// ── My Documents panel ────────────────────────────────────────────────────────
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
var panel = document.querySelector('[data-my-docs="true"]');
|
||||
var list = document.getElementById('myDocsList');
|
||||
if (!panel || !list) return;
|
||||
|
||||
var lang = (window.DBN_TOOLS_LANG || 'en');
|
||||
|
||||
var i18n = {
|
||||
empty: { en: 'No documents uploaded yet. Upload PDFs, DOCX, or TXT files in the AI Chat sidebar.', no: 'Ingen dokumenter lastet opp ennå. Last opp PDF, DOCX eller TXT i AI-chattens sidepanel.', uk: 'Документів ще немає. Завантажте файли у бічній панелі AI-чату.', pl: 'Brak dokumentów. Prześlij pliki w panelu bocznym czatu AI.' },
|
||||
remove: { en: 'Remove', no: 'Fjern', uk: 'Видалити', pl: 'Usuń' },
|
||||
ai: { en: 'AI Chat', no: 'AI-chat', uk: 'AI-чат', pl: 'Czat AI' },
|
||||
tools: { en: 'Tools', no: 'Verktøy', uk: 'Інструменти', pl: 'Narzędzia' },
|
||||
error: { en: 'Could not load documents.', no: 'Kunne ikke laste dokumenter.', uk: 'Не вдалося завантажити документи.', pl: 'Nie można załadować dokumentów.' },
|
||||
};
|
||||
|
||||
function t(key) {
|
||||
return (i18n[key] && i18n[key][lang]) || (i18n[key] && i18n[key]['en']) || key;
|
||||
}
|
||||
|
||||
function formatDate(str) {
|
||||
if (!str) return '';
|
||||
try { return new Date(str).toLocaleDateString(); } catch (e) { return str; }
|
||||
}
|
||||
|
||||
function renderDocs(docs) {
|
||||
if (!docs.length) {
|
||||
list.innerHTML = '<p class="workbench-docs__empty">' + t('empty') + '</p>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = docs.map(function (doc) {
|
||||
return '<div class="workbench-docs__item" role="listitem" data-doc-id="' + esc(doc.doc_id) + '">'
|
||||
+ '<span class="workbench-docs__icon">📄</span>'
|
||||
+ '<span class="workbench-docs__name" title="' + esc(doc.filename) + '">' + esc(doc.filename) + '</span>'
|
||||
+ '<span class="workbench-docs__meta">' + esc(formatDate(doc.created_at)) + ' · ' + (doc.source === 'ai_chat' ? t('ai') : t('tools')) + '</span>'
|
||||
+ '<button class="workbench-docs__remove" type="button" data-doc-id="' + esc(doc.doc_id) + '" aria-label="' + t('remove') + ' ' + esc(doc.filename) + '">' + t('remove') + '</button>'
|
||||
+ '</div>';
|
||||
}).join('');
|
||||
|
||||
list.querySelectorAll('.workbench-docs__remove').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var docId = btn.getAttribute('data-doc-id');
|
||||
if (!docId) return;
|
||||
btn.disabled = true;
|
||||
fetch('/api/user-docs.php?id=' + encodeURIComponent(docId), { method: 'DELETE', credentials: 'include' })
|
||||
.then(function () {
|
||||
var item = list.querySelector('[data-doc-id="' + docId + '"]');
|
||||
if (item) item.remove();
|
||||
if (!list.querySelector('.workbench-docs__item')) {
|
||||
list.innerHTML = '<p class="workbench-docs__empty">' + t('empty') + '</p>';
|
||||
}
|
||||
})
|
||||
.catch(function () { btn.disabled = false; });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function esc(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
fetch('/api/user-docs.php', { credentials: 'include' })
|
||||
.then(function (r) { return r.json(); })
|
||||
.then(function (data) {
|
||||
if (data.ok) {
|
||||
renderDocs(data.docs || []);
|
||||
} else {
|
||||
list.innerHTML = '<p class="workbench-docs__empty">' + t('error') + '</p>';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
list.innerHTML = '<p class="workbench-docs__empty">' + t('error') + '</p>';
|
||||
});
|
||||
}());
|
||||
|
||||
Reference in New Issue
Block a user