Alternative broken multi line replace without execCommand#4214
Alternative broken multi line replace without execCommand#4214hoangdat merged 4 commits intofeatures/aifrom
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughThis change introduces utilities for improved text insertion in a web-based composer. A new JavaScript constant in Pre-merge checks and finishing touches✅ Passed checks (3 passed)
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. Comment |
|
This PR has been deployed to https://linagora.github.io/tmail-flutter/4214. |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart (1)
32-45: Consider adding error handling for async operations.The method is now async but lacks try-catch blocks around the JavaScript evaluation and HTML insertion. Silent failures could make debugging difficult.
🔎 View suggested enhancement:
void insertTextInEditor(String text) async { - final htmlContent = StringConvert.convertTextContentToHtmlContent(text); + try { + final htmlContent = StringConvert.convertTextContentToHtmlContent(text); - if (PlatformInfo.isWeb) { - await richTextWebController?.editorController.evaluateJavascriptWeb( - HtmlUtils.deleteSelectionContent.name, - hasReturnValue: false, - ); + if (PlatformInfo.isWeb) { + await richTextWebController?.editorController.evaluateJavascriptWeb( + HtmlUtils.deleteSelectionContent.name, + hasReturnValue: false, + ); - richTextWebController?.editorController.insertHtml(htmlContent); - } else { - richTextMobileTabletController?.htmlEditorApi?.insertHtml(htmlContent); + richTextWebController?.editorController.insertHtml(htmlContent); + } else { + richTextMobileTabletController?.htmlEditorApi?.insertHtml(htmlContent); + } + } catch (e) { + logError('$runtimeType::insertTextInEditor:Exception = $e'); } }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
core/lib/utils/html/html_utils.dart(1 hunks)core/lib/utils/string_convert.dart(1 hunks)lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart(1 hunks)lib/features/composer/presentation/widgets/web/web_editor_widget.dart(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-12-09T09:36:45.349Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4194
File: lib/features/manage_account/presentation/manage_account_dashboard_controller.dart:174-176
Timestamp: 2025-12-09T09:36:45.349Z
Learning: In Dart/Flutter projects using GetX, do not wrap getBinding<T>() calls in try/catch since they return null when not found. Only wrap Get.find<T>() calls in try/catch because they throw if a dependency is unavailable. When a binding is optional, consider checking Get.isRegistered<T>() or handling the null/exception path gracefully instead of blindly catching, and document the expectation for failure modes where a dependency may not be registered.
Applied to files:
lib/features/composer/presentation/widgets/web/web_editor_widget.dartlib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dartcore/lib/utils/string_convert.dartcore/lib/utils/html/html_utils.dart
📚 Learning: 2025-12-09T12:47:45.861Z
Learnt from: zatteo
Repo: linagora/tmail-flutter PR: 4196
File: scribe/lib/scribe/ai/data/datasource_impl/ai_datasource_impl.dart:34-35
Timestamp: 2025-12-09T12:47:45.861Z
Learning: In the tmail-flutter repository, avoid suggesting replacing DioError with DioException unless there is a codebase-wide migration. This pattern applies to all Dart files; when reviewing, only propose a DioError-safe change (e.g., compatible error handling or conversion) unless a global migration is in place. Ensure consistency of DioError usage across modules and flag any deviations for a repo-wide decision.
Applied to files:
lib/features/composer/presentation/widgets/web/web_editor_widget.dartlib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dartcore/lib/utils/string_convert.dartcore/lib/utils/html/html_utils.dart
📚 Learning: 2025-12-12T07:43:26.643Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4204
File: lib/features/email/presentation/extensions/handle_label_for_email_extension.dart:94-148
Timestamp: 2025-12-12T07:43:26.643Z
Learning: In lib/features/email/presentation/extensions/handle_label_for_email_extension.dart and similar keyword synchronization code, the addKeyword() function is the preferred method for adding keywords to emails. The resyncKeywords() pattern is being phased out and will be replaced in favor of addKeyword().
Applied to files:
lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart
🔇 Additional comments (3)
core/lib/utils/html/html_utils.dart (1)
124-133: LGTM! JavaScript implementation is correct and defensive.The
deleteSelectionContentscript properly checks for selection existence and range availability before deleting contents. The implementation follows the same IIFE pattern as other scripts in this file.lib/features/composer/presentation/widgets/web/web_editor_widget.dart (1)
192-195: LGTM! Script registration follows the established pattern.The
deleteSelectionContentscript is correctly registered in thewebInitialScriptslist, consistent with other utility scripts likecollapseSelectionToEnd.lib/features/composer/presentation/extensions/ai_scribe/handle_ai_scribe_in_composer_extension.dart (1)
32-45: Verify the occasional extra line break issue is acceptable.The PR description mentions that this approach (deleting selection then inserting wrapped content) occasionally adds an extra line break at the end. Please confirm:
- Is this behavior acceptable for the AI Scribe feature?
- Has the root cause been identified?
- Would it impact user experience significantly?
If this is a known limitation that's acceptable, consider documenting it with a comment explaining why this approach was chosen over
execCommandand noting the trade-off.
- Delete selection content before inserting - Insert correct HTML
… and potential security issues
f355901 to
d0bd10e
Compare
Following coderabbit comment here #4212 (comment), I tried to implement another solution with half success.
When selecting multiple lines and clicking on "Replace", it is adding only the last line because insertHtml calls a summernote method that throws when inserting the content.
That's why I wrap the HTML to insert in a
<div>otherwise summernote insertion throw an error.But then it was just inserting it after the selection, not deleting the selection. That's why I delete the selection content before inserting.
Both solution keep undo/redo history.
Video with more complex case
With execCommand
Screen.Recording.2025-12-18.at.16.48.20.mov
With deleting selection and inserting content (this PR)
See how a line break is added at the end 🤷 It happened this time but not in my other tests 🤷
Screen.Recording.2025-12-18.at.16.44.14.mov
Summary by CodeRabbit
Bug Fixes
✏️ Tip: You can customize this high-level summary in your review settings.