Skip to content

Implement not include events filter for search#4451

Open
dab246 wants to merge 4 commits intomasterfrom
hotfix/filter-event-in-mail-search
Open

Implement not include events filter for search#4451
dab246 wants to merge 4 commits intomasterfrom
hotfix/filter-event-in-mail-search

Conversation

@dab246
Copy link
Copy Markdown
Member

@dab246 dab246 commented Apr 14, 2026

Demo

Screen.Recording.2026-04-20.at.16.51.10.mov

Summary by CodeRabbit

  • New Features

    • Added a "Don't include events" search filter/quick-filter to explicitly exclude event-related emails.
  • UI

    • Quick-filter label, localization, checkbox and filter chip updated to "Don't include events"; selection and deletion now use this dedicated option.
  • Bug Fixes

    • Filter composition, application and deletion logic updated so the exclusion flag is correctly applied and removed.
  • Tests

    • Expanded tests to cover the exclusion flag across combinations and resulting filter outputs.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 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

Replaces the previous keyword-driven “events” filter with an explicit boolean notIncludeEvents on SearchEmailFilter and propagates it through controllers, views, quick-search enum, and localization. mappingToEmailFilterCondition() now injects an events-exclusion EmailFilterCondition when notIncludeEvents is true. Tests were added/updated to cover notIncludeEvents behavior and copyWith option handling. UI and controller handlers were renamed/rewired from events/hasEvents to notIncludeEvents and corresponding option plumbing was introduced.

Possibly related PRs

Suggested labels

search

Suggested reviewers

  • hoangdat
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The pull request title accurately summarizes the main change: implementing a 'not include events' filter for search functionality across the codebase.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hotfix/filter-event-in-mail-search

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.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart (1)

161-164: Consider guarding explicit Events inclusion beyond hasKeyword.

Right now, only hasKeyword disables the default notKeyword(events) clause. If Events can be selected via another path (e.g., label.keyword), this can create contradictory filters. Consider centralizing an isEventsExplicitlyIncluded check.

♻️ Suggested hardening
+    final isEventsExplicitlyIncluded =
+      hasKeyword.contains(KeyWordIdentifierExtension.eventsMail.value) ||
+      label?.keyword?.value == KeyWordIdentifierExtension.eventsMail.value;
+
     final listEmailCondition = {
       if (emailEmailFilterConditionShared.hasCondition)
         emailEmailFilterConditionShared,
@@
-      if (!hasKeyword.contains(KeyWordIdentifierExtension.eventsMail.value))
+      if (!isEventsExplicitlyIncluded)
         EmailFilterCondition(
           notKeyword: KeyWordIdentifierExtension.eventsMail.value,
         ),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart`
around lines 161 - 164, The code currently only checks hasKeyword before adding
an EmailFilterCondition(notKeyword:
KeyWordIdentifierExtension.eventsMail.value), which can conflict if Events are
included via another path (e.g., label.keyword); add a centralized boolean
(e.g., isEventsExplicitlyIncluded) that returns true when hasKeyword OR any
other explicit include (like label?.keyword ==
KeyWordIdentifierExtension.eventsMail.value or other selection flags) and then
replace the hasKeyword check with !isEventsExplicitlyIncluded before emitting
EmailFilterCondition(notKeyword: KeyWordIdentifierExtension.eventsMail.value);
update the logic where EmailFilterCondition is created so all places consult
isEventsExplicitlyIncluded to avoid contradictory filters.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart`:
- Around line 161-164: Update the tests to reflect that
mappingToEmailFilterCondition() now returns a non-null EmailFilterCondition for
the initial filter because Events (KeyWordIdentifierExtension.eventsMail) is
excluded by default; specifically modify the assertions in
test/features/search/search_email_filter_test.dart starting around line 81 to
expect a non-null EmailFilterCondition with notKeyword ==
KeyWordIdentifierExtension.eventsMail.value, and add a new test case that
verifies an explicit “include Events” scenario (i.e., when hasKeyword includes
KeyWordIdentifierExtension.eventsMail.value the mapping returns null or an
EmailFilterCondition without notKeyword as appropriate).

---

Nitpick comments:
In
`@lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart`:
- Around line 161-164: The code currently only checks hasKeyword before adding
an EmailFilterCondition(notKeyword:
KeyWordIdentifierExtension.eventsMail.value), which can conflict if Events are
included via another path (e.g., label.keyword); add a centralized boolean
(e.g., isEventsExplicitlyIncluded) that returns true when hasKeyword OR any
other explicit include (like label?.keyword ==
KeyWordIdentifierExtension.eventsMail.value or other selection flags) and then
replace the hasKeyword check with !isEventsExplicitlyIncluded before emitting
EmailFilterCondition(notKeyword: KeyWordIdentifierExtension.eventsMail.value);
update the logic where EmailFilterCondition is created so all places consult
isEventsExplicitlyIncluded to avoid contradictory filters.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e61aa082-96e8-4da3-a030-22c8a4bfe505

📥 Commits

Reviewing files that changed from the base of the PR and between 1d59480 and 52cd120.

📒 Files selected for processing (1)
  • lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart

Comment thread lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart Outdated
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
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

🧹 Nitpick comments (1)
test/features/search/search_email_filter_test.dart (1)

121-135: Assert the events exclusion explicitly here.

Line 135 only checks the condition count, so this can still pass if the third condition is unrelated. Since this hotfix is specifically about the default events exclusion, assert that one EmailFilterCondition has notKeyword == KeyWordIdentifierExtension.eventsMail.value, not just that there are three entries.

Suggested test hardening
         expect(result, isA<LogicFilterOperator>());
         final logicOperator = result as LogicFilterOperator;
         expect(logicOperator.operator, Operator.AND);
         expect(logicOperator.conditions.length, equals(3));
+        expect(
+          logicOperator.conditions.whereType<EmailFilterCondition>().any(
+            (condition) =>
+                condition.notKeyword ==
+                KeyWordIdentifierExtension.eventsMail.value,
+          ),
+          isTrue,
+        );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/features/search/search_email_filter_test.dart` around lines 121 - 135,
The test for SearchEmailFilter.mappingToEmailFilterCondition currently only
checks there are three conditions but doesn't verify the default events
exclusion; update the test to explicitly assert that among the
LogicFilterOperator.conditions (from mappingToEmailFilterCondition) there exists
an EmailFilterCondition whose notKeyword equals
KeyWordIdentifierExtension.eventsMail.value, while keeping the existing checks
for operator AND and total length; refer to
SearchEmailFilter.mappingToEmailFilterCondition, LogicFilterOperator,
EmailFilterCondition, and the
notKeyword/KeyWordIdentifierExtension.eventsMail.value identifiers to locate and
add the assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/features/search/search_email_filter_test.dart`:
- Around line 246-260: Add two additional test cases around
SearchEmailFilter.mappingToEmailFilterCondition to catch membership bugs: (1)
when hasKeyword contains a non-events keyword (ensure
EmailFilterCondition.notKeyword is the events exclusion and hasKeyword reflects
only the provided non-events value), and (2) when hasKeyword contains eventsMail
plus another keyword (ensure eventsMail presence prevents setting notKeyword
while hasKeyword includes both values). Use
KeyWordIdentifierExtension.eventsMail.value and other keyword identifiers, and
assert EmailFilterCondition.hasKeyword and EmailFilterCondition.notKeyword
accordingly to validate membership rather than exact-set equality.

---

Nitpick comments:
In `@test/features/search/search_email_filter_test.dart`:
- Around line 121-135: The test for
SearchEmailFilter.mappingToEmailFilterCondition currently only checks there are
three conditions but doesn't verify the default events exclusion; update the
test to explicitly assert that among the LogicFilterOperator.conditions (from
mappingToEmailFilterCondition) there exists an EmailFilterCondition whose
notKeyword equals KeyWordIdentifierExtension.eventsMail.value, while keeping the
existing checks for operator AND and total length; refer to
SearchEmailFilter.mappingToEmailFilterCondition, LogicFilterOperator,
EmailFilterCondition, and the
notKeyword/KeyWordIdentifierExtension.eventsMail.value identifiers to locate and
add the assertion.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf4925bc-fa87-4cb3-8559-09ecbed4620e

📥 Commits

Reviewing files that changed from the base of the PR and between 52cd120 and d2af657.

📒 Files selected for processing (1)
  • test/features/search/search_email_filter_test.dart

Comment thread test/features/search/search_email_filter_test.dart Outdated
@github-actions
Copy link
Copy Markdown

This PR has been deployed to https://linagora.github.io/tmail-flutter/4451.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@chibenwa
Copy link
Copy Markdown
Member

chibenwa commented Apr 14, 2026

Well I STRONGLY disagree with that change.

I do believe that pleople are actually interested in email about event and might actually actively look for them.

I thus challenge this functionnal requirement that I believe is misplaced.

What are other email providers doing? Is GMail for instance actively filtering out events from my email search ?

Cc @poupotte

Copy link
Copy Markdown
Member

@chibenwa chibenwa left a comment

Choose a reason for hiding this comment

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

Cf earlier comment

Signed-off-by: dab246 <tdvu@linagora.com>
@dab246 dab246 force-pushed the hotfix/filter-event-in-mail-search branch from 9cd5bec to 8cd75a8 Compare April 20, 2026 03:19
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
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: 2

🧹 Nitpick comments (2)
lib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart (1)

40-42: Consider renaming the stale delete helper.

Line 40 now clears notIncludeEventsOption, so deleteNotIncludeEventsSearchFilter() would better match the behavior than deleteEventsSearchFilter().

Also applies to: 55-56

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@lib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart`
around lines 40 - 42, The helper deleteEventsSearchFilter() is misnamed because
it clears the notIncludeEventsOption; rename the function to
deleteNotIncludeEventsSearchFilter and update all call sites and references
accordingly; inside the function keep the call to
searchController.updateFilterEmail(notIncludeEventsOption: const None())
unchanged and also rename the analogous helper at the other occurrence (lines
55-56) to the matching deleteNotIncludeEvents... name so names reflect
behaviour.
test/features/search/search_email_filter_test.dart (1)

25-29: Match the events exclusion explicitly in the helper.

firstWhere((c) => c.notKeyword != null) can pick another notKeyword condition, such as unread’s emailSeen, if this helper is reused on a broader AND filter. Match eventsMail directly to avoid false failures.

Suggested test helper hardening
 void _assertEventsExclusionInAnd(LogicFilterOperator andFilter) {
   final eventsExclusion = andFilter.conditions
       .whereType<EmailFilterCondition>()
-      .firstWhere((c) => c.notKeyword != null);
+      .firstWhere(
+        (c) => c.notKeyword == KeyWordIdentifierExtension.eventsMail.value,
+      );
   expect(eventsExclusion.notKeyword, KeyWordIdentifierExtension.eventsMail.value);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/features/search/search_email_filter_test.dart` around lines 25 - 29, The
helper _assertEventsExclusionInAnd currently finds any EmailFilterCondition with
a non-null notKeyword which can pick the wrong condition; update the predicate
so it explicitly looks for the events exclusion by matching c.notKeyword ==
KeyWordIdentifierExtension.eventsMail.value (i.e., use firstWhere((c) =>
c.notKeyword == KeyWordIdentifierExtension.eventsMail.value)) to ensure the test
asserts the eventsMail exclusion rather than any notKeyword.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@lib/features/search/email/presentation/extension/update_search_filter_extension.dart`:
- Around line 1-11: The current DeleteQuickSearchFilter implementation in the
UpdateSearchFilterExtension only handles QuickSearchFilter.labels, causing
deletions of QuickSearchFilter.starred, QuickSearchFilter.unread, and
QuickSearchFilter.notIncludeEvents to be ignored; update deleteQuickSearchFilter
to switch on the incoming QuickSearchFilter and for each case clear the
corresponding filter state (e.g., call updateSimpleSearchFilter with the
appropriate parameters for labels, remove/clear the starred flag, clear the
unread flag, and clear the not-include-events flag), then call
searchEmailAction() after clearing to re-run the search; reference the extension
UpdateSearchFilterExtension, the method deleteQuickSearchFilter, the
QuickSearchFilter enum values, updateSimpleSearchFilter, and searchEmailAction
when making the changes.

In `@test/features/search/verify_before_time_in_search_email_filter_test.dart`:
- Around line 178-188: _extractBeforeFromFilter currently calls firstWhere on
LogicFilterOperator.conditions which throws if no EmailFilterCondition has
before; change it to defensively search recursively: iterate over
filter.conditions in _extractBeforeFromFilter, for each condition return
condition.before if it's an EmailFilterCondition with before set, and if it's a
LogicFilterOperator call _extractBeforeFromFilter recursively and return the
non-null result; if none found return null. This avoids StateError and safely
handles nested LogicFilterOperator trees when before is absent.

---

Nitpick comments:
In
`@lib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart`:
- Around line 40-42: The helper deleteEventsSearchFilter() is misnamed because
it clears the notIncludeEventsOption; rename the function to
deleteNotIncludeEventsSearchFilter and update all call sites and references
accordingly; inside the function keep the call to
searchController.updateFilterEmail(notIncludeEventsOption: const None())
unchanged and also rename the analogous helper at the other occurrence (lines
55-56) to the matching deleteNotIncludeEvents... name so names reflect
behaviour.

In `@test/features/search/search_email_filter_test.dart`:
- Around line 25-29: The helper _assertEventsExclusionInAnd currently finds any
EmailFilterCondition with a non-null notKeyword which can pick the wrong
condition; update the predicate so it explicitly looks for the events exclusion
by matching c.notKeyword == KeyWordIdentifierExtension.eventsMail.value (i.e.,
use firstWhere((c) => c.notKeyword ==
KeyWordIdentifierExtension.eventsMail.value)) to ensure the test asserts the
eventsMail exclusion rather than any notKeyword.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 972c36c9-d5bc-4539-8b47-a42dbdec5b93

📥 Commits

Reviewing files that changed from the base of the PR and between 9cd5bec and 8cd75a8.

📒 Files selected for processing (15)
  • lib/features/mailbox_dashboard/presentation/controller/advanced_filter_controller.dart
  • lib/features/mailbox_dashboard/presentation/controller/mailbox_dashboard_controller.dart
  • lib/features/mailbox_dashboard/presentation/controller/search_controller.dart
  • lib/features/mailbox_dashboard/presentation/extensions/select_search_filter_action_extension.dart
  • lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart
  • lib/features/mailbox_dashboard/presentation/model/search/quick_search_filter.dart
  • lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart
  • lib/features/mailbox_dashboard/presentation/widgets/advanced_search/advanced_search_filter_form_bottom_view.dart
  • lib/features/search/email/presentation/extension/update_search_filter_extension.dart
  • lib/features/search/email/presentation/search_email_controller.dart
  • lib/features/search/email/presentation/search_email_view.dart
  • lib/l10n/intl_messages.arb
  • lib/main/localizations/app_localizations.dart
  • test/features/search/search_email_filter_test.dart
  • test/features/search/verify_before_time_in_search_email_filter_test.dart
✅ Files skipped from review due to trivial changes (1)
  • lib/features/mailbox_dashboard/presentation/controller/search_controller.dart
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/features/mailbox_dashboard/presentation/model/search/search_email_filter.dart

Signed-off-by: dab246 <tdvu@linagora.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

@dab246 dab246 changed the title hotfix: Set not event-email when search email as default Implement not include events filter for search Apr 20, 2026
case QuickSearchFilter.unread:
case QuickSearchFilter.labels:
case QuickSearchFilter.events:
case QuickSearchFilter.notIncludeEvents:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Change spotted in mailbox_dashboard_controller.

Please elaborate on "why this is needed" and "what we can do to avoid this change"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Why this is needed

This is an optional change; we modify it to clarify the function of each variable and avoid confusion during maintenance later, if another type of filter related to the event is needed.

What we can do to avoid this change

As explained above, we can keep it as is, but we should add a comment to clarify the function of this filter.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Keep QuickSearchFilter.events

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We have searchController is the single source of truth for search state.

Image

But in some other UI, which was controlled by other controller - mailbox_dashboard_controller in this case was updated to update the searchController. This is the reason why some controller were changed also.

Copy link
Copy Markdown
Member

@chibenwa chibenwa left a comment

Choose a reason for hiding this comment

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

Reviewed.

No strong opposition on my side. We are touching with a simple code change 5+ controler and views, which lead me to think we have a view centered model, while there could be room for higher level abstractions...

Can we have a video of what is delivered, please?

codescene-delta-analysis[bot]

This comment was marked as outdated.

@dab246
Copy link
Copy Markdown
Member Author

dab246 commented Apr 20, 2026

Can we have a video of what is delivered, please?

Updated

Screen.Recording.2026-04-20.at.16.51.10.mov

Comment thread lib/features/mailbox_dashboard/presentation/mailbox_dashboard_view_web.dart Outdated
Comment thread test/features/search/search_email_filter_test.dart
Copy link
Copy Markdown

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Choose a reason for hiding this comment

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

Code Health Improved (1 files improve in Code Health)

Gates Passed
3 Quality Gates Passed

See analysis details in CodeScene

View Improvements
File Code Health Impact Categories Improved
update_search_filter_extension.dart 9.69 → 10.00 Complex Method

Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

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.

4 participants