Skip to content

feat: Added-pdf-preview-feature#38674

Open
KumarHarshit3603 wants to merge 5 commits intoRocketChat:developfrom
KumarHarshit3603:pdf-preivew
Open

feat: Added-pdf-preview-feature#38674
KumarHarshit3603 wants to merge 5 commits intoRocketChat:developfrom
KumarHarshit3603:pdf-preivew

Conversation

@KumarHarshit3603
Copy link

@KumarHarshit3603 KumarHarshit3603 commented Feb 14, 2026

Proposed changes (including videos or screenshots)

  • Add PdfPreviewModal that embeds PDFs inside a Fuselage modal via iframe, with download and “open in app” controls.
  • Update GenericFileAttachment to open the modal on PDF clicks while preserving decrypt/download flows and desktop viewer support.
  • Pure client-side change; no server impact.

Issue(s)

  • n/a (feature request: inline PDF preview popup)

Steps to test or reproduce

  1. Send or receive a message with a PDF attachment.
  2. Click the attachment title; a modal should open with the PDF rendered inline.
  3. Click “Download” to save the file when permitted.
  4. In desktop app, “Open” should launch the native viewer if openDocumentViewer is available.
  5. Encrypted (/file-decrypt/) links still trigger the registered download flow.

Further comments

  • Could add loading/error states in the modal if PDF loading reliability becomes an issue.
14.02.2026_06.18.01_REC.mp4

Summary by CodeRabbit

  • New Features
    • PDF attachments open in a modal preview with an embedded viewer, title, and close control.
    • Modal shows Download and "Open in app" actions when available.
  • Refactor
    • Title-click behavior refined: encrypted/special links trigger direct download; PDFs use inline modal preview or in-app viewer.
    • External download URLs now better support preview/open flows.

@KumarHarshit3603 KumarHarshit3603 requested a review from a team as a code owner February 14, 2026 00:54
@changeset-bot
Copy link

changeset-bot bot commented Feb 14, 2026

⚠️ No Changeset found

Latest commit: 1ba17ad

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Feb 14, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 14, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a modal-based PDF preview flow: introduces PdfPreviewModal and updates GenericFileAttachment to open that modal for PDFs (with preview, download, and open-in-app actions) while preserving direct-download behavior for /file-decrypt/ links.

Changes

Cohort / File(s) Summary
PDF preview component
apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
New React modal component that renders a PDF in an iframe and exposes Close plus optional Download and Open-in-App actions via props (title, url, downloadUrl, onClose, onOpenInApp).
Attachment click handling / modal integration
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
Adds useSetModal usage to open PdfPreviewModal for PDFs; constructs inline content-disposition preview URLs, computes optional download URL, preserves direct-download flow for /file-decrypt/ links and wires onOpenInApp behavior.

Sequence Diagram

sequenceDiagram
    actor User
    participant Attachment as GenericFileAttachment
    participant ModalSvc as useSetModal
    participant PdfModal as PdfPreviewModal
    participant Desktop as DesktopViewer

    User->>Attachment: Click file title
    alt file-decrypt link
        Attachment->>User: register UID & trigger download (forAttachmentDownload)
    else PDF
        Attachment->>Attachment: build previewUrl & downloadUrl
        Attachment->>ModalSvc: setModal(PdfPreviewModal{title,url,downloadUrl,onClose,onOpenInApp})
        ModalSvc->>PdfModal: render with props
        PdfModal->>User: display iframe (url)
        User->>PdfModal: Click action
        alt Close
            PdfModal->>ModalSvc: onClose -> clear modal
        else Download
            PdfModal->>User: navigate to downloadUrl
        else Open in App
            PdfModal->>Desktop: request openDocumentViewer(downloadUrl or url)
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

type: feature

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: Added-pdf-preview-feature' clearly describes the main change (adding a PDF preview feature), which aligns with the PR objectives of adding PdfPreviewModal and updating GenericFileAttachment for PDF preview functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In
`@apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx`:
- Around line 63-65: The modal remains visible after launching the desktop
viewer because openInApp (defined where openDocumentViewer is wrapped) only
calls openDocumentViewer; update that wrapper so after calling
openDocumentViewer(previewUrl.toString(), format, '') it also dismisses the
attachment modal by invoking the component's close handler (e.g., onClose,
dismissModal, or the prop that toggles the modal visibility) — ensure you check
that the close handler exists before calling and preserve error handling (call
close after successful launch or in a finally block) so the modal is always
closed when opening in the external viewer.

In
`@apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx`:
- Line 30: The component PdfPreviewModal uses raw English fallbacks ('PDF' and
'PDF preview') for ModalTitle (and the subtitle/label on line 34), which
bypasses i18n; replace those hardcoded fallbacks by passing them through the
translation function (t) so the fallback becomes t('PDF') and t('PDF preview')
(or their existing translation keys) when title or the subtitle prop is absent,
updating usages in PdfPreviewModal (ModalTitle and the subtitle element) to call
t(...) instead of raw strings.
- Line 34: PdfPreviewModal renders a user-uploaded URL in an iframe without
sandboxing; add a restrictive sandbox attribute on the iframe element in
PdfPreviewModal (the line with <iframe src={url} ... />) to limit
capabilities—use a minimal set of allowances required for your PDF renderer (for
example include only "allow-scripts allow-same-origin" if the viewer needs them,
or an empty sandbox if not) so the embedded document cannot perform navigation
or broader scripting actions.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 11e1c51 and 74e94ed.

📒 Files selected for processing (2)
  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
🔇 Additional comments (2)
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx (2)

57-58: getURL(link) returns a full absolute URL; the code is correct.

When useMediaUrl() is called, it provides getURL from AttachmentProvider, which wraps the utility function with { full: true }. This option makes getURL return a full absolute URL (e.g., https://host.com/path/to/file) by concatenating the Site_Url setting with the relative path. The new URL(absoluteUrl, base) constructor ignores the base argument when given an absolute URL, so this pattern works as intended.


54-54: Use format?.toLowerCase() === 'pdf' instead of case-sensitive 'PDF' check.

Sharp's metadata().format returns lowercase format names. Since PDFs arrive as format: 'pdf', the current case-sensitive check format === 'PDF' will never match, preventing the PDF preview modal from opening.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx`:
- Line 34: The iframe in PdfPreviewModal currently sets
sandbox='allow-same-origin' which prevents native PDF rendering; remove the
sandbox attribute from the iframe element (<iframe src={url} style={iframeStyle}
title={title || t('PDF_preview')} />) to restore browser PDF viewers, or
alternatively replace the iframe approach with a JS-based renderer such as
PDF.js inside PdfPreviewModal if sandboxing must be preserved.
🧹 Nitpick comments (2)
apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx (2)

14-20: Consider adding aria-label or accessible description to the modal for screen readers.

The modal's accessibility relies on ModalTitle for labeling. This is acceptable if Fuselage's Modal component automatically associates the title via aria-labelledby. No action needed if that's the case, but worth confirming.


38-41: Download button does not specify a filename in the download attribute.

The download boolean attribute will let the browser pick the filename from the URL, which may be an opaque ID rather than the original filename. Passing title would preserve the original name.

Proposed fix
-						<Button is='a' href={downloadUrl} download secondary>
+						<Button is='a' href={downloadUrl} download={title || true} secondary>
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 74e94ed and cc299ec.

📒 Files selected for processing (2)
  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
🧬 Code graph analysis (2)
apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • useTranslation (81-81)
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx (2)
packages/ui-contexts/src/index.ts (1)
  • useSetModal (71-71)
packages/message-parser/src/utils.ts (1)
  • link (77-80)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (3)
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx (3)

46-52: Encrypted PDF links skip the preview modal — confirm this is intentional.

The /file-decrypt/ check (line 46) precedes the format === 'PDF' check (line 54), so encrypted PDFs bypass the preview and go straight to the download flow. If preview of decrypted PDFs is desired in the future, this ordering would need adjustment. Just flagging for awareness; the current behavior matches the PR objectives.


9-9: Modal integration looks well-structured.

The wiring of useSetModal, PdfPreviewModal, and the close/open-in-app handlers is clean. The previously flagged issue (modal not closing on "Open in app") is addressed in the openInApp callback (lines 64-67). The lifecycle management via setModal(null) is correct.

Also applies to: 20-20, 37-37, 62-78


57-58: The server properly handles the contentDisposition query parameter. The implementation in apps/meteor/app/file-upload/server/config/helper.ts explicitly checks for query.contentDisposition === 'inline' and returns the corresponding disposition. The fallback to 'attachment' is intentional. No action required.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx`:
- Around line 38-41: The download link in PdfPreviewModal (the <Button is='a'
href={downloadUrl} download ... />) can point to a cross-origin URL returned by
GenericFileAttachment.getExternalUrl/getURL when openDocumentViewer is
unavailable, which makes the download attribute ignored; update the logic that
produces downloadUrl (or getExternalUrl/getURL call path) to ensure same-origin
URLs by wrapping external hrefs with new URL(href, window.location.origin)
before assigning to download, and for truly cross-origin resources implement a
programmatic fallback: fetch the resource, create a blob/object URL and set that
as the download href (or trigger download) so clicking the Button triggers a
download instead of navigation; reference getExternalUrl, getURL,
openDocumentViewer, and PdfPreviewModal/Button when making the change.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc299ec and 08ae343.

📒 Files selected for processing (1)
  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx
🧬 Code graph analysis (1)
apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx (1)
packages/ui-contexts/src/index.ts (1)
  • useTranslation (81-81)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (2)
apps/meteor/client/components/message/content/attachments/file/PdfPreviewModal.tsx (2)

1-22: Imports, types, and style constant look good.

Clean setup with proper typing and no unnecessary dependencies.


24-54: Component is well-structured overall.

The modal layout, conditional rendering of footer buttons, and i18n usage are all clean. The past review items (sandbox removal, i18n fallbacks) have been addressed.

One small note: there is no loading or error state for the iframe. The PR description acknowledges this as a possible future enhancement, which seems reasonable for an initial implementation.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@ggazzo ggazzo added the valid A valid contribution where maintainers will review based on priority label Feb 25, 2026
@coderabbitai coderabbitai bot added the type: feature Pull requests that introduces new feature label Feb 28, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx (1)

84-96: Remove duplicate code in getExternalUrl.

Both branches of the if (openDocumentViewer) conditional perform identical operations. The check is redundant.

♻️ Proposed simplification
 	const getExternalUrl = () => {
 		if (!hasDownload || !link) return undefined;
 
-		if (openDocumentViewer) {
-			const url = new URL(getURL(link), window.location.origin);
-			url.searchParams.set('download', '');
-			return url.toString();
-		}
-
 		const url = new URL(getURL(link), window.location.origin);
 		url.searchParams.set('download', '');
 		return url.toString();
 	};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx`
around lines 84 - 96, The getExternalUrl function contains a redundant if
(openDocumentViewer) branch that duplicates the same URL construction and
download param logic; simplify by removing the conditional and always return the
constructed URL when hasDownload and link are truthy. Update getExternalUrl
(referencing hasDownload, link, openDocumentViewer, and getURL) to early-return
undefined if !hasDownload || !link, then create the URL from getURL(link), set
searchParams 'download', and return url.toString().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx`:
- Around line 84-96: The getExternalUrl function contains a redundant if
(openDocumentViewer) branch that duplicates the same URL construction and
download param logic; simplify by removing the conditional and always return the
constructed URL when hasDownload and link are truthy. Update getExternalUrl
(referencing hasDownload, link, openDocumentViewer, and getURL) to early-return
undefined if !hasDownload || !link, then create the URL from getURL(link), set
searchParams 'download', and return url.toString().

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ffd4cf and 1ba17ad.

📒 Files selected for processing (1)
  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx
🔇 Additional comments (3)
apps/meteor/client/components/message/content/attachments/file/GenericFileAttachment.tsx (3)

9-9: LGTM!

New imports for useSetModal and PdfPreviewModal are appropriate for the PDF preview modal feature.

Also applies to: 20-20


54-80: LGTM!

PDF preview flow is well-implemented:

  • Correctly prevents default event behavior
  • Constructs preview URL with contentDisposition=inline for iframe embedding
  • Conditionally provides download URL based on hasDownload
  • The openInApp handler now properly closes the modal after launching the native viewer (previous feedback addressed)

98-118: LGTM!

The JSX structure correctly integrates the handleTitleClick handler with the MessageGenericPreviewTitle component.

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

Labels

type: feature Pull requests that introduces new feature valid A valid contribution where maintainers will review based on priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants