-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Allow DATE_TIME IS operand to filter on a whole day #17529
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Allow DATE_TIME IS operand to filter on a whole day #17529
Conversation
Greptile OverviewGreptile SummaryChanged DATE_TIME filter with IS operand to use date-only picker and filter for entire day period instead of precise minute. Key Changes:
Issues Found:
Confidence Score: 4/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant DateInput as ObjectFilterDropdownDateInput
participant FilterInput as ObjectFilterDropdownFilterInput
participant Backend as view-query-params.service
participant Filter as turnRecordFilterIntoGqlOperationFilter
participant DB as Database
User->>FilterInput: Select DATE_TIME field with IS operand
FilterInput->>DateInput: Render DatePicker (not DateTimePicker)
User->>DateInput: Select date (e.g., 2027-01-15)
DateInput->>DateInput: Convert to Instant at 00:00 in user timezone
DateInput->>Backend: Save filter with Instant value
Note over User,DB: Later: Apply saved view filter
User->>Backend: Load view
Backend->>Backend: Fetch workspace member timezone
Backend->>Filter: Pass filter with timezone dependency
Filter->>Filter: Detect plain date or instant format
Filter->>Filter: Calculate day start and end in user timezone
Filter->>DB: Query with gte (day start) and lt (day end)
DB->>User: Return records from full day period
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3 files reviewed, 1 comment
| } | ||
|
|
||
| const newFilterValue = Temporal.PlainDate.from(newPlainDate) | ||
| .toZonedDateTime({ timeZone, plainTime: '00:00' }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
incorrect API usage - toZonedDateTime accepts timezone string directly, not an object
| .toZonedDateTime({ timeZone, plainTime: '00:00' }) | |
| .toZonedDateTime(timeZone) |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx
Line: 48:48
Comment:
incorrect API usage - `toZonedDateTime` accepts timezone string directly, not an object
```suggestion
.toZonedDateTime(timeZone)
```
How can I resolve this? If you propose a fix, please make it concise.|
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:22992 This environment will automatically shut down when the PR is closed or after 5 hours. |
packages/twenty-server/src/engine/metadata-modules/view/services/view-query-params.service.ts
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No issues found across 6 files
...rc/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx
Outdated
Show resolved
Hide resolved
|
The approach is good. But instead of having two code paths to handle both a plain date and a date time value, we want to only handle plain date values for DATE_TIME + IS operand. We'll create a migration command to migrate any date time string to a plain date string value in core.viewFilter table. Let's take for granted in your code that viewFilter.value contains a plain date string. Also during your QA, be careful with operand change, because sometimes changing an operand and keeping the value associated to a previous operand can provoke a crash, we have to take care of cleaning up the value for any operand change. |
|
If you are willing to work on this simple migration command you can do it in another PR, otherwise I'll do it no problem. |
|
Ohk sure I'll do it in another PR. |
|
|
||
| let timeZone = 'UTC'; | ||
|
|
||
| if (currentWorkspaceMemberId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you put this into a util or separate function in this service ? getWorkspaceMemberTimezoneIfAvailable for example
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts
Show resolved
Hide resolved
...twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 6 files (changes from recent commits).
Prompt for AI agents (all issues)
Check if these issues are valid — if so, understand the root cause of each and fix them.
<file name="packages/twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts">
<violation number="1" location="packages/twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts:97">
P2: DATE_TIME IS display now always uses Temporal.PlainDate.from, which throws on stored ISO datetimes with timezone offsets (e.g., existing values like "2024-09-17T20:46:58.922Z"), causing a runtime error and broken filter UI for legacy values.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| const zonedDateTime = Temporal.PlainDate.from( | ||
| recordFilter.value, | ||
| ).toZonedDateTime(userTimezone); | ||
| const { displayValue } = getDateFilterDisplayValue(zonedDateTime); | ||
| return `${displayValue}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: DATE_TIME IS display now always uses Temporal.PlainDate.from, which throws on stored ISO datetimes with timezone offsets (e.g., existing values like "2024-09-17T20:46:58.922Z"), causing a runtime error and broken filter UI for legacy values.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts, line 97:
<comment>DATE_TIME IS display now always uses Temporal.PlainDate.from, which throws on stored ISO datetimes with timezone offsets (e.g., existing values like "2024-09-17T20:46:58.922Z"), causing a runtime error and broken filter UI for legacy values.</comment>
<file context>
@@ -92,28 +94,11 @@ export const useGetRecordFilterDisplayValue = () => {
- const { displayValue } = getDateFilterDisplayValue(zonedDateTime);
- return `${displayValue}`;
- }
+ const zonedDateTime = Temporal.PlainDate.from(
+ recordFilter.value,
+ ).toZonedDateTime(userTimezone);
</file context>
| const zonedDateTime = Temporal.PlainDate.from( | |
| recordFilter.value, | |
| ).toZonedDateTime(userTimezone); | |
| const { displayValue } = getDateFilterDisplayValue(zonedDateTime); | |
| return `${displayValue}`; | |
| let zonedDateTime: Temporal.ZonedDateTime; | |
| try { | |
| zonedDateTime = Temporal.PlainDate.from( | |
| recordFilter.value, | |
| ).toZonedDateTime(userTimezone); | |
| } catch { | |
| zonedDateTime = Temporal.Instant.from( | |
| recordFilter.value, | |
| ).toZonedDateTimeISO(userTimezone); | |
| } | |
| const { displayValue } = getDateFilterDisplayValue(zonedDateTime); | |
| return `${displayValue}`; |
lucasbordeau
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice PR
...twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR modifies the DATE_TIME filter with the IS operand to filter on whole days instead of minute-level precision. The change replaces the DATE_TIME picker with a DATE picker for the IS operand and adjusts the filtering logic to cover a complete 24-hour period in the user's timezone.
Changes:
- Modified filtering logic to convert DATE_TIME IS filters to use full-day ranges based on user timezone
- Added timezone retrieval from workspace member settings with UTC fallback
- Updated frontend components to show date picker instead of datetime picker for IS operand
- Implemented value conversion logic when switching between IS and other operands
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts | Changed DATE_TIME IS operand logic from 1-minute window to 24-hour window using PlainDate and user timezone |
| packages/twenty-server/src/engine/metadata-modules/view/services/view-query-params.service.ts | Added workspace member timezone retrieval and passed it to filter computation |
| packages/twenty-server/src/engine/metadata-modules/view/services/tests/view-query-params.service.spec.ts | Updated test mock to include GlobalWorkspaceOrmManager dependency |
| packages/twenty-server/src/engine/metadata-modules/view/constants/default-timezone.constant.ts | Created constant for default UTC timezone fallback |
| packages/twenty-front/src/modules/object-record/record-filter/hooks/useGetRecordFilterDisplayValue.ts | Updated display value logic to show date format for DATE_TIME IS operand |
| packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useGetInitialFilterValue.ts | Modified initial value generation for DATE_TIME IS to use PlainDate format |
| packages/twenty-front/src/modules/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand.ts | Added conversion logic for switching between IS and other operands, handling format changes between PlainDate and Instant |
| packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx | Added conditional rendering to show date picker for DATE_TIME IS operand |
| packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput.tsx | Improved null handling and variable naming for date input |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Head branch was pushed to by a user without write access
|
@lucasbordeau I’ve addressed the CI failure by fixing the failing test; could you please re-enable auto-merge on this pull request when you have a moment? |
|
@carbonFibreCode I want to be sure of the strategy to roll this out before, because there is a data migration involved. |
lucasbordeau
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Waiting for deploy strategy
@lucasbordeau ohh yes, we have two PRs for the issue , and both are dependent on each other. |
|
We will use a feature flag. So here are the requirements for both PR. This PR :
The data migration PR :
|
| if (recordFilter.operand === RecordFilterOperand.IS) { | ||
| const timeZone = filterValueDependencies.timeZone ?? 'UTC'; | ||
| const plainDate = Temporal.PlainDate.from(recordFilter.value); | ||
| const zonedDateTime = plainDate.toZonedDateTime(timeZone); | ||
| const start = zonedDateTime.toInstant(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: The backend unconditionally parses DATE_TIME IS filter values as PlainDate, but the frontend can send Instant format, causing a crash if a feature flag is disabled.
Severity: HIGH
Suggested Fix
The backend should be made resilient to both PlainDate and Instant formats for DATE_TIME IS filters to ensure backwards compatibility. This can be achieved by attempting to parse the value as a PlainDate first, and if that fails, falling back to parsing it as an Instant.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location:
packages/twenty-shared/src/utils/filter/turnRecordFilterIntoGqlOperationFilter.ts#L393-L397
Potential issue: The backend code at `turnRecordFilterIntoGqlOperationFilter.ts`
unconditionally assumes that when a `DATE_TIME` filter has the `IS` operand, the filter
value is in `PlainDate` format (e.g., 'YYYY-MM-DD'). However, the frontend conditionally
generates this format only when the `IS_DATE_TIME_WHOLE_DAY_FILTER_ENABLED` feature flag
is enabled. If this flag is disabled, the frontend generates a value in `Instant` format
(an ISO 8601 timestamp). This mismatch will cause the backend to throw an unhandled
`RangeError` when `Temporal.PlainDate.from()` receives an `Instant` string, crashing the
request. This affects not only newly created filters but also any existing saved filters
that were created in the `Instant` format before this change.
|
@lucasbordeau done with feature flags, Please let me know further updates regarding the deployment strategy for this PR |
Fixes: twentyhq/core-team-issues#2027
We've replaced the DATE_TIME picker with DATE picker, and changed the logic to filter for complete day period.
Screen.Recording.2026-01-29.at.4.56.06.AM.mov