fix(webapp): a wikilink is a real link, not a wiki: string (BEA-136) - #151
Open
ssowonny wants to merge 1 commit into
Open
fix(webapp): a wikilink is a real link, not a wiki: string (BEA-136)#151ssowonny wants to merge 1 commit into
ssowonny wants to merge 1 commit into
Conversation
[[guide]] rendered as href="wiki:guide" — a pseudo-scheme no browser can resolve. The delegated click handler rescued a plain left-click, so the feature looked fine until someone copied the link, middle-clicked it, or opened it in a new tab and got a dead string. Resolution moves from click time to transform time: transformHTML (the pass that already rewrites this HTML before the mount) matches the target against flatFiles and writes the real urlForPath() URL, plus a data-wiki marker. A wikilink matching no file loses its href entirely and renders as .wiki-missing, so no "wiki:" survives into the DOM either way. The matching rules didn't change — they moved into a pure resolveWiki() in util.ts, where node --test covers the whole matrix without a browser. The consequence to get right is the click: real hrefs mean a plain click must be intercepted (or it does a full document load) and every modified click must be let through (or the fix buys nothing) — the same rule nav.ts:linkProps applies everywhere else. The guard sits above both branches, so cmd-clicking a relative markdown link now opens a tab too instead of SPA-navigating the current one. markdown.go is unchanged: wiki: stays the marker the server leaves behind because RenderMarkdown has no file tree. /s/<token> share pages keep their dead wikilinks by the spec's decision — the target isn't part of the share. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
TL;DR
[[wikilink]]handed youwiki:guide— a dead string. Plain clicks always worked, which is why nobody caught it./<project-id>/guide.mdURL, so every way of using a link works the way it looks like it should./s/<token>share pages still render dead wikilinks — the target isn't part of the share, so a real URL would hand an anonymous visitor a 404.Wikilinks resolved at click time. The DOM kept the server's
wiki:marker, and the click handler rescued only the one path that never reads the attribute:flowchart TD A["one rendered anchor<br/><a href="wiki:guide">"] --> B["left-click"] A --> C["copy link / middle-click / cmd-click / new tab"] B --> D["handler intercepts,<br/>opens guide.md<br/>WORKS"] C --> E["browser follows href<br/>wiki:guide<br/>DEAD"]The fix moves the match one step earlier, into
transformHTML— the pass that already rewrites this HTML before the mount (relative image srcs, external-link targets). Nothing patches the mounteddangerouslySetInnerHTMLsubtree, which is the failure CLAUDE.md calls out by name.flowchart LR S["server<br/>markdown.go<br/>href=wiki:guide"] --> T["transformHTML NEW<br/>match flatFiles<br/>href=/<pid>/guide.md"] T --> D["mounted DOM<br/>copy, middle-click,<br/>new tab all real"] D --> H["click handler<br/>plain -> openFile<br/>modified -> browser"]What changed
src/util.tsresolveWiki(target, files)— the matching rules lifted verbatim out ofopenWikilink(exact path, path +.md, basename, basename +.md, all case-insensitive, path before basename). Pure and DOM-free, sonode --testcovers the whole matrix without a browser.src/components/FileView.tsxtransformHTMLgainsfiles+projectId. A hit getshref=urlForPath(hit.path, projectId)and adata-wikimarker; a miss loses itshrefand getsclass="wiki-missing"+ a title.openWikilinkis gone.src/components/FileView.tsxhandleLinkClickinterceptsdata-wikianchors only, and returns early for modified / non-primary clicks — the same rulenav.ts:linkPropsapplies to every other link in the app.src/apps/Browser.tsxprojectId={project?.id}down. Volume mode has none, sourlForPathyields/<path>there.src/style.css.markdown a.wiki-missing— an anchor with no href loses link styling entirely, and a broken cross-reference silently reading as prose is worse than the dead URL it replaced.e2e_serve_test.goindex.mdgains a dangling[[nowhere]], so the unresolved case has something to assert against. Content-only change to an existing op.markdown.gois untouched.wiki:stays the marker the server leaves behind (RenderMarkdownis pure and has no file tree) — it just never survives to the mounted DOM.Why
data-wikirather than "any root-absolute href": an author writing[x](/somewhere)in their own markdown keeps today's behavior instead of quietly becoming an SPA route, and the target path is read back directly instead of re-parsed out of a URL.The one deviation from the reviewed plan
resolveWikitakes a structural{ path, name }[]instead of importingNodefromapi/types. Same call sites, same behavior, one less import in the module the node test runner loads.Before / after
The bug lives in the
hrefattribute, so the screenshots only show the visible half — the new unresolved-wikilink treatment. The attribute itself is in the DOM read below them.origin/main)The same page's anchors, read out of the live DOM:
Verification
go test ./...— pass (full suite).npm test— 79 pass, including the newresolveWikimatrix (path/basename precedence, implied.md, mixed case, miss returnsundefined).npm run e2e— 171 pass, 1 skipped (pre-existing). The existingwikilink navigates to the target filenow assertsgetAttribute("href")and that a plain click did not reload the document; a new spec covers the modified click staying put and[[nowhere]]rendering with no href and nowiki:anywhere in#content.npm run buildrun andinternal/webapp/static/committed;check-dist.shclean.The
architecture/webapp-frontend.mdnote ontransformHTMLgained a sentence describing the new pass. No types or relationships changed, so there's no architecture diff section.Build session
(Only works on the machine that built this.)