fix(response-viewer): keep a path link's label in the prose font, pin its edges

Merge-time fix for #665.

- A markdown link converted to a preview link became `a.rv-path`, so its
  label ("Our incident record") took the path style: monospace, 0.92em
  and `word-break: break-all`, which split prose mid-word on a phone. The
  anchor now also carries `rv-path-link`, and
  `.rv-text a.rv-path.rv-path-link` resets font and word-break, as the
  File Viewer does for its labelled document links.
- The first new test adds `/tmp/a.json?raw=true` (pins the `?query`
  strip) and `/tmp/` (pins the trailing-slash folder check, since
  findFilePathLinks finds no folder in a bare `/tmp/`), and checks the
  new class.
- The `_linkifyFilePaths` JSDoc and docs/architecture-invariants.md say
  the function also rewrites anchors whose href is a scheme-less,
  non-`//` path, on purpose without FILE_PATH_LINK_PATTERN's root and
  extension filter.
- Mobile Guide: "a web link" in the response viewer opens a tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-10-22 19:20:01 +02:00
1 parent 6f785e116f
commit fde23e3a07
5 files changed
+28 -5

No files matched your search

+9 -2
View File
@@ -117,7 +117,7 @@ describe('response viewer file-path linkifier', () => {
const root = linkify(
`<p><a href="${path}" target="_blank" rel="noopener noreferrer">Our incident record</a> and ` +
`<a href="src/a%20b.ts:42:7">a b</a>, <a href="docs/#L3">docs</a>, <a href="/tmp/renders">renders</a>, ` +
`<a href="/tmp/release%3A12">release</a></p>`
`<a href="/tmp/release%3A12">release</a>, <a href="/tmp/a.json?raw=true">raw</a>, <a href="/tmp/">tmp</a></p>`
);
const links = paths(root);
@@ -128,6 +128,9 @@ describe('response viewer file-path linkifier', () => {
'/tmp/renders',
// An encoded colon is part of the name, never a line suffix.
'/tmp/release:12',
// A query names a view of the file, not the file.
'/tmp/a.json',
'/tmp/',
]);
for (const a of links) {
expect(a.getAttribute('href')).toBe('#');
@@ -136,9 +139,13 @@ describe('response viewer file-path linkifier', () => {
expect(a.getAttribute('data-linkified')).toBe('1');
}
expect(links[0].textContent).toBe('Our incident record');
// A label, not a path: the second class keeps it in the prose font (styles.css).
expect(links.every((a) => a.classList.contains('rv-path-link'))).toBe(true);
// A trailing slash and a rooted folder path without one both open the folder grid
// (`:` ends a folder match in findFilePathLinks, so `release:12` previews instead).
expect(links.map((a) => a.hasAttribute('data-folder'))).toEqual([false, false, true, true, false]);
// findFilePathLinks finds no folder in a bare `/tmp/`, so only the trailing-slash
// check marks that one.
expect(links.map((a) => a.hasAttribute('data-folder'))).toEqual([false, false, true, true, false, false, true]);
});
it('opens a clicked markdown path link in the file preview through the click delegate', () => {