Skip to content

fix: work-package block exports as a real markdown link#134

Open
wielinde wants to merge 3 commits into
devfrom
fix/work-package-block-markdown-link
Open

fix: work-package block exports as a real markdown link#134
wielinde wants to merge 3 commits into
devfrom
fix/work-package-block-markdown-link

Conversation

@wielinde
Copy link
Copy Markdown
Member

@wielinde wielinde commented May 15, 2026

Precodition

BlockNote was bumped to >=0.0.51.

Summary

Fixes a regression where work-package block content was effectively lost when serialized for clipboard copy or hocuspocus's server-side description (markdown) export.

toExternalHTML used to return a plain <div data-...>#123</div>. The markdown serializer dropped it. Now we emit <a href=\"${linkToWorkPackage(wpid)}\" data-...>#123</a>, which markdown-serializes to a proper [#123](https://.../wp/123).

Details

  • lib/components/BlockWorkPackage/spec.tsx: replace <div> with <a href>; defensive skip for missing or non-positive wpid (avoids linkToWorkPackage throwing during export).
  • parse still inspects data-block-content-type regardless of tag, so paste-from-HTML round-trips unchanged.
  • New unit test (jsdom env) invokes spec.implementation.toExternalHTML(...) directly and asserts the rendered anchor's href / text / data-attrs.

Test plan

  • npm run test:unit — 35 tests pass (4 new)
  • npm run build — clean

Refs

wielinde and others added 3 commits May 15, 2026 16:26
…s a real link

Previously toExternalHTML returned a bare `<div data-...>#123</div>`. When
blocksToMarkdownLossy serialized it, the result was effectively empty (the
markdown serializer drops the data-only wrapper). For browser
copy-to-clipboard and the server-side description export in hocuspocus,
work-package blocks ended up as nothing — a regression.

Now toExternalHTML emits `<a href="${linkToWorkPackage(wpid)}" data-...>#123</a>`,
which serializes to `[#123](https://.../wp/123)` in markdown and renders as
a clickable link in any HTML target. The data-* attributes are preserved on
the anchor so the inverse `parse` continues to round-trip.

Defensive: skip rendering when wpid is missing or non-positive (matches the
guard in linkToWorkPackage, avoids the helper throwing during export).

Tested with a jsdom-backed unit test that invokes the spec's
implementation.toExternalHTML directly and asserts the anchor href / text.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Inline work-package chips (openProjectWorkPackageInline) had the same
markdown-conversion regression as the block variant: the bare
`<span data-...>#wpid</span>` was dropped by blocksToMarkdownLossy,
leaving the chip's id out of the saved description entirely.

Now toExternalHTML emits `<a href="${linkToWorkPackage(numericWpid)}" data-...>#wpid</a>`,
which serializes to `[#wpid](https://.../wp/wpid)` in markdown.

Defensive: keep skipping pending: placeholders; also require the wpid
parses to a positive number before calling linkToWorkPackage (the helper
throws on invalid ids).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Visible link text in the markdown export now mirrors the chip variant:

  xxs (tiny inline)              → "#106"     ([#106](url))
  xs  (compact inline)           → "##106"    ([##106](url))
  s   (regular inline)           → "###106"   ([###106](url))
  m / l / xl (block + preview)   → "###106"   ([###106](url))

A shared `hashesForSize(size)` helper lives next to the WpSize types
(lib/components/WorkPackage/types.ts) so both the block and inline
React specs use the same mapping.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@judithroth
Copy link
Copy Markdown
Contributor

Thanks, this will be really useful! I wanted to merge this today already but didn't have the time to properly look into it. I hope I get to it tomorrow 🙂

Copy link
Copy Markdown
Contributor

@judithroth judithroth left a comment

Choose a reason for hiding this comment

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

Thanks for this contribution!
However, this didn't work for me, copypaste of work package links still is empty:

Screencast.from.2026-05-26.09-32-22.webm

Could it be that this depends on the BlockNote update?
However, we also still need to make this support semantic IDs.

toExternalHTML: ({ block }) => {
const { wpid, size, initialized } = block.props;
if (!wpid) return <></>;
if (!wpid || wpid <= 0) return <></>;
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.

We have to make sure this also works with semantic IDs and will correctly use the semantic ID for the copy-paste content

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good point. Do we also have the semantic ID in a wp link block? We probably need first add it to the block's JSON. Then, our Markdown renderer needs to check if that semantic ID is there. If so, use it, else fall back to DB ID.

const { wpid, instanceId, size } = inlineContent.props;
if (!wpid || wpid.startsWith("pending:")) return <></>;
const numericWpid = Number(wpid);
if (!Number.isFinite(numericWpid) || numericWpid <= 0) return <></>;
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.

Same here, this should respect the semantic IDs

@wielinde
Copy link
Copy Markdown
Member Author

Thanks for this contribution! However, this didn't work for me, copypaste of work package links still is empty:

Screencast.from.2026-05-26.09-32-22.webm
Could it be that this depends on the BlockNote update? However, we also still need to make this support semantic IDs.

@judithroth Yes, copy and paste first needs to have the BlockNote bump. That is due to shadow dom fixes that the newer BlockNote brings.

@wielinde
Copy link
Copy Markdown
Member Author

@judithroth We probably want to prioritize BlockNote update over this fix here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants