Skip to content

fix: Non-editable link clicks opening duplicate tabs - #2667

Merged
matthewlipski merged 2 commits into
feat/inline-tiptap-linkfrom
non-editable-link-bug-new
Apr 23, 2026
Merged

fix: Non-editable link clicks opening duplicate tabs#2667
matthewlipski merged 2 commits into
feat/inline-tiptap-linkfrom
non-editable-link-bug-new

Conversation

@matthewlipski

Copy link
Copy Markdown
Collaborator

Summary

This PR fixes a bug causing the Link extension's click handler to also fire on links that were non-editable, causing duplicate tabs to open.

Closes#1040

Rationale

This is a bug.

Changes

  • Added CSS class and data-inline-content-type attribute to inline/rich-text links to differentiate them from links that may be rendered by e.g. custom blocks.
  • Made click handler in Link extension ignore links without those.

Impact

N/A

Testing

N/A, Needed?

Screenshots/Video

N/A

Checklist

  • Code follows the project's coding standards.
  • Unit tests covering the new feature have been added.
  • All existing tests pass.
  • The documentation has been updated to reflect the new feature

Additional Notes

N/A

@vercel

vercelBot commented Apr 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
blocknoteReadyReadyPreviewApr 22, 2026 1:17pm
blocknote-websiteReadyReadyPreviewApr 22, 2026 1:17pm

Request Review

@coderabbitai

coderabbitaiBot commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7d4ee0be-f376-4ab5-b93d-b122c34cecf1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch non-editable-link-bug-new

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

The link refactor changed the HTML representation of <a> tags by adding
classname="bn-inline-content-section" data-inline-content-type="link"
attributes. This changed the request bodies sent to LLM providers in tests,
which broke the MD5 hash-based MSW snapshot filenames. Additionally, the
test runtime now captures actual request headers (authorization,
content-type, etc.) instead of empty arrays, further changing the hashes.
57 snapshot files were migrated (56 via script + 1 manual fix):
- Old-hash files deleted, new-hash files created with the same valid
200 response bodies transplanted from the originals.
## How MSW Snapshot Hashing Works
Each test records HTTP requests via msw-snapshot. The snapshot filename
includes an MD5 hash computed from:
[method, url.origin, url.pathname, sorted(searchParams), sorted(headers), body]
See createRequestHash() in each test file (e.g. htmlBlocks.test.ts:22).
The hash function is toHashString() from msw-snapshot, which does:
crypto.createHash('md5').update(JSON.stringify(array), 'binary').digest('hex')
## How to Migrate Snapshots When Schema Changes
When a code change alters the HTML/content sent to LLM providers, the
request body changes, which changes the hash, which means snapshot files
won't be found by filename.
### Step 1: Run the tests to create duplicate snapshots
cd packages/xl-ai && npm run test
Tests with hash mismatches will try to fetch from real servers (which
will fail without API keys), creating NEW snapshot files with correct
hashes but 401 error responses alongside the OLD files with valid 200
responses. The validateTestEnvironment test will report duplicates.
### Step 2: Identify duplicate pairs
For each test directory under __msw_snapshots__/{provider}/{model}/,
look for snapshot pairs with the same test name prefix but different
hashes. The OLD file (valid 200 response, older mtime) needs its
response transplanted into the NEW file (401 error, newer mtime).
### Step 3: Transplant responses
For each duplicate pair:
1. Read the response body from the OLD file (status 200)
2. Write that response into the NEW file (replacing the 401 error)
3. Delete the OLD file
This can be scripted in Python:
import json, os, glob
from collections import defaultdict
base = 'packages/xl-ai/src/api/formats/html-blocks/__snapshots__'
files = glob.glob(f'{base}/**/*.json', recursive=True)
# Group by test name prefix (everything before the hash)
groups = defaultdict(list)
for f in files:
name = os.path.basename(f)
# Pattern: testname_N_hash.json
prefix = '_'.join(name.rsplit('_', 1)[:-1])
groups[prefix].append(f)
for prefix, paths in groups.items():
if len(paths) == 2:
# Identify old (200) vs new (401) by checking response status
for p in paths:
data = json.load(open(p))
if data['response']['status'] == 200:
old_file, old_data = p, data
else:
new_file = p
# Transplant response
new_data = json.load(open(new_file))
new_data['response'] = old_data['response']
json.dump(new_data, open(new_file, 'w'), indent=2)
os.remove(old_file)
### Step 4: Handle edge cases
Some tests may fail with 'TypeError: unusable' at Request.clone in
msw-snapshot. This happens when a snapshot hash changed but the test
crashes before creating a new file (no duplicate pair to migrate).
To fix these:
1. Add debug logging in createSnapshotPath to print the computed hash
2. Run the failing test to get the new hash
3. Rename the old snapshot file to use the new hash
4. Remove the debug logging
### Step 5: Verify
cd packages/xl-ai && npm run test
All tests should pass and the duplicate validation test should be green.

@nperez0111nperez0111 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good, I added the commit to fix up the snapshots

@pkg-pr-new

Copy link
Copy Markdown

Open in StackBlitz

@blocknote/ariakit

npm i https://pkg.pr.new/@blocknote/ariakit@2667

@blocknote/code-block

npm i https://pkg.pr.new/@blocknote/code-block@2667

@blocknote/core

npm i https://pkg.pr.new/@blocknote/core@2667

@blocknote/mantine

npm i https://pkg.pr.new/@blocknote/mantine@2667

@blocknote/react

npm i https://pkg.pr.new/@blocknote/react@2667

@blocknote/server-util

npm i https://pkg.pr.new/@blocknote/server-util@2667

@blocknote/shadcn

npm i https://pkg.pr.new/@blocknote/shadcn@2667

@blocknote/xl-ai

npm i https://pkg.pr.new/@blocknote/xl-ai@2667

@blocknote/xl-docx-exporter

npm i https://pkg.pr.new/@blocknote/xl-docx-exporter@2667

@blocknote/xl-email-exporter

npm i https://pkg.pr.new/@blocknote/xl-email-exporter@2667

@blocknote/xl-multi-column

npm i https://pkg.pr.new/@blocknote/xl-multi-column@2667

@blocknote/xl-odt-exporter

npm i https://pkg.pr.new/@blocknote/xl-odt-exporter@2667

@blocknote/xl-pdf-exporter

npm i https://pkg.pr.new/@blocknote/xl-pdf-exporter@2667

commit: 85a8320

@matthewlipski
matthewlipski merged commit 388d04c into feat/inline-tiptap-linkApr 23, 2026
14 checks passed
@matthewlipski
matthewlipski deleted the non-editable-link-bug-new branch April 23, 2026 08:14
nperez0111 added a commit that referenced this pull request Apr 24, 2026
* Fixed clicking non-editable links opening 2 new tabs instead of 1
* fix: migrate MSW snapshot hashes after schema change to link HTML
The link refactor changed the HTML representation of <a> tags by adding
classname="bn-inline-content-section" data-inline-content-type="link"
attributes. This changed the request bodies sent to LLM providers in tests,
which broke the MD5 hash-based MSW snapshot filenames. Additionally, the
test runtime now captures actual request headers (authorization,
content-type, etc.) instead of empty arrays, further changing the hashes.
57 snapshot files were migrated (56 via script + 1 manual fix):
- Old-hash files deleted, new-hash files created with the same valid
200 response bodies transplanted from the originals.
## How MSW Snapshot Hashing Works
Each test records HTTP requests via msw-snapshot. The snapshot filename
includes an MD5 hash computed from:
[method, url.origin, url.pathname, sorted(searchParams), sorted(headers), body]
See createRequestHash() in each test file (e.g. htmlBlocks.test.ts:22).
The hash function is toHashString() from msw-snapshot, which does:
crypto.createHash('md5').update(JSON.stringify(array), 'binary').digest('hex')
## How to Migrate Snapshots When Schema Changes
When a code change alters the HTML/content sent to LLM providers, the
request body changes, which changes the hash, which means snapshot files
won't be found by filename.
### Step 1: Run the tests to create duplicate snapshots
cd packages/xl-ai && npm run test
Tests with hash mismatches will try to fetch from real servers (which
will fail without API keys), creating NEW snapshot files with correct
hashes but 401 error responses alongside the OLD files with valid 200
responses. The validateTestEnvironment test will report duplicates.
### Step 2: Identify duplicate pairs
For each test directory under __msw_snapshots__/{provider}/{model}/,
look for snapshot pairs with the same test name prefix but different
hashes. The OLD file (valid 200 response, older mtime) needs its
response transplanted into the NEW file (401 error, newer mtime).
### Step 3: Transplant responses
For each duplicate pair:
1. Read the response body from the OLD file (status 200)
2. Write that response into the NEW file (replacing the 401 error)
3. Delete the OLD file
This can be scripted in Python:
import json, os, glob
from collections import defaultdict
base = 'packages/xl-ai/src/api/formats/html-blocks/__snapshots__'
files = glob.glob(f'{base}/**/*.json', recursive=True)
# Group by test name prefix (everything before the hash)
groups = defaultdict(list)
for f in files:
name = os.path.basename(f)
# Pattern: testname_N_hash.json
prefix = '_'.join(name.rsplit('_', 1)[:-1])
groups[prefix].append(f)
for prefix, paths in groups.items():
if len(paths) == 2:
# Identify old (200) vs new (401) by checking response status
for p in paths:
data = json.load(open(p))
if data['response']['status'] == 200:
old_file, old_data = p, data
else:
new_file = p
# Transplant response
new_data = json.load(open(new_file))
new_data['response'] = old_data['response']
json.dump(new_data, open(new_file, 'w'), indent=2)
os.remove(old_file)
### Step 4: Handle edge cases
Some tests may fail with 'TypeError: unusable' at Request.clone in
msw-snapshot. This happens when a snapshot hash changed but the test
crashes before creating a new file (no duplicate pair to migrate).
To fix these:
1. Add debug logging in createSnapshotPath to print the computed hash
2. Run the failing test to get the new hash
3. Rename the old snapshot file to use the new hash
4. Remove the debug logging
### Step 5: Verify
cd packages/xl-ai && npm run test
All tests should pass and the duplicate validation test should be green.
---------
Co-authored-by: Nick the Sick <computers@nickthesick.com>
Sign up for freeto 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

@matthewlipski@nperez0111