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 PR introduces comprehensive label-based email filtering and management capabilities. It adds new lifecycle hooks to the base test scenario framework, provisions label and email test data through new mixins and models, implements label selection UI components in advanced search and quick search filters, extends the email search filter pipeline to support label-based filtering, updates email views to leverage new label availability logic, adds keyword support to email creation, and includes integration tests for searching emails by labels. The changes span test infrastructure, domain models, presentation controllers, UI widgets, and localization resources. Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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/4230. |
lib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dart
Outdated
Show resolved
Hide resolved
60db802 to
65e8302
Compare
The integration test results may be inaccurate due to an error in the |
|
@coderabbitai can you please review this? |
|
@chibenwa: I'll review the changes in this PR. ✅ Actions performedReview triggered.
|
lib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dart
Outdated
Show resolved
Hide resolved
lib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dart
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/features/composer/presentation/model/create_email_request.dart (1)
117-118: Pre-existing issue: duplicatereferencesin props.Lines 117-118 both list
references, but line 117 should likely bemessageIdbased on the field declaration at line 41. This affects the Equatable equality comparison.🔧 Suggested fix
unsubscribeEmailId, - references, + messageId, references,lib/features/base/widget/popup_menu/popup_menu_item_action_widget.dart (1)
224-239: Add missingisSelectedcheck for non-RTL selected icon rendering.The selectedIconWidget rendering is asymmetric between RTL and non-RTL layouts:
- Line 176: Shows with
isSelectedcheck- Line 224 (non-RTL): Shows without
isSelectedcheck- Line 239 (RTL): Shows with
isSelectedcheckThis asymmetry affects real actions that override
isArrangeRTL => false(e.g.,PopupMenuItemLabelTypeAction), causing the selected icon to display regardless of selection state in non-RTL mode. Either addisSelected &&to line 224 to match the other paths, or document why this path intentionally differs.
🤖 Fix all issues with AI agents
In @lib/features/base/widget/context_menu/context_menu_dialog_item.dart:
- Around line 91-92: The non-RTL branch is rendering selectedIconWidget without
checking isSelected, causing asymmetry with the RTL branch; update the
conditional to require isSelected as well (i.e., change the check to
!isArrangeRTL && isSelected && selectedIconWidget != null so selectedIconWidget
only renders when the item is selected). Apply the same change in the popup menu
widget where a similar pattern exists (wrap the non-RTL selectedIconWidget
render with isSelected && in addition to the existing checks).
In
@lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart:
- Around line 154-155: The code unconditionally creates an EmailFilterCondition
using label!.keyword?.value which can be null; update the condition construction
in search_email_filter.dart so you first read the keyword (e.g., final kw =
label?.keyword?.value) and only add EmailFilterCondition(hasKeyword: kw) when kw
is non-null (and non-empty if desired), replacing the current if (label != null)
EmailFilterCondition(...) usage to guard against null/empty keyword values.
🧹 Nitpick comments (7)
lib/features/manage_account/domain/model/preferences/label_config.dart (1)
13-14: Verify thatPlatformInfo.isIntegrationTestingreliably detects the integration test environment.The logic correctly enables labels by default during integration tests. However, ensure that
PlatformInfo.isIntegrationTestingaccurately identifies the integration test environment across all test scenarios and doesn't inadvertently enable labels in unintended contexts.Consider adding a brief comment explaining why the default behavior differs based on the test environment:
// Enable labels by default in integration tests to support test scenarios factory LabelConfig.initial() => LabelConfig(isEnabled: PlatformInfo.isIntegrationTesting);lib/features/base/widget/context_menu/context_menu_dialog_item.dart (1)
79-80: Potential spacing inconsistency in non-RTL layouts.The
leadingWidgetprovides a 24-width spacer whenisArrangeRTLis true andiconWidgetis null, ensuring consistent leading spacing. However, whenisArrangeRTLis false andiconWidgetis null,leadingWidgetbecomesnull, which may result in inconsistent left alignment/padding for non-RTL menu items without icons.Consider using a spacer for non-RTL mode as well to maintain uniform spacing.
♻️ Proposed fix to ensure consistent spacing
- final leadingWidget = - iconWidget ?? (isArrangeRTL ? const SizedBox(width: 24) : null); + final leadingWidget = iconWidget ?? const SizedBox(width: 24);lib/features/mailbox/presentation/base_mailbox_view.dart (1)
27-27: Centralizing label-list visibility onisLabelAvailableis reasonableUsing
mailboxDashBoardController.isLabelAvailable(via the new extension import) keeps the “should we show the label list?” logic in one place and makesbuildLabelsListsimpler. The remaining use ofisLabelCapabilitySupportedandisLabelSettingEnabledinbuildLabelsBaris acceptable, but if you ever need identical gating semantics for bar and list, consider reusingisLabelAvailablethere as well to avoid drift.Also applies to: 383-409
lib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart (1)
37-46: Consider renaming or documenting the method's scope.The method
deleteQuickSearchFilteris named generically but currently only handlesQuickSearchFilter.labels. This creates an inconsistency with the existing dedicated methods (deleteStarredSearchFilter,deleteUnreadSearchFilter).Consider either:
- Renaming to
deleteLabelSearchFilterfor consistency with existing methods- Adding documentation explaining why some filters have dedicated methods while others use the generic handler
- Migrating starred/unread handling into this method for consistency
The switch pattern suggests future extensibility, but the current design makes the handling strategy unclear.
integration_test/scenarios/search/search_email_with_tag_scenario.dart (1)
75-85: Consider adding a brief comment explaining the subject-based verification.The test verifies email filtering by checking if the email's subject contains the tag display name. This works because
buildEmailsForLabelpresumably includes the tag name in the email subject. A brief comment would make this relationship clearer for future maintainers.💡 Suggested comment
Future<void> _expectEmailListDisplayedCorrectByTag({ required String tagDisplayName, required int emailCount, }) async { + // Emails provisioned by buildEmailsForLabel include the tag name in the subject final listEmailTileWithTag = $.tester.widgetList<EmailTileBuilder>( $(EmailTileBuilder).which<EmailTileBuilder>((widget) => widget.presentationEmail.subject?.contains(tagDisplayName) == true), ); expect(listEmailTileWithTag.length, greaterThanOrEqualTo(emailCount)); }lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart (1)
95-96: Consider icon selection consistency.Unlike other quick search filters (hasAttachment, starred, unread), the labels case doesn't use the
isSelectedparameter to show different icons. Other filters showicSelectedSBwhen selected.Is this intentional? If labels should follow the same pattern:
♻️ Optional refactor for consistency
case QuickSearchFilter.labels: - return imagePaths.icTag; + return isSelected ? imagePaths.icSelectedSB : imagePaths.icTag;integration_test/mixin/provisioning_label_scenario_mixin.dart (1)
12-45: LGTM! Well-structured label provisioning with proper null handling.The mixin correctly uses
getBinding<T>()which returns null when not found (no try/catch needed per GetX patterns). The concurrent label creation withFuture.waitand filtering withwhereType<Label>()handles partial failures gracefully.One minor observation: if
dashboardControlleris null, the code will still log and return early due toaccountIdbeing null. Consider addingdashboardControllerto the null-check message for clearer diagnostics:💡 Optional: More descriptive logging
- if (createLabelInteractor == null || accountId == null) { + if (dashboardController == null || + createLabelInteractor == null || + accountId == null) { log( 'ProvisioningLabelScenarioMixin::provisionLabels ' - 'skipped: missing CreateNewLabelInteractor or accountId', + 'skipped: missing dashboardController, CreateNewLabelInteractor, or accountId', ); return []; }
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (51)
integration_test/base/base_test_scenario.dartintegration_test/mixin/provisioning_label_scenario_mixin.dartintegration_test/mixin/scenario_utils_mixin.dartintegration_test/models/provisioning_email.dartintegration_test/models/provisioning_label.dartintegration_test/robots/label_list_context_menu_robot.dartintegration_test/robots/label_robot.dartintegration_test/robots/search_robot.dartintegration_test/scenarios/search/search_email_with_tag_scenario.dartintegration_test/tests/search/search_email_with_tag_test.dartlabels/lib/extensions/label_extension.dartlabels/lib/extensions/list_label_extension.dartlib/features/base/mixin/popup_context_menu_action_mixin.dartlib/features/base/model/filter_filter.dartlib/features/base/model/popup_menu_item_action.dartlib/features/base/widget/context_menu/context_menu_dialog_item.dartlib/features/base/widget/context_menu/context_menu_item_action.dartlib/features/base/widget/popup_menu/popup_menu_item_action_widget.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartlib/features/composer/presentation/model/create_email_request.dartlib/features/email/presentation/email_view.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/mailbox_dashboard/presentation/styles/label_drop_down_style.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_field_widget.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/manage_account/domain/model/preferences/label_config.dartlib/features/manage_account/presentation/manage_account_dashboard_controller.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartlib/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.dartlib/features/thread/presentation/thread_view.dartlib/features/thread_detail/presentation/thread_detail_view.dartlib/l10n/intl_messages.arblib/main/localizations/app_localizations.darttest/features/composer/data/repository/composer_repository_impl_test.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dart
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4204
File: lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart:579-582
Timestamp: 2025-12-12T07:56:31.877Z
Learning: In lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart, the addLabelToEmail method intentionally throws UnimplementedError because label synchronization with the email cache is handled separately via extension methods (e.g., _autoSyncLabelToSelectedEmailOnMemory in handle_label_for_email_extension.dart). Implementing it in the cache datasource would cause data conflicts. This differs from other keyword operations like markAsRead, markAsStar, markAsAnswered, and markAsForwarded, which are implemented directly in the cache datasource.
📚 Learning: 2025-12-12T09:03:05.962Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4204
File: lib/features/email/presentation/model/popup_menu_item_email_action.dart:34-35
Timestamp: 2025-12-12T09:03:05.962Z
Learning: In the tmail-flutter codebase, popup menu items intentionally use a consistent hoverIcon (imagePaths.icThumbsUp) across all popup item types (email actions, mailbox actions, profile settings, etc.), while actionIcon varies per action type. This is a deliberate UI/UX design choice.
Applied to files:
lib/features/base/model/popup_menu_item_action.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartlib/features/base/widget/context_menu/context_menu_dialog_item.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/base/widget/context_menu/context_menu_item_action.dartlib/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.dartlib/features/base/widget/popup_menu/popup_menu_item_action_widget.dartlib/features/base/mixin/popup_context_menu_action_mixin.dart
📚 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/base/model/popup_menu_item_action.dartlib/features/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartintegration_test/robots/search_robot.dartlib/main/localizations/app_localizations.dartlib/features/email/presentation/email_view.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartintegration_test/tests/search/search_email_with_tag_test.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartintegration_test/models/provisioning_label.dartintegration_test/models/provisioning_email.dartintegration_test/scenarios/search/search_email_with_tag_scenario.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dartlib/features/composer/presentation/model/create_email_request.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/base/widget/context_menu/context_menu_dialog_item.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/base/widget/context_menu/context_menu_item_action.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_field_widget.dartlib/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/mailbox_dashboard/presentation/styles/label_drop_down_style.dartlib/features/thread/presentation/thread_view.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.darttest/features/composer/data/repository/composer_repository_impl_test.dartlib/features/base/widget/popup_menu/popup_menu_item_action_widget.dartlib/features/manage_account/domain/model/preferences/label_config.dartlib/features/base/mixin/popup_context_menu_action_mixin.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/manage_account/presentation/manage_account_dashboard_controller.dartlabels/lib/extensions/label_extension.dartintegration_test/mixin/provisioning_label_scenario_mixin.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartintegration_test/mixin/scenario_utils_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartintegration_test/robots/label_robot.dartlib/features/thread_detail/presentation/thread_detail_view.dartintegration_test/robots/label_list_context_menu_robot.dartlib/features/base/model/filter_filter.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartintegration_test/base/base_test_scenario.dartlabels/lib/extensions/list_label_extension.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.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/base/model/popup_menu_item_action.dartlib/features/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartintegration_test/robots/search_robot.dartlib/main/localizations/app_localizations.dartlib/features/email/presentation/email_view.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartintegration_test/tests/search/search_email_with_tag_test.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartintegration_test/models/provisioning_label.dartintegration_test/models/provisioning_email.dartintegration_test/scenarios/search/search_email_with_tag_scenario.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dartlib/features/composer/presentation/model/create_email_request.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/base/widget/context_menu/context_menu_dialog_item.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/base/widget/context_menu/context_menu_item_action.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_field_widget.dartlib/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/mailbox_dashboard/presentation/styles/label_drop_down_style.dartlib/features/thread/presentation/thread_view.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.darttest/features/composer/data/repository/composer_repository_impl_test.dartlib/features/base/widget/popup_menu/popup_menu_item_action_widget.dartlib/features/manage_account/domain/model/preferences/label_config.dartlib/features/base/mixin/popup_context_menu_action_mixin.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/manage_account/presentation/manage_account_dashboard_controller.dartlabels/lib/extensions/label_extension.dartintegration_test/mixin/provisioning_label_scenario_mixin.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartintegration_test/mixin/scenario_utils_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartintegration_test/robots/label_robot.dartlib/features/thread_detail/presentation/thread_detail_view.dartintegration_test/robots/label_list_context_menu_robot.dartlib/features/base/model/filter_filter.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartintegration_test/base/base_test_scenario.dartlabels/lib/extensions/list_label_extension.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.dart
📚 Learning: 2025-12-12T04:54:11.121Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4191
File: lib/features/email/presentation/extensions/handle_email_action_extension.dart:37-80
Timestamp: 2025-12-12T04:54:11.121Z
Learning: In lib/features/email/presentation/extensions/handle_email_action_extension.dart, the mailboxDashBoardController.selectedEmail should only be synchronized when isMobileThreadDisabled is true. This is intentional behavior and should not be changed to update selectedEmail in non-mobile or thread-enabled contexts.
Applied to files:
lib/features/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartlib/features/email/presentation/email_view.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/thread/presentation/thread_view.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/manage_account/presentation/manage_account_dashboard_controller.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartintegration_test/mixin/scenario_utils_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartlib/features/thread_detail/presentation/thread_detail_view.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.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/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartlib/features/email/presentation/email_view.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartintegration_test/models/provisioning_email.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dartlib/features/composer/presentation/model/create_email_request.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/thread/presentation/thread_view.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartintegration_test/mixin/scenario_utils_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartlib/features/thread_detail/presentation/thread_detail_view.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartlabels/lib/extensions/list_label_extension.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.dart
📚 Learning: 2025-12-12T07:56:31.877Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4204
File: lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart:579-582
Timestamp: 2025-12-12T07:56:31.877Z
Learning: In lib/features/email/data/datasource_impl/email_hive_cache_datasource_impl.dart, the addLabelToEmail method intentionally throws UnimplementedError because label synchronization with the email cache is handled separately via extension methods (e.g., _autoSyncLabelToSelectedEmailOnMemory in handle_label_for_email_extension.dart). Implementing it in the cache datasource would cause data conflicts. This differs from other keyword operations like markAsRead, markAsStar, markAsAnswered, and markAsForwarded, which are implemented directly in the cache datasource.
Applied to files:
lib/features/mailbox_dashboard/presentation/extensions/advanced_search/update_label_in_advanced_search_extension.dartlib/features/mailbox_dashboard/presentation/extensions/labels/check_label_available_extension.dartlib/features/email/presentation/email_view.dartlib/features/search/email/presentation/extension/update_search_filter_extension.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartintegration_test/models/provisioning_email.dartintegration_test/scenarios/search/search_email_with_tag_scenario.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/label_drop_down_button.dartlib/features/mailbox_dashboard/presentation/extensions/labels/handle_logic_label_extension.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/mailbox/presentation/base_mailbox_view.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/search/email/presentation/mixin/search_label_filter_modal_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dartlib/features/thread/presentation/thread_view.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartintegration_test/mixin/provisioning_label_scenario_mixin.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartintegration_test/mixin/scenario_utils_mixin.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dartlib/features/thread_detail/presentation/thread_detail_view.dartlib/features/composer/presentation/extensions/create_email_request_extension.dartlabels/lib/extensions/list_label_extension.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dartlib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.dart
📚 Learning: 2025-12-23T05:27:10.887Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4210
File: model/lib/mailbox/presentation_mailbox.dart:22-34
Timestamp: 2025-12-23T05:27:10.887Z
Learning: In the tmail-flutter codebase, the Action Required folder (actionRequiredFolder) is a virtual folder that is AI-curated and contains emails with the keyword "needs-action". Unlike the Favorites folder, users should NOT be able to drag emails into the Action Required folder. The UI correctly prevents this by not wrapping the Action Required folder item in a DragTarget (see mailbox_item_widget.dart).
Applied to files:
lib/features/email/presentation/email_view.dartlib/features/search/email/presentation/model/context_item_label_type_action.dartlib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.darttest/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/mailbox_dashboard/presentation/widgets/search_filters/search_filter_button.dartlib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_input_form.dartlib/features/thread/presentation/thread_view.dartlib/features/search/email/presentation/model/popup_menu_item_label_type_action.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartlib/features/thread_detail/presentation/thread_detail_view.dartlib/features/search/email/presentation/search_email_controller.dartlib/features/search/email/presentation/search_email_view.dart
📚 Learning: 2025-12-18T09:19:32.437Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4203
File: scribe/pubspec.yaml:37-37
Timestamp: 2025-12-18T09:19:32.437Z
Learning: In the tmail-flutter repository, json_annotation version 4.8.0 is the standardized version across modules and should not be upgraded without considering the standardization practice.
Applied to files:
test/features/composer/presentation/extensions/create_email_request_extension_test.dartlib/features/manage_account/domain/model/preferences/label_config.dartlib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartlib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart
📚 Learning: 2025-12-23T05:27:40.476Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4210
File: lib/l10n/intl_messages.arb:5151-5182
Timestamp: 2025-12-23T05:27:40.476Z
Learning: In lib/l10n, translations for locale .arb files are updated automatically by an external workflow when new English keys are added to intl_messages.arb. Do not manually modify translated locale .arb files in pull requests; rely on the automated workflow to update translations. If manual edits are necessary, clearly reference the automation workflow and ensure translations remain consistent with the source English keys.
Applied to files:
lib/l10n/intl_messages.arb
📚 Learning: 2025-12-19T08:04:06.064Z
Learnt from: hoangdat
Repo: linagora/tmail-flutter PR: 4208
File: lib/l10n/intl_fr.arb:5209-5226
Timestamp: 2025-12-19T08:04:06.064Z
Learning: In all ARB localization files under lib/l10n, AI Scribe translation keys should only be present for the supported locales: en (default), fr, vi, and ru. Do not add AI Scribe keys to other locale files. Ensure fr, vi, and ru ARB files include the same AI Scribe keys as applicable, with en as the source/default. This pattern applies to any ARB file in the lib/l10n directory.
Applied to files:
lib/l10n/intl_messages.arb
📚 Learning: 2025-12-15T06:24:38.823Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4137
File: lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart:32-32
Timestamp: 2025-12-15T06:24:38.823Z
Learning: In lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart and lib/features/manage_account/presentation/manage_account_dashboard_controller.dart, the code calls SentryManager.instance.setUser() with PII fields (account ID, display name, username, email). This is privacy-sensitive. Review and ensure PII handling complies with policy: avoid sending unnecessary PII to Sentry, redact or hash sensitive fields if possible, or document explicit privacy policy and user consent for such data. If PII must be sent, ensure minimal data, secure handling, and add notes to the privacy policy. Consider adding tests or a lint rule to flag setUser calls that include PII.
Applied to files:
lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dartlib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dartlib/features/mailbox_dashboard/presentation/controller/search_controller.dart
📚 Learning: 2025-12-15T06:24:50.369Z
Learnt from: dab246
Repo: linagora/tmail-flutter PR: 4137
File: lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart:32-32
Timestamp: 2025-12-15T06:24:50.369Z
Learning: In lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart and lib/features/manage_account/presentation/manage_account_dashboard_controller.dart, SentryManager.instance.setUser() intentionally sends PII (account ID, display name, username, email) to Sentry for error tracking. The team plans to document this in the app's privacy policy for transparency and compliance.
Applied to files:
lib/features/manage_account/presentation/manage_account_dashboard_controller.dartlib/features/thread_detail/presentation/thread_detail_view.dart
⏰ 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). (10)
- GitHub Check: Build web version and deploy
- GitHub Check: analyze-test (rule_filter)
- GitHub Check: analyze-test (server_settings)
- GitHub Check: analyze-test (forward)
- GitHub Check: analyze-test (fcm)
- GitHub Check: analyze-test (email_recovery)
- GitHub Check: analyze-test (core)
- GitHub Check: analyze-test (model)
- GitHub Check: analyze-test (default)
- GitHub Check: analyze-test (contact)
lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart
Outdated
Show resolved
Hide resolved
4e59de4 to
5294659
Compare
…endering to match RTL behavior.
4a2fbfa to
6ed154c
Compare
Issue
#4229
Resolved
Screen.Recording.2026-01-02.at.18.03.07.mov
demo-mobile.webm
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.