Skip to content

[_]: feat/add inline image handling and styling for email content#75

Open
jzunigax2 wants to merge 1 commit into
masterfrom
fix/preview-pane-fixes
Open

[_]: feat/add inline image handling and styling for email content#75
jzunigax2 wants to merge 1 commit into
masterfrom
fix/preview-pane-fixes

Conversation

@jzunigax2

Copy link
Copy Markdown
Contributor
  • Introduced a new constant for maximum inline image size.
  • Enhanced the email composition editor to handle image drops with size validation.
  • Updated CSS styles for rendered email content to ensure proper formatting of headings, lists, and links.
  • Added localization support for inline image size error messages in multiple languages.

- Introduced a new constant for maximum inline image size.
- Enhanced the email composition editor to handle image drops with size validation.
- Updated CSS styles for rendered email content to ensure proper formatting of headings, lists, and links.
- Added localization support for inline image size error messages in multiple languages.
@jzunigax2
jzunigax2 requested a review from xabg2 as a code owner July 16, 2026 21:00
@jzunigax2 jzunigax2 added the bug Something isn't working label Jul 16, 2026
@jzunigax2 jzunigax2 self-assigned this Jul 16, 2026
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds size-limited inline image drag-and-drop handling with localized warnings, and updates rendered mail previews with dedicated typography and responsive image styling.

Changes

Inline image drop handling

Layer / File(s) Summary
Inline image limit and editor drop handler
src/constants.ts, src/components/compose-message/config.ts
Defines a 5 MiB inline image limit and inserts accepted dropped images into the editor while warning about oversized files.
Oversized inline image messages
src/i18n/locales/en.json, src/i18n/locales/es.json, src/i18n/locales/fr.json, src/i18n/locales/it.json
Adds localized inlineImageTooLarge messages using the configured maximum size.

Mail preview styling

Layer / File(s) Summary
Rendered mail body presentation
src/features/mail/components/mail-preview/preview/index.tsx, src/index.css
Applies the mail-content wrapper class and styles headings, paragraphs, lists, links, and responsive images.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: xabg2, xabg2

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and describes the main change: inline image handling and email-content styling.
Description check ✅ Passed The description matches the PR changes, covering image limits, editor drops, styling, and localization.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ 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 fix/preview-pane-fixes

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Biome (2.5.3)
src/index.css

File contains syntax errors that prevent linting: Line 4: Tailwind-specific syntax is disabled.; Line 5: Tailwind-specific syntax is disabled.; Line 6: Tailwind-specific syntax is disabled.; Line 14: Tailwind-specific syntax is disabled.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@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.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 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 `@src/components/compose-message/config.ts`:
- Around line 115-124: Update the image insertion flow around the images.forEach
FileReader callbacks to await all image reads before dispatching. Preserve the
original image order, create all image nodes, then insert them in one
transaction at a position clamped to the current document’s valid limits instead
of reusing the stale pos for separate dispatches.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 480e0bf2-4c16-4c79-9497-068b5ed9e107

📥 Commits

Reviewing files that changed from the base of the PR and between 8dec3d1 and f454e00.

📒 Files selected for processing (8)
  • src/components/compose-message/config.ts
  • src/constants.ts
  • src/features/mail/components/mail-preview/preview/index.tsx
  • src/i18n/locales/en.json
  • src/i18n/locales/es.json
  • src/i18n/locales/fr.json
  • src/i18n/locales/it.json
  • src/index.css

Comment on lines +115 to +124
images.forEach((file) => {
const reader = new FileReader();
reader.onload = () => {
if (typeof reader.result !== 'string') return;
const node = view.state.schema.nodes.image.create({ src: reader.result });
view.dispatch(view.state.tr.insert(pos, node));
};
reader.readAsDataURL(file);
});
return true;

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

Group image insertions to prevent out-of-order rendering and out-of-bounds crashes.

When multiple images are dropped, reading them asynchronously and inserting them at the exact same static pos causes them to be rendered in reverse order (each insertion pushes the previous one to the right). Furthermore, if the user modifies the document during the async read, pos may become invalid, leading to a ProseMirror RangeError.

Wait for all images to be read, and insert them in a single transaction while clamping the position to the current document limits.

🐛 Proposed fix to handle async insertion
-      images.forEach((file) => {
-        const reader = new FileReader();
-        reader.onload = () => {
-          if (typeof reader.result !== 'string') return;
-          const node = view.state.schema.nodes.image.create({ src: reader.result });
-          view.dispatch(view.state.tr.insert(pos, node));
-        };
-        reader.readAsDataURL(file);
-      });
+      if (images.length > 0) {
+        Promise.all(
+          images.map(
+            (file) =>
+              new Promise<string>((resolve) => {
+                const reader = new FileReader();
+                reader.onload = () => resolve(reader.result as string);
+                reader.readAsDataURL(file);
+              })
+          )
+        ).then((results) => {
+          const nodes = results.map((src) =>
+            view.state.schema.nodes.image.create({ src })
+          );
+          
+          // Protect against document mutations invalidating the original pos
+          const maxPos = view.state.doc.content.size;
+          const validPos = pos > maxPos ? maxPos : pos;
+          
+          view.dispatch(view.state.tr.insert(validPos, nodes));
+        });
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
images.forEach((file) => {
const reader = new FileReader();
reader.onload = () => {
if (typeof reader.result !== 'string') return;
const node = view.state.schema.nodes.image.create({ src: reader.result });
view.dispatch(view.state.tr.insert(pos, node));
};
reader.readAsDataURL(file);
});
return true;
if (images.length > 0) {
Promise.all(
images.map(
(file) =>
new Promise<string>((resolve) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result as string);
reader.readAsDataURL(file);
})
)
).then((results) => {
const nodes = results.map((src) =>
view.state.schema.nodes.image.create({ src })
);
// Protect against document mutations invalidating the original pos
const maxPos = view.state.doc.content.size;
const validPos = pos > maxPos ? maxPos : pos;
view.dispatch(view.state.tr.insert(validPos, nodes));
});
}
return true;
🤖 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 `@src/components/compose-message/config.ts` around lines 115 - 124, Update the
image insertion flow around the images.forEach FileReader callbacks to await all
image reads before dispatching. Preserve the original image order, create all
image nodes, then insert them in one transaction at a position clamped to the
current document’s valid limits instead of reusing the stale pos for separate
dispatches.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant