Skip to content

feat(composer): add per-link preview controls - #4258

Draft
tellaho wants to merge 1 commit into
tho/link-preview-rich-settingfrom
tho/per-link-preview-controls
Draft

feat(composer): add per-link preview controls#4258
tellaho wants to merge 1 commit into
tho/link-preview-rich-settingfrom
tho/per-link-preview-controls

Conversation

@tellaho

@tellaho tellaho commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Category: new-feature
User Impact: Authors can review and remove individual link previews before sending while keeping the links in their message.

Problem: Link previews only appeared after send, and authors could only remove every preview at once. Solution: Resolve previews inside new and edit composers, persist canonical per-URL suppression through drafts and events, and apply the same controls across optimistic, timeline, and forum rendering without blocking Send.

File changes

desktop/src-tauri/src/commands/messages.rs
Accept and validate per-link suppression on sends and edits.

desktop/src-tauri/src/events.rs, desktop/src-tauri/src/link_preview_tags.rs
Build canonical suppression tags into message and edit events behind a strict HTTPS-only validator.

desktop/src-tauri/src/egress_guard_tests.rs, desktop/src-tauri/src/huddle/pipeline.rs, desktop/src-tauri/src/lib.rs
Wire the new builder argument through existing Rust callers and register the validator module.

desktop/src/features/channels/ui/ChannelPane.types.ts, desktop/src/features/channels/ui/ChannelScreen.tsx, desktop/src/features/channels/useChannelPaneHandlers.ts
Seed edit composers from effective event suppression and pass controls through send/edit handlers.

desktop/src/features/messages/hooks.ts, desktop/src/features/messages/ui/useMentionSendFlow.ts
Carry suppression through normal, mention-confirmed, optimistic, REST, and edit paths.

desktop/src/features/messages/lib/applyEditTagOverlay.mjs, desktop/src/features/messages/lib/applyEditTagOverlay.test.mjs, desktop/src/features/messages/lib/formatTimelineMessages.ts
Overlay URL-specific edit controls deterministically while preserving blanket suppression compatibility.

desktop/src/features/messages/lib/imetaMediaMarkdown.ts, desktop/src/features/messages/lib/imetaMediaMarkdown.test.mjs
Split preview-control tags from media, emoji, and mention tags for validated relay submission.

desktop/src/features/messages/lib/useDrafts.ts, desktop/src/features/messages/ui/useDraftPersistSnapshot.ts
Persist and restore per-draft suppression with backward-compatible migration.

desktop/src/features/messages/ui/MessageComposer.tsx, desktop/src/features/messages/ui/MessageComposer.types.ts, desktop/src/features/messages/ui/useComposerLinkPreviews.tsx
Render non-blocking previews before send and restore suppression correctly across draft and edit transitions.

desktop/src/features/messages/ui/MessageRow.tsx, desktop/src/shared/ui/link-preview-list.tsx, desktop/src/shared/ui/markdown.tsx, desktop/src/shared/ui/markdown/types.ts, desktop/src/shared/ui/markdownUtils.ts
Reuse existing preview cards for per-item removal and filter suppressed canonical URLs on rendered messages.

desktop/src/shared/api/editMessage.ts, desktop/src/shared/api/tauri.ts
Expose suppression fields through the desktop bridge.

desktop/src/shared/lib/linkPreviewSuppression.mjs, desktop/src/shared/lib/linkPreviewSuppression.d.mts, desktop/src/shared/lib/linkPreviewSuppression.test.mjs
Normalize fragments, deduplicate URLs, parse legacy controls, and build deterministic tags.

desktop/tests/e2e/messaging.spec.ts
Cover composer preview deduplication, canonical removal, retained text, and Compact/Rich display.

Reproduction steps

  1. Start the desktop app and open a channel composer.
  2. Paste two supported links, including a duplicate with a fragment; verify each canonical URL gets one preview before send.
  3. Remove one preview and verify its link text remains while only that canonical preview disappears.
  4. Switch channels and return, then send; verify the suppression survives the draft and sent message.
  5. Edit the message, remove or change another preview, save, and verify recipients render the same result.

Validation

  • pnpm check
  • Desktop unit suite: 3,928 passed
  • cargo test --workspace: 2,105 passed, 14 ignored
  • cargo clippy --all-targets -- -D warnings
  • Full messaging.spec.ts: 41 passed

Screenshots

Compact

Composer showing two canonical link previews before send

Rich after removing one preview

Composer retaining link text after one canonical preview is removed

Co-authored-by: Taylor Ho <taylorkmho@gmail.com>
Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
@tellaho
tellaho force-pushed the tho/per-link-preview-controls branch from 62e051f to 3f21a71 Compare August 2, 2026 05:34
@iroiro147

Copy link
Copy Markdown

Re-validated the branch end-to-end against current main:

  • npx tsc --noEmit (desktop/): clean
  • Webview test suite (node --import ./test-loader.mjs --experimental-strip-types --test "src/**/*.test.mjs"): 3928 / 3928 passing (13.3s; up from the project-wide baseline of 3906 — the delta is the new linkPreviewSuppression unit tests added here)
  • cargo check --lib (desktop/src-tauri): clean (17s)
  • cargo clippy --lib: zero warnings
  • cargo test --lib (desktop/src-tauri): 2102 / 2102 passing (14 ignored, as documented — production KDF etc.)

Every gate listed in the PR's own validation block passes on this checkout. No further changes needed from my side — ready for review.

Attempted to flip the PR from draft → ready-for-review but MarkPullRequestReadyForReview is permission-gated for fork authors; leaving this comment as the readiness signal instead.

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