diff --git a/packages/twenty-front/src/modules/object-metadata/hooks/useUpdateOneObjectMetadataItem.ts b/packages/twenty-front/src/modules/object-metadata/hooks/useUpdateOneObjectMetadataItem.ts index ef266b710a..6a0247e0dd 100644 --- a/packages/twenty-front/src/modules/object-metadata/hooks/useUpdateOneObjectMetadataItem.ts +++ b/packages/twenty-front/src/modules/object-metadata/hooks/useUpdateOneObjectMetadataItem.ts @@ -9,6 +9,7 @@ import { import { UPDATE_ONE_OBJECT_METADATA_ITEM } from '../graphql/mutations'; import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; // TODO: Slice the Apollo store synchronously in the update function instead of subscribing, so we can use update after read in the same function call export const useUpdateOneObjectMetadataItem = () => { @@ -20,6 +21,9 @@ export const useUpdateOneObjectMetadataItem = () => { const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems('network-only'); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); + const updateOneObjectMetadataItem = async ({ idToUpdate, updatePayload, @@ -35,6 +39,7 @@ export const useUpdateOneObjectMetadataItem = () => { }); await refreshObjectMetadataItems(); + await refreshCoreViewsByObjectMetadataId(idToUpdate); return result; }; diff --git a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx index 3296cdf23f..da5a53eafb 100644 --- a/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx +++ b/packages/twenty-front/src/modules/views/components/UpdateViewButtonGroup.tsx @@ -16,7 +16,7 @@ import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAr import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts'; import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly'; import { useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter } from '@/views/hooks/useIsViewAnyFieldFilterDifferentFromCurrentAnyFieldFilter'; -import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts'; import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId'; import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode'; @@ -36,7 +36,8 @@ const StyledContainer = styled.div` export const UpdateViewButtonGroup = () => { const { saveCurrentViewFilterAndSorts } = useSaveCurrentViewFiltersAndSorts(); - const { refreshCoreViews } = useRefreshCoreViews(); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -78,7 +79,7 @@ export const UpdateViewButtonGroup = () => { const handleUpdateViewClick = async () => { await saveCurrentViewFilterAndSorts(); - await refreshCoreViews(objectMetadataItem.id); + await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); }; const { hasFiltersQueryParams } = useViewFromQueryParams(); diff --git a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts index 65d51d43de..4424036781 100644 --- a/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useCreateViewFromCurrentView.ts @@ -13,7 +13,7 @@ import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePers import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords'; import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords'; import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords'; -import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState'; import { type GraphQLView } from '@/views/types/GraphQLView'; import { type ViewGroup } from '@/views/types/ViewGroup'; @@ -54,7 +54,8 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { const { objectMetadataItem } = useRecordIndexContextOrThrow(); - const { refreshCoreViews } = useRefreshCoreViews(); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); const currentRecordFilterGroups = useRecoilComponentValue( currentRecordFilterGroupsComponentState, @@ -212,7 +213,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { await createViewSortRecords(viewSortsToCreate, { id: newViewId }); } - await refreshCoreViews(objectMetadataItem.id); + await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); set(isPersistingViewFieldsState, false); return newViewId; @@ -231,7 +232,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => { createViewFilterGroupRecords, createViewFilterRecords, createViewSortRecords, - refreshCoreViews, + refreshCoreViewsByObjectMetadataId, ], ); diff --git a/packages/twenty-front/src/modules/views/hooks/useDeleteView.ts b/packages/twenty-front/src/modules/views/hooks/useDeleteView.ts index fd2b3be3f9..88d80776c1 100644 --- a/packages/twenty-front/src/modules/views/hooks/useDeleteView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useDeleteView.ts @@ -1,12 +1,13 @@ import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector'; -import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { useDeleteCoreViewMutation } from '~/generated/graphql'; export const useDeleteView = () => { const [deleteCoreViewMutation] = useDeleteCoreViewMutation(); - const { refreshCoreViews } = useRefreshCoreViews(); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); const deleteView = useRecoilCallback( ({ snapshot }) => @@ -29,9 +30,9 @@ export const useDeleteView = () => { }, }); - await refreshCoreViews(currentView.objectMetadataId); + await refreshCoreViewsByObjectMetadataId(currentView.objectMetadataId); }, - [deleteCoreViewMutation, refreshCoreViews], + [deleteCoreViewMutation, refreshCoreViewsByObjectMetadataId], ); return { deleteView }; diff --git a/packages/twenty-front/src/modules/views/hooks/useRefreshAllCoreViews.ts b/packages/twenty-front/src/modules/views/hooks/useRefreshAllCoreViews.ts new file mode 100644 index 0000000000..2cbc5715ec --- /dev/null +++ b/packages/twenty-front/src/modules/views/hooks/useRefreshAllCoreViews.ts @@ -0,0 +1,42 @@ +import { coreViewsState } from '@/views/states/coreViewState'; +import { type FetchPolicy, useApolloClient } from '@apollo/client'; +import { useRecoilCallback } from 'recoil'; +import { isDefined } from 'twenty-shared/utils'; +import { type FindManyCoreViewsQuery } from '~/generated/graphql'; +import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; +import { FIND_MANY_CORE_VIEWS } from '../graphql/queries/findManyCoreViews'; + +export const useRefreshAllCoreViews = ( + fetchPolicy: FetchPolicy = 'network-only', +) => { + const client = useApolloClient(); + + const refreshAllCoreViews = useRecoilCallback( + ({ snapshot, set }) => + async () => { + const result = await client.query({ + query: FIND_MANY_CORE_VIEWS, + variables: {}, + fetchPolicy, + }); + + const currentCoreViews = snapshot + .getLoadable(coreViewsState) + .getValue(); + + if ( + isDefined(result.data?.getCoreViews) && + !isDeeplyEqual(currentCoreViews, result.data.getCoreViews) + ) { + set(coreViewsState, result.data.getCoreViews); + } + + return result.data?.getCoreViews; + }, + [client, fetchPolicy], + ); + + return { + refreshAllCoreViews, + }; +}; diff --git a/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViews.ts b/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts similarity index 87% rename from packages/twenty-front/src/modules/views/hooks/useRefreshCoreViews.ts rename to packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts index a737ced2a7..6eadeff93e 100644 --- a/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViews.ts +++ b/packages/twenty-front/src/modules/views/hooks/useRefreshCoreViewsByObjectMetadataId.ts @@ -4,10 +4,10 @@ import { isDefined } from 'twenty-shared/utils'; import { useFindManyCoreViewsLazyQuery } from '~/generated/graphql'; import { isDeeplyEqual } from '~/utils/isDeeplyEqual'; -export const useRefreshCoreViews = () => { +export const useRefreshCoreViewsByObjectMetadataId = () => { const [findManyCoreViewsLazy] = useFindManyCoreViewsLazyQuery(); - const refreshCoreViews = useRecoilCallback( + const refreshCoreViewsByObjectMetadataId = useRecoilCallback( ({ snapshot, set }) => async (objectMetadataId: string) => { const result = await findManyCoreViewsLazy({ @@ -37,6 +37,6 @@ export const useRefreshCoreViews = () => { ); return { - refreshCoreViews, + refreshCoreViewsByObjectMetadataId, }; }; diff --git a/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts b/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts index 583f23aefe..f0f4405015 100644 --- a/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useUpdateCurrentView.ts @@ -3,7 +3,7 @@ import { useRecoilCallback } from 'recoil'; import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState'; import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector'; import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState'; -import { useRefreshCoreViews } from '@/views/hooks/useRefreshCoreViews'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { type GraphQLView } from '@/views/types/GraphQLView'; import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore'; import { isDefined } from 'twenty-shared/utils'; @@ -14,7 +14,8 @@ export const useUpdateCurrentView = () => { contextStoreCurrentViewIdComponentState, ); - const { refreshCoreViews } = useRefreshCoreViews(); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); const [updateOneCoreView] = useUpdateCoreViewMutation(); @@ -46,10 +47,16 @@ export const useUpdateCurrentView = () => { input, }, }); - await refreshCoreViews(currentView.objectMetadataId); + await refreshCoreViewsByObjectMetadataId( + currentView.objectMetadataId, + ); } }, - [currentViewIdCallbackState, refreshCoreViews, updateOneCoreView], + [ + currentViewIdCallbackState, + refreshCoreViewsByObjectMetadataId, + updateOneCoreView, + ], ); return { diff --git a/packages/twenty-front/src/modules/views/hooks/useUpdateView.ts b/packages/twenty-front/src/modules/views/hooks/useUpdateView.ts index 148de67881..095e0d0eaf 100644 --- a/packages/twenty-front/src/modules/views/hooks/useUpdateView.ts +++ b/packages/twenty-front/src/modules/views/hooks/useUpdateView.ts @@ -1,15 +1,16 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext'; +import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId'; import { type GraphQLView } from '@/views/types/GraphQLView'; import { convertUpdateViewInputToCore } from '@/views/utils/convertUpdateViewInputToCore'; import { useRecoilCallback } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; import { useUpdateCoreViewMutation } from '~/generated/graphql'; -import { useRefreshCoreViews } from './useRefreshCoreViews'; export const useUpdateView = () => { const [updateOneCoreView] = useUpdateCoreViewMutation(); - const { refreshCoreViews } = useRefreshCoreViews(); + const { refreshCoreViewsByObjectMetadataId } = + useRefreshCoreViewsByObjectMetadataId(); const { objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -26,9 +27,13 @@ export const useUpdateView = () => { }, }); - await refreshCoreViews(objectMetadataItem.id); + await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id); }, - [objectMetadataItem.id, refreshCoreViews, updateOneCoreView], + [ + objectMetadataItem.id, + refreshCoreViewsByObjectMetadataId, + updateOneCoreView, + ], ); return { diff --git a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx index 557a69d565..8519c4e5c4 100644 --- a/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx +++ b/packages/twenty-front/src/pages/settings/profile/appearance/components/LocalePicker.tsx @@ -8,6 +8,7 @@ import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util import { Select } from '@/ui/input/components/Select'; import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems'; +import { useRefreshAllCoreViews } from '@/views/hooks/useRefreshAllCoreViews'; import { useLingui } from '@lingui/react/macro'; import { enUS } from 'date-fns/locale'; import { APP_LOCALES } from 'twenty-shared/translations'; @@ -36,6 +37,8 @@ export const LocalePicker = () => { const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems('network-only'); + const { refreshAllCoreViews } = useRefreshAllCoreViews('network-only'); + const updateWorkspaceMember = async (changedFields: any) => { if (!currentWorkspaceMember?.id) { throw new Error('User is not logged in'); @@ -74,6 +77,7 @@ export const LocalePicker = () => { console.log('Failed to save locale to localStorage:', error); } await refreshObjectMetadataItems(); + await refreshAllCoreViews(); }; const unsortedLocaleOptions: Array<{