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.
This commit is contained in:
Marie
2025-12-09 11:42:00 +01:00
committed by GitHub
parent ec2b6ae691
commit 790a8d6f93
5 changed files with 33 additions and 24 deletions
@@ -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,
@@ -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;
@@ -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<boolean>({
key: 'isSwitchingToKanbanViewTypeComponentState',
componentInstanceContext: ContextStoreComponentInstanceContext,
defaultValue: false,
});
@@ -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<string[]>({
key: 'lastRecordGroupIdsComponentState',
componentInstanceContext: RecordBoardComponentInstanceContext,
defaultValue: [],
});
@@ -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;
}