fix: open #document deep-links on refresh and surface load errors (#631)

Add a hashchange handler for #document-<id> so refresh / URL-bar nav opens the document, and replace the silent console.error in loadDocument with a user-facing toast.

Closes #560
This commit is contained in:
Rasmus
2026-06-02 04:48:54 +02:00
committed by GitHub
parent 35ba56fa0c
commit 1882ad68ea
2 changed files with 51 additions and 1 deletions

View File

@@ -152,6 +152,8 @@ import * as Modals from './modalManager.js';
addDocToTabs,
syncDocIndicator: _syncDocIndicator,
});
_maybeOpenDocFromHash();
window.addEventListener('hashchange', _maybeOpenDocFromHash);
}
/** Update overflow-doc-btn accent indicator, toolbar indicator, and session list icon */
@@ -5811,16 +5813,31 @@ import * as Modals from './modalManager.js';
}
try {
const res = await fetch(`${API_BASE}/api/document/${docId}`);
if (!res.ok) throw new Error('Not found');
if (!res.ok) throw new Error(res.status === 404 ? 'Not found' : `HTTP ${res.status}`);
const doc = await res.json();
addDocToTabs(doc, doc.session_id);
_ensureDocPaneMounted();
switchToDoc(doc.id);
} catch (e) {
console.error('Failed to load document:', e);
if (uiModule) {
const msg = e.message === 'Not found'
? 'Document not found — try opening it from the Library.'
: 'Could not open document.';
uiModule.showError(msg);
}
}
}
// Deep-link: #document-<id> opens that document on load / URL-bar nav.
// Clicks on in-chat document anchors are handled separately (they call
// preventDefault, so they don't change the hash); this covers refresh
// and pasted/typed document URLs, which previously did nothing.
function _maybeOpenDocFromHash() {
const m = (window.location.hash || '').match(/^#document-(.+)$/);
if (m) loadDocument(m[1]);
}
/** Open panel and ensure a document exists, creating a session if needed */
export async function ensureDocPanel() {
let sessionId = _lastSessionId

View File

@@ -0,0 +1,33 @@
"""Regression guards for in-chat document deep-links (#document-<id>).
The frontend module is browser-coupled (window/fetch/document) so there's
no JS unit harness for it — these pin the source-level invariants that the
404-silent-failure fix depends on. See issue #560.
"""
from pathlib import Path
_REPO = Path(__file__).resolve().parents[1]
def test_chat_document_links_use_the_document_id():
"""The list/open tool must anchor to the real document id, not a slug —
a slug 404s against the UUID-keyed /api/document/<id> route."""
src = (_REPO / "src" / "tool_implementations.py").read_text(encoding="utf-8")
assert "(#document-{d.id})" in src
assert "(#document-{doc.id})" in src
def test_document_deeplink_handled_on_hashchange_and_load():
"""#document-<id> in the URL must open the doc on refresh / URL-bar nav,
not just on click."""
js = (_REPO / "static" / "js" / "document.js").read_text(encoding="utf-8")
assert "addEventListener('hashchange', _maybeOpenDocFromHash)" in js
assert "#document-" in js
def test_failed_document_load_surfaces_user_error():
"""A missing/failed document must tell the user, not fail silently."""
js = (_REPO / "static" / "js" / "document.js").read_text(encoding="utf-8")
assert "uiModule.showError" in js
assert "Document not found" in js