feat: add IS/IS_NOT option in filters#18426
feat: add IS/IS_NOT option in filters#18426bugisthegod wants to merge 6 commits intotwentyhq:mainfrom
Conversation
packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
1 issue found across 6 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts">
<violation number="1" location="packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts:699">
P1: FULL_NAME IS/IS_NOT operand parsing is whitespace-fragile: uses `split(' ')` without trimming, causing exact-match `eq` comparisons to fail when input has extra spaces (e.g., "John Doe" produces `lastPart=" Doe"` with leading space)</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts
Show resolved
Hide resolved
Greptile SummaryThis PR adds Key changes:
Critical issue: Confidence Score: 2/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User selects IS / IS_NOT operand] --> B{Field type?}
B -->|TEXT| C[turnRecordFilter: eq / not+NULL]
B -->|FULL_NAME| D{Has subfield?}
D -->|No| E[Split value: firstName OR lastName OR firstName+lastName combo]
D -->|Yes| F[eq on subFieldName / not+NULL on subFieldName]
B -->|EMAILS| G[computeGqlOperationFilterForEmails]
G -->|primaryEmail subfield or top-level| H[primaryEmail eq / not+NULL]
B -->|LINKS| I[computeGqlOperationFilterForLinks]
I -->|primaryLinkUrl or primaryLinkLabel subfield| J[subfield eq / not+NULL]
I -->|top-level| K[primaryLinkUrl eq / not+NULL]
B -->|PHONES subfield primaryPhoneNumber| L[primaryPhoneNumber eq / not+NULL]
B -->|PHONES top-level| M[⚠️ NOT IMPLEMENTED → throws runtime error]
style M fill:#f55,color:#fff
|
There was a problem hiding this comment.
Pull request overview
Adds support for exact-match filtering via new IS / IS_NOT operands across multiple filter types, and updates UI operand availability to expose these where appropriate (notably in advanced filters for specific composite subfields).
Changes:
- Implement
IS/IS_NOTtranslation to GQL operation filters forTEXT,FULL_NAME, and selected composite subfields (primaryEmail,primaryLinkUrl,primaryPhoneNumber). - Update frontend operand selection logic to include
IS/IS_NOTfor relevant filter types, with advanced-filter-specific subfield restrictions for Emails/Links/Phones. - Add/extend unit tests to cover the new operand behaviors.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts | Adds GQL filter generation for IS / IS_NOT (notably TEXT, FULL_NAME, and PHONES.primaryPhoneNumber). |
| packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForLinks.ts | Adds IS / IS_NOT support for Links composite fields/subfields. |
| packages/twenty-shared/src/utils/filter/compute-record-gql-operation-filter/for-composite-field/computeGqlOperationFilterForEmails.ts | Adds IS / IS_NOT support for Emails composite fields/subfields. |
| packages/twenty-shared/src/utils/filter/tests/turnRecordFilterIntoGqlOperationFilter.test.ts | Adds test coverage for new IS / IS_NOT operand mappings. |
| packages/twenty-front/src/modules/object-record/record-filter/utils/getRecordFilterOperands.ts | Exposes IS / IS_NOT operands in the UI, with subfield-specific restrictions for advanced filtering. |
| packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/tests/getOperandsForFilterType.test.ts | Updates operand expectations in tests to include the new operands. |
Comments suppressed due to low confidence (1)
packages/twenty-front/src/modules/object-record/object-filter-dropdown/utils/tests/getOperandsForFilterType.test.ts:23
- This test suite validates
getRecordFilterOperands, but it lives underobject-filter-dropdown/utils/__tests__and still uses the legacygetOperandsForFilterTypenaming. Moving/renaming it torecord-filter/utils/__tests__(e.g.getRecordFilterOperands.test.ts) would make it easier to discover and aligns the test location with the unit under test (as noted in the PR description).
const isOperands = [RecordFilterOperand.IS, RecordFilterOperand.IS_NOT];
const numberOperands = [
RecordFilterOperand.IS,
RecordFilterOperand.IS_NOT,
RecordFilterOperand.GREATER_THAN_OR_EQUAL,
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts
Show resolved
Hide resolved
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts">
<violation number="1" location="packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts:1540">
P1: Subfield phone filters can generate wildcard '%%' queries when normalized values are empty but original values contain non-digit characters. The subfield branch lacks the empty-value guard that exists in the non-subfield branch (if (!isNonEmptyString(filterValue)) { return; }), allowing queries like `like '%%'` that can incorrectly match all records and cause expensive broad scans.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts
Show resolved
Hide resolved
…lOperationFilter.ts Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
|
Hi @Bonapara , could you take a look at this PR when you get a chance? Let me know if anything needs to be changed. Thanks! |
|
I'll check if that is corresponding to the initial need, after reading the issue and testing it, I'm not sure. |
Summary
Add IS/IS_NOT option for Full name, text, phone, Links , email. Fixes twentyhq/core-team-issues#2314
In the advanced filter, only show is/is_not option in phone (primaryPhoneNumber), Links (primaryLinkUrl), email (primaryEmail).
name.is.option.mp4
Recording.at.2026-03-05.14.27.51.mp4
Note: test file getOperandsForFilterType.test.ts is misplaced (should be under record-filter/utils/tests/) . It seems it was forgotten when moving — leftover from #9604 .
Question For the Maintainer
Should DOES_NOT_CONTAIN include records where the field is NULL? Currently it doesn't — only records with an existing value that doesn't match are returned. I'm making IS_NOT include NULLs, so wanted to confirm the intended behavior for consistency.
Debounce problem. When a user types quickly (e.g. "Google"), the filter fires on every keystroke, causing results to momentarily include values that should be excluded. Should we add debounce to filter inputs?
type.fast.mp4