Skip to content

feat: add backlink hover previews#768

Merged
ocavue merged 5 commits into
nextfrom
wikilink-hover-preview-2
Jul 12, 2026
Merged

feat: add backlink hover previews#768
ocavue merged 5 commits into
nextfrom
wikilink-hover-preview-2

Conversation

@ocavue

@ocavue ocavue commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Resting the pointer on a wiki link in a desktop note pane now shows a passive, local-only preview of the existing target, built on meowdown 0.46's async WikilinkHoverCard and a new side-effect-free resolveExistingWikiTarget resolver whose unavailable outcome also stops navigation, autocomplete, and capture from minting duplicate notes for iCloud placeholders or transient read failures.

Supersedes #756.

Summary by CodeRabbit

  • New Features
    • Added desktop hover previews for wiki links, including note content, daily-note dates, empty-note messaging, and safe local images.
    • Hover previews are passive and unavailable on touch editor surfaces.
  • Bug Fixes
    • Improved wiki-link resolution to distinguish missing, ambiguous, and temporarily unavailable notes.
    • Prevented duplicate note creation when an existing note cannot currently be read.
    • Improved handling of daily-note links and index synchronization.
    • Restricted preview image requests to supported raster formats for safer rendering.
  • Documentation
    • Updated editor architecture and porting documentation to reflect hover preview support.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds side-effect-free wiki-target resolution with explicit unavailable outcomes, desktop wiki-link hover previews, passive markdown rendering, raster-only preview asset serving, and related tests and documentation.

Changes

Wiki-link hover previews and target resolution

Layer / File(s) Summary
Existing target resolution and creation delegation
packages/core/src/graph/resolve-existing-wiki-target.ts, packages/core/src/graph/create-note.ts, packages/core/src/actions/backlink-target.ts, packages/core/src/exports/platform.ts, packages/core/src/graph/*test.ts, packages/core/src/actions/*test.ts
Existing targets are resolved through indexed, daily, and bounded disk checks with resolved, ambiguous, unavailable, and missing outcomes; note creation and backlink capture preserve unavailable targets.
Navigation and creation outcome handling
apps/desktop/src/editor/use-wiki-link-navigation.ts, apps/desktop/src/editor/use-wiki-link-navigation.test.tsx, apps/desktop/src/editor/use-editor-autocomplete.ts, apps/desktop/src/editor/use-editor-autocomplete.test.tsx
Navigation and autocomplete distinguish unavailable targets from ambiguous and missing targets, including date-link handling and operation failures.
Passive desktop hover preview rendering
apps/desktop/src/editor/use-wiki-link-hover-preview.tsx, apps/desktop/src/editor/wiki-link-hover-preview.tsx, apps/desktop/src/editor/markdown-preview.tsx, apps/desktop/src/editor/note-editor.tsx, apps/desktop/src/components/note-pane.tsx, apps/desktop/src/lib/read-existing-note-source.ts, apps/desktop/src/editor/*test.tsx, apps/desktop/src/components/route-content.test.tsx, apps/desktop/src/lib/read-existing-note-source.test.ts, docs/contributing/editor-architecture.md, docs/porting/backlink-hover-previews.md
The desktop note editor mounts a conditional hover-card renderer that resolves and reads existing notes, renders passive markdown or empty daily-note content, and is disabled on touch surfaces.
Raster-only preview asset serving
apps/desktop/src-tauri/src/fs/asset_protocol.rs
Asset requests with reflect-preview=raster are limited to responses sniffed as PNG, JPEG, GIF, or WebP.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 51.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main user-facing addition: backlink hover previews for desktop wiki links.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wikilink-hover-preview-2

Comment @coderabbitai help to get the list of available commands.

@ocavue
ocavue requested a review from Copilot July 12, 2026 13:53
@ocavue
ocavue marked this pull request as ready for review July 12, 2026 13:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds passive, local-only hover previews for [[wiki links]] in pointer-capable desktop note panes, while tightening “existing target” resolution so iCloud placeholders or transient read failures are treated as unavailable (not “missing”) to prevent duplicate-note creation and incorrect navigation.

Changes:

  • Introduces resolveExistingWikiTarget (resolved / ambiguous / unavailable / missing) and reuses it across creation, navigation, and capture-related flows.
  • Wires Meowdown’s WikilinkHoverCard into the desktop editor with a passive preview body renderer backed by generation-pinned reads and frontmatter-stripped markdown.
  • Restricts hover-preview asset loading to sniffed raster-only responses via ?reflect-preview=raster enforcement in the Tauri asset protocol, and makes Markdown previews optionally non-interactive.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/core/src/graph/resolve-existing-wiki-target.ts Adds side-effect-free resolver for existing wiki-link targets with bounded disk fallback and “unavailable” outcome.
packages/core/src/graph/resolve-existing-wiki-target.test.ts Comprehensive unit tests for resolver precedence, disk fallback, and unavailable handling.
packages/core/src/graph/create-note.ts Refactors create-guard logic to delegate to resolveExistingWikiTarget, adding unavailable to outcomes.
packages/core/src/graph/create-note.test.ts Updates/extends tests to cover daily outranking and unavailable blocking note creation.
packages/core/src/exports/platform.ts Exports the new resolver and its result type from @reflect/core.
packages/core/src/actions/backlink-target.ts Treats unavailable resolutions as non-blocking for capture/backlinks (keeps requested spelling).
packages/core/src/actions/backlink-target.test.ts Adds test coverage for unavailable backlink target behavior.
docs/porting/README.md Marks backlink hover previews as ported.
docs/porting/backlink-hover-previews.md Updates doc from planned → implemented; records UX and architecture decisions.
docs/contributing/editor-architecture.md Documents the new hover-preview hook and read helper in editor architecture overview.
apps/desktop/src/lib/read-existing-note-source.ts Adds helper to read from live open-session buffer when safe, else generation-pinned disk read.
apps/desktop/src/lib/read-existing-note-source.test.ts Tests for live-buffer vs disk fallback, including stale-buffer refusal.
apps/desktop/src/editor/use-wiki-link-navigation.ts Uses resolveExistingWikiTarget for ISO date navigation when generation is available; surfaces unavailable distinctly.
apps/desktop/src/editor/use-wiki-link-navigation.test.tsx Updates tests to cover new ISO-date resolution behavior and unavailable messaging.
apps/desktop/src/editor/use-wiki-link-hover-preview.tsx Implements Meowdown hover-card body resolver (passive, frontmatter-free, local raster-only assets).
apps/desktop/src/editor/use-wiki-link-hover-preview.test.tsx Tests hover preview resolver behavior, inert rendering, and raster-only asset URL shaping.
apps/desktop/src/editor/use-editor-autocomplete.ts Adds distinct unavailable handling for background create from [[ autocomplete.
apps/desktop/src/editor/use-editor-autocomplete.test.tsx Tests unavailable reporting path for autocomplete create.
apps/desktop/src/editor/note-editor.tsx Adds optional renderWikilinkHoverCard prop and mounts WikilinkHoverCard when provided.
apps/desktop/src/editor/note-editor.test.tsx Verifies hover card mounts only when a renderer is provided and passes the renderer through.
apps/desktop/src/editor/markdown-preview.tsx Adds interactive flag to support passive/inert markdown rendering.
apps/desktop/src/components/wiki-link-hover-preview.tsx Adds the passive hover preview body component (daily header + inert markdown / empty state).
apps/desktop/src/components/route-content.test.tsx Ensures hover renderer is enabled on pointer surfaces and omitted on touch editor surface.
apps/desktop/src/components/note-pane.tsx Wires hover preview renderer into primary note pane only when non-touch and graph session exists.
apps/desktop/src-tauri/src/fs/asset_protocol.rs Enforces raster-only MIME allowlist when reflect-preview=raster query is present; adds tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/desktop/src/editor/use-editor-autocomplete.ts (1)

58-68: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract a shared unavailable-note helper

The unavailable create message duplicates the opening-link wording in use-wiki-link-navigation.ts; a shared reportUnavailableNoteTitle(operationLabel, title) helper next to reportAmbiguousNoteTitle would keep the copy aligned and avoid drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/editor/use-editor-autocomplete.ts` around lines 58 - 68,
Extract a shared reportUnavailableNoteTitle(operationLabel, title) helper
alongside reportAmbiguousNoteTitle, and update resolveOrCreateFromAutocomplete
to use it for the unavailable outcome. Reuse the helper in
use-wiki-link-navigation.ts so opening-link and autocomplete flows share
identical unavailable-note messaging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/graph/resolve-existing-wiki-target.ts`:
- Around line 174-190: The indexedResolution function returns date, title, and
alias index matches without validating note availability. Route indexed paths
through the existing readNote/placeholder availability check used by
dailyFileResolution and matchTitleOnDisk, preserving null for unreadable or
evicted notes before constructing the resolution.

---

Nitpick comments:
In `@apps/desktop/src/editor/use-editor-autocomplete.ts`:
- Around line 58-68: Extract a shared reportUnavailableNoteTitle(operationLabel,
title) helper alongside reportAmbiguousNoteTitle, and update
resolveOrCreateFromAutocomplete to use it for the unavailable outcome. Reuse the
helper in use-wiki-link-navigation.ts so opening-link and autocomplete flows
share identical unavailable-note messaging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 069274ba-10e6-4fee-b7dc-e50d1cfa26fc

📥 Commits

Reviewing files that changed from the base of the PR and between a2edb38 and 5cd7580.

📒 Files selected for processing (25)
  • apps/desktop/src-tauri/src/fs/asset_protocol.rs
  • apps/desktop/src/components/note-pane.tsx
  • apps/desktop/src/components/route-content.test.tsx
  • apps/desktop/src/components/wiki-link-hover-preview.tsx
  • apps/desktop/src/editor/markdown-preview.tsx
  • apps/desktop/src/editor/note-editor.test.tsx
  • apps/desktop/src/editor/note-editor.tsx
  • apps/desktop/src/editor/use-editor-autocomplete.test.tsx
  • apps/desktop/src/editor/use-editor-autocomplete.ts
  • apps/desktop/src/editor/use-wiki-link-hover-preview.test.tsx
  • apps/desktop/src/editor/use-wiki-link-hover-preview.tsx
  • apps/desktop/src/editor/use-wiki-link-navigation.test.tsx
  • apps/desktop/src/editor/use-wiki-link-navigation.ts
  • apps/desktop/src/lib/read-existing-note-source.test.ts
  • apps/desktop/src/lib/read-existing-note-source.ts
  • docs/contributing/editor-architecture.md
  • docs/porting/README.md
  • docs/porting/backlink-hover-previews.md
  • packages/core/src/actions/backlink-target.test.ts
  • packages/core/src/actions/backlink-target.ts
  • packages/core/src/exports/platform.ts
  • packages/core/src/graph/create-note.test.ts
  • packages/core/src/graph/create-note.ts
  • packages/core/src/graph/resolve-existing-wiki-target.test.ts
  • packages/core/src/graph/resolve-existing-wiki-target.ts

Comment on lines +174 to +190
async function indexedResolution(
match: ExactWikiTargetMatch,
date: string | undefined,
generation: number,
listNoteFiles: ListNoteFiles,
): Promise<ExistingMatchResolution | null> {
if (match.kind === 'date') {
return resolutionForPaths(match.paths)
}
if (date !== undefined) {
const daily = await dailyFileResolution(date, generation, listNoteFiles)
if (daily !== null) {
return daily
}
}
return match.kind === 'missing' ? null : resolutionForPaths(match.paths)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect how indexed matches are produced, and whether placeholder/evicted
# files can appear as indexed title/alias/date matches.
fd -t f 'queries.ts' packages/core/src/indexing
ast-grep outline packages/core/src/indexing/queries.ts --items all --match 'findExactWikiTargetMatches'
rg -n -B3 -A40 'function findExactWikiTargetMatches' packages/core/src/indexing/queries.ts
rg -n 'placeholder' packages/core/src -A3 -B3

Repository: team-reflect/reflect-open

Length of output: 30254


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- resolve-existing-wiki-target.ts ---'
sed -n '1,280p' packages/core/src/graph/resolve-existing-wiki-target.ts

echo
echo '--- indexer.ts (placeholder handling) ---'
sed -n '300,350p' packages/core/src/indexing/indexer.ts

echo
echo '--- resolve-existing-wiki-target.test.ts around the indexed/unavailable cases ---'
sed -n '180,280p' packages/core/src/graph/resolve-existing-wiki-target.test.ts

Repository: team-reflect/reflect-open

Length of output: 13165


Check readability before returning indexed matches
indexedResolution returns indexed date/title/alias hits without the readNote/placeholder gate that dailyFileResolution and matchTitleOnDisk apply. A stale index row can therefore report resolved for an evicted or otherwise unreadable note. Route indexed hits through the same availability check before returning.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/graph/resolve-existing-wiki-target.ts` around lines 174 -
190, The indexedResolution function returns date, title, and alias index matches
without validating note availability. Route indexed paths through the existing
readNote/placeholder availability check used by dailyFileResolution and
matchTitleOnDisk, preserving null for unreadable or evicted notes before
constructing the resolution.

@ocavue ocavue changed the title feat: add wiki-link hover previews feat: add backlink hover previews Jul 12, 2026
@ocavue
ocavue merged commit 16c8b4f into next Jul 12, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants