From 790a8d6f939d92901011843c4eeaa98c385824d5 Mon Sep 17 00:00:00 2001 From: Marie <51697796+ijreilly@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:42:00 +0100 Subject: [PATCH] Fixes on views (#16407) Fixes - Fixes https://github.com/twentyhq/twenty/issues/15640 : we have some viewGroups that were in the past wrongly migrated; eg deleteing an enum's option did not lead to deleting the associated viewGroup. We have not cleaned that (we could do a command), but we can identify them and choose not to display them - otherwise currently they are shown as a duplicate of "No value" column - Fixes buggy edge case introduced by https://github.com/twentyhq/twenty/pull/16382 : after updating a view from Table/Calendar to Kanban, then visiting another view, when coming back to the newly updated kanban view the view groups were empty. This is due to to the view groups being optimistically created with on-the-fly computed ids when the view is updated, while we call refreshCoreViewsByObjectMetadataId() after. The view groups we get from the refresh obviously have different ids. It is not possible to indicate the ids of the view group through the update of the view as they are a side effect of the view update. --- .../useSetViewTypeFromLayoutOptionsMenu.ts | 6 ----- .../components/RecordBoardQueryEffect.tsx | 26 ++++++++++++------- ...SwitchingToKanbanViewTypeComponentState.ts | 9 ------- .../lastRecordGroupIdsComponentState.ts | 8 ++++++ .../mapViewGroupsToRecordGroupDefinitions.ts | 8 ++++++ 5 files changed, 33 insertions(+), 24 deletions(-) delete mode 100644 packages/twenty-front/src/modules/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState.ts create mode 100644 packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts index d29ec98be8..3e24902c34 100644 --- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts +++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/hooks/useSetViewTypeFromLayoutOptionsMenu.ts @@ -1,11 +1,9 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; -import { isSwitchingToKanbanViewTypeComponentState } from '@/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates'; import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState'; -import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView'; import { coreViewsState } from '@/views/states/coreViewState'; import { type GraphQLView } from '@/views/types/GraphQLView'; @@ -21,8 +19,6 @@ import { ViewCalendarLayout } from '~/generated/graphql'; export const useSetViewTypeFromLayoutOptionsMenu = () => { const { updateCurrentView } = useUpdateCurrentView(); const setRecordIndexViewType = useSetRecoilState(recordIndexViewTypeState); - const isSwitchingToKanbanViewTypeCallbackState = - useRecoilComponentCallbackState(isSwitchingToKanbanViewTypeComponentState); const { availableFieldsForKanban } = useGetAvailableFieldsForKanban(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -64,7 +60,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => { switch (viewType) { case ViewType.Kanban: { - set(isSwitchingToKanbanViewTypeCallbackState, true); if (availableFieldsForKanban.length === 0) { throw new Error('No fields for kanban - should not happen'); } @@ -159,7 +154,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => { } }, [ - isSwitchingToKanbanViewTypeCallbackState, availableFieldsForKanban, setRecordIndexViewType, updateCurrentView, diff --git a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx index a9f99eb80a..fb5ac2c501 100644 --- a/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx +++ b/packages/twenty-front/src/modules/object-record/record-board/components/RecordBoardQueryEffect.tsx @@ -1,10 +1,11 @@ import { useTriggerRecordBoardFetchMore } from '@/object-record/record-board/hooks/useTriggerRecordBoardFetchMore'; import { useTriggerRecordBoardInitialQuery } from '@/object-record/record-board/hooks/useTriggerRecordBoardInitialQuery'; -import { isSwitchingToKanbanViewTypeComponentState } from '@/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState'; import { lastRecordBoardQueryIdentifierComponentState } from '@/object-record/record-board/states/lastRecordBoardQueryIdentifierComponentState'; +import { lastRecordGroupIdsComponentState } from '@/object-record/record-board/states/lastRecordGroupIdsComponentState'; import { recordBoardCurrentGroupByQueryOffsetComponentState } from '@/object-record/record-board/states/recordBoardCurrentGroupByQueryOffsetComponentState'; import { recordBoardIsFetchingMoreComponentState } from '@/object-record/record-board/states/recordBoardIsFetchingMoreComponentState'; import { recordBoardShouldFetchMoreComponentState } from '@/object-record/record-board/states/recordBoardShouldFetchMoreComponentState'; +import { recordGroupIdsComponentState } from '@/object-record/record-group/states/recordGroupIdsComponentState'; import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; import { useRecordIndexGroupCommonQueryVariables } from '@/object-record/record-index/hooks/useRecordIndexGroupCommonQueryVariables'; @@ -16,6 +17,7 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState'; import { useEffect } from 'react'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; export const RecordBoardQueryEffect = () => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -23,10 +25,9 @@ export const RecordBoardQueryEffect = () => { const [lastRecordBoardQueryIdentifier, setLastRecordBoardQueryIdentifier] = useRecoilComponentState(lastRecordBoardQueryIdentifierComponentState); - const [ - isSwitchingToKanbanViewTypeCallbackState, - setIsSwitchingToKanbanViewTypeComponentState, - ] = useRecoilComponentState(isSwitchingToKanbanViewTypeComponentState); + const [lastRecordGroupIds, setLastRecordGroupIds] = useRecoilComponentState( + lastRecordGroupIdsComponentState, + ); const [recordIndexRecordGroupsAreInInitialLoading] = useRecoilComponentState( recordIndexRecordGroupsAreInInitialLoadingComponentState, @@ -63,13 +64,19 @@ export const RecordBoardQueryEffect = () => { const { triggerRecordBoardInitialQuery } = useTriggerRecordBoardInitialQuery(); + const recordGroupdIds = useRecoilComponentValue(recordGroupIdsComponentState); + const recordGroupIdsHaveChanged = !isDeeplyEqual( + [...recordGroupdIds].sort(), + [...lastRecordGroupIds].sort(), + ); + useEffect(() => { if ( !recordIndexRecordGroupsAreInInitialLoading && - (queryIdentifierHasChanged || isSwitchingToKanbanViewTypeCallbackState) + (queryIdentifierHasChanged || recordGroupIdsHaveChanged) ) { triggerRecordBoardInitialQuery(); - setIsSwitchingToKanbanViewTypeComponentState(false); + setLastRecordGroupIds(recordGroupdIds); } else if ( !recordIndexRecordGroupsAreInInitialLoading && shouldFetchMore && @@ -89,8 +96,9 @@ export const RecordBoardQueryEffect = () => { shouldFetchMore, recordBoardIsFetchingMore, triggerRecordBoardFetchMore, - isSwitchingToKanbanViewTypeCallbackState, - setIsSwitchingToKanbanViewTypeComponentState, + setLastRecordGroupIds, + recordGroupdIds, + recordGroupIdsHaveChanged, ]); return null; diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState.ts deleted file mode 100644 index 74bdeb91f1..0000000000 --- a/packages/twenty-front/src/modules/object-record/record-board/states/isSwitchingToKanbanViewTypeComponentState.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { ContextStoreComponentInstanceContext } from '@/context-store/states/contexts/ContextStoreComponentInstanceContext'; -import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; - -export const isSwitchingToKanbanViewTypeComponentState = - createComponentState({ - key: 'isSwitchingToKanbanViewTypeComponentState', - componentInstanceContext: ContextStoreComponentInstanceContext, - defaultValue: false, - }); diff --git a/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts new file mode 100644 index 0000000000..d9d23d6c87 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-board/states/lastRecordGroupIdsComponentState.ts @@ -0,0 +1,8 @@ +import { RecordBoardComponentInstanceContext } from '@/object-record/record-board/states/contexts/RecordBoardComponentInstanceContext'; +import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState'; + +export const lastRecordGroupIdsComponentState = createComponentState({ + key: 'lastRecordGroupIdsComponentState', + componentInstanceContext: RecordBoardComponentInstanceContext, + defaultValue: [], +}); diff --git a/packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts b/packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts index 8e6bca62ff..4ab607a760 100644 --- a/packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts +++ b/packages/twenty-front/src/modules/views/utils/mapViewGroupsToRecordGroupDefinitions.ts @@ -42,6 +42,14 @@ export const mapViewGroupsToRecordGroupDefinitions = ({ (option) => option.value === viewGroup.fieldValue, ); + if ( + !selectedOption && + isDefined(viewGroup.fieldValue) && + viewGroup.fieldValue !== '' + ) { + return null; + } + if (!selectedOption && selectFieldMetadataItem.isNullable === false) { return null; }