feat(ui): clickable document viewer — open any cited document in the browser from chat chips and the sources table

This commit is contained in:
2026-08-22 02:08:49 -04:00
parent 7e8d14702e
commit 6ec6181c7b
15 changed files with 1218 additions and 58 deletions
+27 -4
View File
@@ -21,6 +21,12 @@ function fmtDate(iso) {
}
}
/* Viewer link (phase 10) — same encoded URL the chat chips use; both query
* values are percent-encoded (paths contain slashes, sometimes spaces). */
export function documentUrl(source, path) {
return "/document.html?source=" + encodeURIComponent(source) + "&path=" + encodeURIComponent(path);
}
async function loadDocs() {
let r;
try {
@@ -56,13 +62,30 @@ async function loadDocs() {
function makeRow(d) {
const tr = document.createElement("tr");
const cells = [d.source, d.path, d.title, String(d.chunks), fmtDate(d.indexed_at)];
for (const value of cells) {
const sourceTd = document.createElement("td");
sourceTd.textContent = d.source; // document-derived text — never innerHTML
tr.appendChild(sourceTd);
// Path cell: a link to the document viewer (phase 10), full path as the
// accessible/hover name (the column is ellipsized).
const pathTd = document.createElement("td");
pathTd.title = d.path; // full path on hover (column is ellipsized)
const link = document.createElement("a");
link.className = "doc-link";
link.href = documentUrl(d.source, d.path);
link.target = "_blank"; // open the full document in a new tab
link.rel = "noopener";
link.title = d.path; // full path as the link's hover/accessible name
link.textContent = d.path;
pathTd.appendChild(link);
tr.appendChild(pathTd);
for (const value of [d.title, String(d.chunks), fmtDate(d.indexed_at)]) {
const td = document.createElement("td");
td.textContent = value; // document-derived text — never innerHTML
td.textContent = value;
tr.appendChild(td);
}
tr.children[1].title = d.path; // full path on hover (column is ellipsized)
return tr;
}