From 9bc0db5666e5a12d6b97cd5ad027785bdc3b490d Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Thu, 18 Jun 2026 18:18:08 +0530 Subject: [PATCH] fix: exclude non-groupBy date fields (deletedAt) from calendar field selection (#21764) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #21608 The Tasks Calendar renders an empty grid because `GroupByTasks` fails with `Field "deletedAt" is not supported in groupBy` while the header count (`AggregateTasks`) still succeeds. The calendar renders by grouping records on the selected date field. Calendar-field eligibility only checked `isFieldMetadataDateKind`, so `deletedAt` (a system DATE_TIME field) could be picked or auto-defaulted as the calendar field — and the groupBy engine correctly rejects it (only `createdAt`/`updatedAt` are groupable system date fields). Fix: gate calendar-field eligibility on `isFieldMetadataSupportedInGroupBy` (the same authority the backend groupBy validator uses), so non-groupable date fields can no longer be selected. - `useGetAvailableFieldsForCalendar` — add the groupBy-support check alongside the date-kind filter - `ObjectOptionsDropdownCalendarFieldsContent` — reuse the hook's list instead of re-filtering raw fields --- ...ctOptionsDropdownCalendarFieldsContent.tsx | 7 +-- .../useGetAvailableFieldsForCalendar.test.tsx | 48 +++++++++++++++++++ .../hooks/useGetAvailableFieldsForCalendar.ts | 16 +++++-- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx index e1bb6b9aea..7715e47b18 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownCalendarFieldsContent.tsx @@ -13,7 +13,6 @@ import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useG import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState'; import { useLingui } from '@lingui/react/macro'; import { useState } from 'react'; -import { isFieldMetadataDateKind } from 'twenty-shared/utils'; import { IconChevronLeft, IconSettings, useIcons } from 'twenty-ui/icon'; import { MenuItem, MenuItemSelect } from 'twenty-ui/navigation'; @@ -27,14 +26,12 @@ export const ObjectOptionsDropdownCalendarFieldsContent = () => { const { currentView } = useGetCurrentViewOnly(); const { updateCurrentView } = useUpdateCurrentView(); - const { navigateToDateFieldSettings } = useGetAvailableFieldsForCalendar(); + const { availableFieldsForCalendar, navigateToDateFieldSettings } = + useGetAvailableFieldsForCalendar(); const setRecordIndexCalendarFieldMetadataId = useSetAtomState( recordIndexCalendarFieldMetadataIdState, ); - const availableFieldsForCalendar = objectMetadataItem.fields.filter((field) => - isFieldMetadataDateKind(field.type), - ); const calendarFieldMetadata = currentView?.calendarFieldMetadataId ? objectMetadataItem.fields.find( diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx index 3b585a90f0..18f13955cb 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/__tests__/useGetAvailableFieldsForCalendar.test.tsx @@ -96,6 +96,54 @@ describe('useGetAvailableFieldsForCalendar', () => { ]); }); + it('should exclude date fields not supported in groupBy while keeping createdAt and updatedAt', () => { + const fields = [ + { + id: '1', + name: 'dueAt', + type: FieldMetadataType.DATE_TIME, + label: 'Due Date', + isActive: true, + isSystem: false, + }, + { + id: '2', + name: 'createdAt', + type: FieldMetadataType.DATE_TIME, + label: 'Created At', + isActive: true, + isSystem: true, + }, + { + id: '3', + name: 'updatedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Updated At', + isActive: true, + isSystem: true, + }, + { + id: '4', + name: 'deletedAt', + type: FieldMetadataType.DATE_TIME, + label: 'Deleted At', + isActive: true, + isSystem: true, + }, + ]; + + const objectMetadataItems = [createMockObjectMetadataItem(fields)]; + const wrapper = createWrapper(objectMetadataItems); + + const { result } = renderHook(() => useGetAvailableFieldsForCalendar(), { + wrapper, + }); + + expect( + result.current.availableFieldsForCalendar.map((field) => field.name), + ).toEqual(['dueAt', 'createdAt', 'updatedAt']); + }); + it('should return the navigateToDateFieldSettings function', () => { const fields = [ { diff --git a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts index 2de2925237..9faf22e559 100644 --- a/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts +++ b/packages/twenty-front/src/modules/views/view-picker/hooks/useGetAvailableFieldsForCalendar.ts @@ -8,7 +8,11 @@ import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/use import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState'; import { FieldMetadataType, SettingsPath } from 'twenty-shared/types'; -import { isDefined, isFieldMetadataDateKind } from 'twenty-shared/utils'; +import { + isDefined, + isFieldMetadataDateKind, + isFieldMetadataSupportedInGroupBy, +} from 'twenty-shared/utils'; import { useNavigateSettings } from '~/hooks/useNavigateSettings'; export const useGetAvailableFieldsForCalendar = () => { @@ -26,8 +30,14 @@ export const useGetAvailableFieldsForCalendar = () => { ); const availableFieldsForCalendar = - objectMetadataItem?.readableFields.filter((field) => - isFieldMetadataDateKind(field.type), + objectMetadataItem?.readableFields.filter( + (field) => + isFieldMetadataDateKind(field.type) && + isFieldMetadataSupportedInGroupBy({ + type: field.type, + name: field.name, + isSystem: field.isSystem ?? false, + }), ) ?? []; const navigate = useNavigateSettings();