Refacto views (#10272)
In this huge (sorry!) PR: - introducing objectMetadataItem in contextStore instead of objectMetadataId which is more convenient - splitting some big hooks into smaller parts to avoid re-renders - removing Effects to avoid re-renders (especially onViewChange) - making the view prefetch separate from favorites to avoid re-renders - making the view prefetch load a state and add selectors on top of it to avoir re-renders As a result, the performance is WAY better (I suspect the favorite implementation to trigger a lot of re-renders unfortunately). However, we are still facing a random app freeze on view creation. I could not investigate the root cause. As this seems to be already there in the precedent release, we can move forward but this seems a urgent follow up to me ==> EDIT: I've found the root cause after a few ours of deep dive... an infinite loop in RecordTableNoRecordGroupBodyEffect... prastoin edit: close https://github.com/twentyhq/twenty/issues/10253 --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com> Co-authored-by: prastoin <paul@twenty.com>
This commit is contained in:
@ -1,18 +1,20 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentFamilyStateV2';
|
||||
import { useViewFromQueryParams } from '@/views/hooks/internal/useViewFromQueryParams';
|
||||
import { useApplyViewFiltersToCurrentRecordFilters } from '@/views/hooks/useApplyViewFiltersToCurrentRecordFilters';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
|
||||
export const QueryParamsFiltersEffect = () => {
|
||||
const { hasFiltersQueryParams, getFiltersFromQueryParams, viewIdQueryParam } =
|
||||
useViewFromQueryParams();
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const setUnsavedViewFilter = useSetRecoilComponentFamilyStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
// TODO: This whole code should be removed. currentViewId should be used directly to set the mainContextStore
|
||||
// and viewbar / view tooling should be updated to use that state contextStore state directly.
|
||||
export const QueryParamsViewIdEffect = () => {
|
||||
const [currentViewId, setCurrentViewId] = useRecoilComponentStateV2(
|
||||
currentViewIdComponentState,
|
||||
);
|
||||
|
||||
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||
mainContextStoreComponentInstanceIdState,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
mainContextStoreComponentInstanceId,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDefined(contextStoreCurrentViewId)) {
|
||||
if (currentViewId !== contextStoreCurrentViewId) {
|
||||
setCurrentViewId(contextStoreCurrentViewId);
|
||||
}
|
||||
}
|
||||
}, [contextStoreCurrentViewId, currentViewId, setCurrentViewId]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -7,6 +7,7 @@ import {
|
||||
MenuItem,
|
||||
} from 'twenty-ui';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
@ -19,7 +20,6 @@ import { useAreViewFiltersDifferentFromRecordFilters } from '@/views/hooks/useAr
|
||||
import { useAreViewSortsDifferentFromRecordSorts } from '@/views/hooks/useAreViewSortsDifferentFromRecordSorts';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
@ -44,7 +44,9 @@ export const UpdateViewButtonGroup = ({
|
||||
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { closeDropdown: closeUpdateViewButtonDropdown } = useDropdown(
|
||||
UPDATE_VIEW_BUTTON_DROPDOWN_ID,
|
||||
|
||||
@ -7,13 +7,10 @@ import { ObjectSortDropdownButton } from '@/object-record/object-sort-dropdown/c
|
||||
import { useIsPrefetchLoading } from '@/prefetch/hooks/useIsPrefetchLoading';
|
||||
import { TopBar } from '@/ui/layout/top-bar/components/TopBar';
|
||||
import { QueryParamsFiltersEffect } from '@/views/components/QueryParamsFiltersEffect';
|
||||
import { QueryParamsViewIdEffect } from '@/views/components/QueryParamsViewIdEffect';
|
||||
import { ViewBarEffect } from '@/views/components/ViewBarEffect';
|
||||
import { ViewBarFilterEffect } from '@/views/components/ViewBarFilterEffect';
|
||||
import { ViewBarPageTitle } from '@/views/components/ViewBarPageTitle';
|
||||
import { ViewBarSkeletonLoader } from '@/views/components/ViewBarSkeletonLoader';
|
||||
import { ViewBarSortEffect } from '@/views/components/ViewBarSortEffect';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { ViewPickerDropdown } from '@/views/view-picker/components/ViewPickerDropdown';
|
||||
|
||||
import { ViewsHotkeyScope } from '../types/ViewsHotkeyScope';
|
||||
@ -22,7 +19,6 @@ import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types
|
||||
import { VIEW_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ViewSortDropdownId';
|
||||
import { ObjectSortDropdownComponentInstanceContext } from '@/object-record/object-sort-dropdown/states/context/ObjectSortDropdownComponentInstanceContext';
|
||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||
import { ViewBarDetails } from './ViewBarDetails';
|
||||
|
||||
@ -30,14 +26,12 @@ export type ViewBarProps = {
|
||||
viewBarId: string;
|
||||
className?: string;
|
||||
optionsDropdownButton: ReactNode;
|
||||
onCurrentViewChange: (view: GraphQLView | undefined) => void | Promise<void>;
|
||||
};
|
||||
|
||||
export const ViewBar = ({
|
||||
viewBarId,
|
||||
className,
|
||||
optionsDropdownButton,
|
||||
onCurrentViewChange,
|
||||
}: ViewBarProps) => {
|
||||
const { objectNamePlural } = useParams();
|
||||
|
||||
@ -53,53 +47,49 @@ export const ViewBar = ({
|
||||
<ObjectSortDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_SORT_DROPDOWN_ID }}
|
||||
>
|
||||
<ViewEventContext.Provider value={{ onCurrentViewChange }}>
|
||||
<ViewBarRecordFilterEffect />
|
||||
<ViewBarEffect viewBarId={viewBarId} />
|
||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||
<ViewBarSortEffect />
|
||||
<QueryParamsFiltersEffect />
|
||||
<QueryParamsViewIdEffect />
|
||||
<ViewBarRecordFilterEffect />
|
||||
<ViewBarFilterEffect filterDropdownId={filterDropdownId} />
|
||||
<ViewBarSortEffect />
|
||||
<QueryParamsFiltersEffect />
|
||||
|
||||
<ViewBarPageTitle viewBarId={viewBarId} />
|
||||
<TopBar
|
||||
className={className}
|
||||
leftComponent={
|
||||
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
|
||||
}
|
||||
rightComponent={
|
||||
<>
|
||||
<ObjectFilterDropdownButton
|
||||
filterDropdownId={filterDropdownId}
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||
}}
|
||||
/>
|
||||
<ObjectSortDropdownButton
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||
}}
|
||||
/>
|
||||
{optionsDropdownButton}
|
||||
</>
|
||||
}
|
||||
bottomComponent={
|
||||
<ViewBarDetails
|
||||
<ViewBarPageTitle viewBarId={viewBarId} />
|
||||
<TopBar
|
||||
className={className}
|
||||
leftComponent={
|
||||
loading ? <ViewBarSkeletonLoader /> : <ViewPickerDropdown />
|
||||
}
|
||||
rightComponent={
|
||||
<>
|
||||
<ObjectFilterDropdownButton
|
||||
filterDropdownId={filterDropdownId}
|
||||
hasFilterButton
|
||||
viewBarId={viewBarId}
|
||||
objectNamePlural={objectNamePlural}
|
||||
rightComponent={
|
||||
<UpdateViewButtonGroup
|
||||
hotkeyScope={{
|
||||
scope: ViewsHotkeyScope.UpdateViewButtonDropdown,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectFilterDropdownButton,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ViewEventContext.Provider>
|
||||
<ObjectSortDropdownButton
|
||||
hotkeyScope={{
|
||||
scope: FiltersHotkeyScope.ObjectSortDropdownButton,
|
||||
}}
|
||||
/>
|
||||
{optionsDropdownButton}
|
||||
</>
|
||||
}
|
||||
bottomComponent={
|
||||
<ViewBarDetails
|
||||
filterDropdownId={filterDropdownId}
|
||||
hasFilterButton
|
||||
viewBarId={viewBarId}
|
||||
objectNamePlural={objectNamePlural}
|
||||
rightComponent={
|
||||
<UpdateViewButtonGroup
|
||||
hotkeyScope={{
|
||||
scope: ViewsHotkeyScope.UpdateViewButtonDropdown,
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</ObjectSortDropdownComponentInstanceContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
import { isUndefined } from '@sniptt/guards';
|
||||
import { useContext, useEffect, useState } from 'react';
|
||||
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewEventContext } from '@/views/events/contexts/ViewEventContext';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
type ViewBarEffectProps = {
|
||||
viewBarId: string;
|
||||
};
|
||||
|
||||
export const ViewBarEffect = ({ viewBarId }: ViewBarEffectProps) => {
|
||||
const { currentViewWithCombinedFiltersAndSorts } =
|
||||
useGetCurrentView(viewBarId);
|
||||
|
||||
const { onCurrentViewChange } = useContext(ViewEventContext);
|
||||
|
||||
const [currentViewSnapshot, setCurrentViewSnapshot] = useState<
|
||||
View | undefined
|
||||
>(undefined);
|
||||
|
||||
const isPersistingViewFields = useRecoilComponentValueV2(
|
||||
isPersistingViewFieldsComponentState,
|
||||
viewBarId,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
currentViewWithCombinedFiltersAndSorts,
|
||||
currentViewSnapshot,
|
||||
)
|
||||
) {
|
||||
if (isUndefined(currentViewWithCombinedFiltersAndSorts)) {
|
||||
setCurrentViewSnapshot(currentViewWithCombinedFiltersAndSorts);
|
||||
onCurrentViewChange?.(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isPersistingViewFields) {
|
||||
setCurrentViewSnapshot(currentViewWithCombinedFiltersAndSorts);
|
||||
onCurrentViewChange?.(currentViewWithCombinedFiltersAndSorts);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
currentViewSnapshot,
|
||||
currentViewWithCombinedFiltersAndSorts,
|
||||
isPersistingViewFields,
|
||||
onCurrentViewChange,
|
||||
]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
@ -1,38 +1,24 @@
|
||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||
import { contextStoreCurrentObjectMetadataItemComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemComponentState';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const ViewBarRecordFilterEffect = () => {
|
||||
const { records: views, isDataPrefetched } = usePrefetchedData<View>(
|
||||
PrefetchKey.AllViews,
|
||||
);
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataIdComponentState,
|
||||
);
|
||||
|
||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
objectMetadataItem.id === contextStoreCurrentObjectMetadataId,
|
||||
const contextStoreCurrentObjectMetadataItem = useRecoilComponentValueV2(
|
||||
contextStoreCurrentObjectMetadataItemComponentState,
|
||||
);
|
||||
|
||||
const [
|
||||
@ -54,14 +40,21 @@ export const ViewBarRecordFilterEffect = () => {
|
||||
);
|
||||
|
||||
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||
objectMetadataItem?.id,
|
||||
contextStoreCurrentObjectMetadataItem?.id,
|
||||
);
|
||||
|
||||
const currentView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isDataPrefetched && !hasInitializedCurrentRecordFilters) {
|
||||
const currentView = views.find((view) => view.id === currentViewId);
|
||||
|
||||
if (currentView?.objectMetadataId !== objectMetadataItem?.id) {
|
||||
if (isDefined(currentView) && !hasInitializedCurrentRecordFilters) {
|
||||
if (
|
||||
currentView.objectMetadataId !==
|
||||
contextStoreCurrentObjectMetadataItem?.id
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -76,15 +69,14 @@ export const ViewBarRecordFilterEffect = () => {
|
||||
}
|
||||
}
|
||||
}, [
|
||||
isDataPrefetched,
|
||||
views,
|
||||
currentViewId,
|
||||
setCurrentRecordFilters,
|
||||
filterableFieldMetadataItems,
|
||||
currentRecordFilters,
|
||||
hasInitializedCurrentRecordFilters,
|
||||
setHasInitializedCurrentRecordFilters,
|
||||
objectMetadataItem?.id,
|
||||
contextStoreCurrentObjectMetadataItem?.id,
|
||||
currentView,
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
||||
@ -1,8 +0,0 @@
|
||||
import { View } from '@/views/types/View';
|
||||
import { createEventContext } from '~/utils/createEventContext';
|
||||
|
||||
type ViewEventContextType = {
|
||||
onCurrentViewChange: (view: View | undefined) => void | Promise<void>;
|
||||
};
|
||||
|
||||
export const ViewEventContext = createEventContext<ViewEventContextType>();
|
||||
@ -1,20 +1,22 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { AGGREGATE_OPERATIONS } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { prefetchViewsState } from '@/prefetch/states/prefetchViewsState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { act } from 'react';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { getJestMetadataAndApolloMocksAndActionMenuWrapper } from '~/testing/jest/getJestMetadataAndApolloMocksAndContextStoreWrapper';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/mock-data/generatedMockObjectMetadataItems';
|
||||
import { useApplyCurrentViewFiltersToCurrentRecordFilters } from '../useApplyCurrentViewFiltersToCurrentRecordFilters';
|
||||
|
||||
jest.mock('@/prefetch/hooks/usePrefetchedData');
|
||||
|
||||
const mockObjectMetadataItemNameSingular = 'company';
|
||||
|
||||
describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
@ -41,18 +43,26 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
positionInViewFilterGroup: 0,
|
||||
};
|
||||
|
||||
const mockView = {
|
||||
const mockView: View = {
|
||||
id: 'view-1',
|
||||
name: 'Test View',
|
||||
objectMetadataId: mockObjectMetadataItem.id,
|
||||
viewFilters: [mockViewFilter],
|
||||
type: ViewType.Table,
|
||||
key: null,
|
||||
isCompact: false,
|
||||
viewFields: [],
|
||||
viewGroups: [],
|
||||
viewSorts: [],
|
||||
kanbanFieldMetadataId: '',
|
||||
kanbanAggregateOperation: AGGREGATE_OPERATIONS.count,
|
||||
icon: '',
|
||||
kanbanAggregateOperationFieldMetadataId: '',
|
||||
position: 0,
|
||||
__typename: 'View',
|
||||
};
|
||||
|
||||
it('should apply filters from current view', () => {
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [mockView],
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
@ -75,11 +85,12 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
mockObjectMetadataItemNameSingular,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(prefetchViewsState, [mockView]);
|
||||
},
|
||||
}),
|
||||
},
|
||||
@ -105,10 +116,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
});
|
||||
|
||||
it('should not apply filters when current view is not found', () => {
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [],
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
@ -131,11 +138,12 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
mockObjectMetadataItemNameSingular,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(prefetchViewsState, []);
|
||||
},
|
||||
}),
|
||||
},
|
||||
@ -149,15 +157,6 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
});
|
||||
|
||||
it('should handle view with empty filters', () => {
|
||||
const viewWithNoFilters = {
|
||||
...mockView,
|
||||
viewFilters: [],
|
||||
};
|
||||
|
||||
(usePrefetchedData as jest.Mock).mockReturnValue({
|
||||
records: [viewWithNoFilters],
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => {
|
||||
const { applyCurrentViewFiltersToCurrentRecordFilters } =
|
||||
@ -180,11 +179,14 @@ describe('useApplyCurrentViewFiltersToCurrentRecordFilters', () => {
|
||||
mockObjectMetadataItemNameSingular,
|
||||
onInitializeRecoilSnapshot: (snapshot) => {
|
||||
snapshot.set(
|
||||
currentViewIdComponentState.atomFamily({
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: 'instanceId',
|
||||
}),
|
||||
mockView.id,
|
||||
);
|
||||
snapshot.set(prefetchViewsState, [
|
||||
{ ...mockView, viewFilters: [] },
|
||||
]);
|
||||
},
|
||||
}),
|
||||
},
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const setCurrentRecordFilters = useSetRecoilComponentStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
@ -22,18 +21,28 @@ export const useApplyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||
const { filterableFieldMetadataItems } =
|
||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
||||
|
||||
const applyCurrentViewFiltersToCurrentRecordFilters = () => {
|
||||
const currentView = views.find((view) => view.id === currentViewId);
|
||||
const applyCurrentViewFiltersToCurrentRecordFilters = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
() => {
|
||||
const currentView = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (isDefined(currentView)) {
|
||||
setCurrentRecordFilters(
|
||||
mapViewFiltersToFilters(
|
||||
currentView.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
}
|
||||
};
|
||||
if (isDefined(currentView)) {
|
||||
setCurrentRecordFilters(
|
||||
mapViewFiltersToFilters(
|
||||
currentView.viewFilters,
|
||||
filterableFieldMetadataItems,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
[currentViewId, filterableFieldMetadataItems, setCurrentRecordFilters],
|
||||
);
|
||||
|
||||
return {
|
||||
applyCurrentViewFiltersToCurrentRecordFilters,
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
||||
@ -11,9 +14,7 @@ import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistView
|
||||
import { useGetViewFilterGroupsCombined } from '@/views/hooks/useGetCombinedViewFilterGroups';
|
||||
import { useGetViewFiltersCombined } from '@/views/hooks/useGetCombinedViewFilters';
|
||||
import { useGetViewSortsCombined } from '@/views/hooks/useGetCombinedViewSorts';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { View } from '@/views/types/View';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
@ -25,17 +26,10 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const isPersistingViewFieldsCallbackState = useRecoilComponentCallbackStateV2(
|
||||
isPersistingViewFieldsComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const { createOneRecord } = useCreateOneRecord<View>({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
@ -58,6 +52,11 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const { findManyRecords } = useLazyFindManyRecords({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
const createViewFromCurrentView = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (
|
||||
@ -84,14 +83,19 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we might instead want to get view from unsaved filters ?
|
||||
const sourceView = await getViewFromCache(currentViewId);
|
||||
const sourceView = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(sourceView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, true);
|
||||
set(isPersistingViewFieldsState, true);
|
||||
|
||||
const newView = await createOneRecord({
|
||||
id: id ?? v4(),
|
||||
@ -123,7 +127,7 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
}
|
||||
|
||||
const viewGroupsToCreate =
|
||||
objectMetadataItem?.fields
|
||||
objectMetadataItem.fields
|
||||
?.find((field) => field.id === kanbanFieldMetadataId)
|
||||
?.options?.map(
|
||||
(option, index) =>
|
||||
@ -169,21 +173,21 @@ export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
);
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, false);
|
||||
await findManyRecords();
|
||||
set(isPersistingViewFieldsState, false);
|
||||
},
|
||||
[
|
||||
objectMetadataItem,
|
||||
createViewSortRecords,
|
||||
createViewFilterRecords,
|
||||
currentViewIdCallbackState,
|
||||
createOneRecord,
|
||||
createViewFieldRecords,
|
||||
getViewSortsCombined,
|
||||
getViewFiltersCombined,
|
||||
getViewFilterGroupsCombined,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
isPersistingViewFieldsCallbackState,
|
||||
findManyRecords,
|
||||
objectMetadataItem.fields,
|
||||
createViewGroupRecords,
|
||||
getViewFilterGroupsCombined,
|
||||
getViewFiltersCombined,
|
||||
getViewSortsCombined,
|
||||
createViewSortRecords,
|
||||
createViewFilterRecords,
|
||||
createViewFilterGroupRecords,
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
@ -22,11 +22,11 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const deleteCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -50,7 +50,7 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
@ -89,7 +89,7 @@ export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
@ -26,7 +25,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const deleteCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -50,7 +49,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
@ -88,7 +87,7 @@ export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const unsavedToUpsertViewFilterGroupsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFilterGroupsComponentFamilyState,
|
||||
@ -28,7 +24,13 @@ export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
||||
const getViewFilterGroupsCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = views.find((view) => view.id === viewId);
|
||||
const view = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
@ -55,7 +57,6 @@ export const useGetViewFilterGroupsCombined = (viewBarComponentId?: string) => {
|
||||
return combinedViewFilterGroups;
|
||||
},
|
||||
[
|
||||
views,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
unsavedToUpsertViewFilterGroupsCallbackState,
|
||||
],
|
||||
|
||||
@ -1,18 +1,14 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const unsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
@ -28,7 +24,13 @@ export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
||||
const getViewFiltersCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = views.find((view) => view.id === viewId);
|
||||
const view = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
@ -55,7 +57,6 @@ export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
||||
return combinedViewFilters;
|
||||
},
|
||||
[
|
||||
views,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
|
||||
@ -1,19 +1,15 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
// TODO: fix naming
|
||||
export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
@ -29,7 +25,13 @@ export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
||||
const getViewSortsCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = views.find((view) => view.id === viewId);
|
||||
const view = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
@ -56,7 +58,6 @@ export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
||||
return combinedViewSorts;
|
||||
},
|
||||
[
|
||||
views,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentFamilyValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
@ -15,12 +17,10 @@ import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/u
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
import { getCombinedViewFilterGroups } from '@/views/utils/getCombinedViewFilterGroups';
|
||||
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
||||
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
||||
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
@ -29,16 +29,28 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
currentViewIdComponentState,
|
||||
instanceId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const viewObjectMetadataId = useRecoilComponentValueV2(
|
||||
viewObjectMetadataIdComponentState,
|
||||
instanceId,
|
||||
const indexViewId = useRecoilValue(
|
||||
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const currentViewFromViewId = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
const indexView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: indexViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
const setIsCurrentViewKeyIndex = useSetRecoilComponentStateV2(
|
||||
@ -46,25 +58,17 @@ export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const currentViewFromCurrentViewId = views.find(
|
||||
(view) => view.id === currentViewId,
|
||||
);
|
||||
const indexView = views.find(
|
||||
(view) =>
|
||||
view.key === 'INDEX' && view.objectMetadataId === viewObjectMetadataId,
|
||||
);
|
||||
|
||||
const currentView = currentViewId ? currentViewFromCurrentViewId : indexView;
|
||||
|
||||
const viewId = currentViewId ?? indexView?.id;
|
||||
const currentView = currentViewFromViewId ?? indexView;
|
||||
|
||||
useEffect(() => {
|
||||
setIsCurrentViewKeyIndex(currentView?.key === 'INDEX');
|
||||
}, [currentView, setIsCurrentViewKeyIndex]);
|
||||
|
||||
const viewsOnCurrentObject = getObjectMetadataItemViews(
|
||||
viewObjectMetadataId ?? '',
|
||||
views,
|
||||
const viewsOnCurrentObject = useRecoilValue(
|
||||
prefetchViewsFromObjectMetadataItemFamilySelector({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilters = useRecoilComponentFamilyValueV2(
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { View } from '@/views/types/View';
|
||||
|
||||
import { useMemo } from 'react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useGetCurrentViewOnly = () => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
|
||||
const currentView = useMemo(
|
||||
() => views.find((view) => view.id === currentViewId),
|
||||
[views, currentViewId],
|
||||
const currentView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: currentViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useGetRecordFromCache } from '@/object-record/cache/hooks/useGetRecordFromCache';
|
||||
import { View } from '@/views/types/View';
|
||||
|
||||
export const useGetViewFromCache = () => {
|
||||
const client = useApolloClient();
|
||||
const cache = client.cache;
|
||||
|
||||
const getRecordFromCache = useGetRecordFromCache({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const getViewFromCache = useCallback(
|
||||
async (viewId: string) => {
|
||||
return getRecordFromCache<View>(viewId, cache);
|
||||
},
|
||||
[cache, getRecordFromCache],
|
||||
);
|
||||
|
||||
return {
|
||||
getViewFromCache,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,24 @@
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useGetViewFromPrefetchState = () => {
|
||||
const getViewFromPrefetchState = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = snapshot
|
||||
.getLoadable(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: viewId,
|
||||
}),
|
||||
)
|
||||
.getValue();
|
||||
|
||||
return view;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
return {
|
||||
getViewFromPrefetchState,
|
||||
};
|
||||
};
|
||||
@ -6,14 +6,11 @@ import { getQueryVariablesFromView } from '@/views/utils/getQueryVariablesFromVi
|
||||
|
||||
export const useQueryVariablesFromActiveFieldsOfViewOrDefaultView = ({
|
||||
objectMetadataItem,
|
||||
viewId,
|
||||
}: {
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
viewId: string | null | undefined;
|
||||
}) => {
|
||||
const { view } = useViewOrDefaultViewFromPrefetchedViews({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
viewId,
|
||||
});
|
||||
|
||||
const { activeFieldMetadataItems } = useActiveFieldMetadataItems({
|
||||
|
||||
@ -1,29 +1,23 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { isPersistingViewFieldsState } from '@/views/states/isPersistingViewFieldsState';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useSaveCurrentViewFields = (viewBarComponentId?: string) => {
|
||||
export const useSaveCurrentViewFields = () => {
|
||||
const { createViewFieldRecords, updateViewFieldRecords } =
|
||||
usePersistViewFieldRecords();
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const isPersistingViewFieldsCallbackState = useRecoilComponentCallbackStateV2(
|
||||
isPersistingViewFieldsComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const saveViewFields = useRecoilCallback(
|
||||
@ -37,9 +31,9 @@ export const useSaveCurrentViewFields = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, true);
|
||||
set(isPersistingViewFieldsState, true);
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -94,13 +88,12 @@ export const useSaveCurrentViewFields = (viewBarComponentId?: string) => {
|
||||
updateViewFieldRecords(viewFieldsToUpdate),
|
||||
]);
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, false);
|
||||
set(isPersistingViewFieldsState, false);
|
||||
},
|
||||
[
|
||||
createViewFieldRecords,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
isPersistingViewFieldsCallbackState,
|
||||
getViewFromPrefetchState,
|
||||
updateViewFieldRecords,
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFilterGroupRecords } from '@/views/hooks/internal/usePersistViewFilterGroupRecords';
|
||||
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { useSaveRecordFiltersToViewFilters } from '@/views/hooks/useSaveRecordFiltersToViewFilters';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { unsavedToDeleteViewFilterGroupIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterGroupIdsComponentFamilyState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFilterGroupsComponentFamilyState } from '@/views/states/unsavedToUpsertViewFilterGroupsComponentFamilyState';
|
||||
@ -18,10 +18,10 @@ import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
export const useSaveCurrentViewFiltersAndSorts = (
|
||||
viewBarComponentId?: string,
|
||||
) => {
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
@ -77,7 +77,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const view = await getViewFromCache(viewId);
|
||||
const view = await getViewFromPrefetchState(viewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -103,7 +103,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
[
|
||||
createViewSortRecords,
|
||||
deleteViewSortRecords,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
updateViewSortRecords,
|
||||
@ -123,7 +123,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
unsavedToUpsertViewFilterGroupsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const view = await getViewFromCache(viewId);
|
||||
const view = await getViewFromPrefetchState(viewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -150,7 +150,7 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
await deleteViewFilterGroupRecords(unsavedToDeleteViewFilterGroupIds);
|
||||
},
|
||||
[
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
createViewFilterGroupRecords,
|
||||
deleteViewFilterGroupRecords,
|
||||
unsavedToDeleteViewFilterGroupIdsCallbackState,
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewGroupRecords } from '@/views/hooks/internal/usePersistViewGroupRecords';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
@ -13,10 +13,10 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
const { createViewGroupRecords, updateViewGroupRecords } =
|
||||
usePersistViewGroupRecords();
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
@ -31,7 +31,7 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -67,7 +67,11 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
{ ...viewGroupToSave, id: existingField.id },
|
||||
]);
|
||||
},
|
||||
[currentViewIdCallbackState, getViewFromCache, updateViewGroupRecords],
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromPrefetchState,
|
||||
updateViewGroupRecords,
|
||||
],
|
||||
);
|
||||
|
||||
const saveViewGroups = useRecoilCallback(
|
||||
@ -81,7 +85,7 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
const view = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (isUndefinedOrNull(view)) {
|
||||
return;
|
||||
@ -135,7 +139,7 @@ export const useSaveCurrentViewGroups = (viewBarComponentId?: string) => {
|
||||
[
|
||||
createViewGroupRecords,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
updateViewGroupRecords,
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useUpdateCurrentView = (viewBarComponentId?: string) => {
|
||||
export const useUpdateCurrentView = () => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-record/utils/convertExtendedAggregateOperationToAggregateOperation';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useUpdateView } from '@/views/hooks/useUpdateView';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useUpdateViewAggregate = () => {
|
||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
const { updateView } = useUpdateView();
|
||||
const updateViewAggregate = useCallback(
|
||||
({
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
@ -25,11 +25,11 @@ export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const upsertCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -53,7 +53,7 @@ export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
@ -120,7 +120,7 @@ export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { useGetViewFromPrefetchState } from '@/views/hooks/useGetViewFromPrefetchState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
@ -13,8 +13,7 @@ import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
contextStoreCurrentViewIdComponentState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
@ -29,7 +28,7 @@ export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
const { getViewFromPrefetchState } = useGetViewFromPrefetchState();
|
||||
|
||||
const upsertCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
@ -53,7 +52,7 @@ export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
const currentView = await getViewFromPrefetchState(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
@ -111,7 +110,7 @@ export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
getViewFromPrefetchState,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { View } from '@/views/types/View';
|
||||
import { useMemo } from 'react';
|
||||
import { prefetchIndexViewIdFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchIndexViewIdFromObjectMetadataItemFamilySelector';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const useViewOrDefaultViewFromPrefetchedViews = ({
|
||||
objectMetadataItemId,
|
||||
viewId,
|
||||
}: {
|
||||
objectMetadataItemId: string;
|
||||
viewId: string | null | undefined;
|
||||
}) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const indexViewId = useRecoilValue(
|
||||
prefetchIndexViewIdFromObjectMetadataItemFamilySelector({
|
||||
objectMetadataItemId,
|
||||
}),
|
||||
);
|
||||
|
||||
const view = useMemo(() => {
|
||||
return views.find(
|
||||
(view: View) =>
|
||||
(view.key === 'INDEX' || view?.id === viewId) &&
|
||||
view?.objectMetadataId === objectMetadataItemId,
|
||||
);
|
||||
}, [viewId, views, objectMetadataItemId]);
|
||||
const indexView = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: indexViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
return { view };
|
||||
return { view: indexView };
|
||||
};
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const currentViewIdComponentState = createComponentStateV2<
|
||||
string | undefined
|
||||
>({
|
||||
key: 'currentViewIdComponentState',
|
||||
defaultValue: undefined,
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
||||
@ -1,9 +0,0 @@
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
|
||||
export const isPersistingViewFieldsComponentState =
|
||||
createComponentStateV2<boolean>({
|
||||
key: 'isPersistingViewFieldsComponentState',
|
||||
defaultValue: false,
|
||||
componentInstanceContext: ViewComponentInstanceContext,
|
||||
});
|
||||
@ -0,0 +1,6 @@
|
||||
import { createState } from 'twenty-ui';
|
||||
|
||||
export const isPersistingViewFieldsState = createState<boolean>({
|
||||
key: 'isPersistingViewFieldsState',
|
||||
defaultValue: false,
|
||||
});
|
||||
@ -18,9 +18,8 @@ export const mapViewFiltersToFilters = (
|
||||
);
|
||||
|
||||
if (!isDefined(availableFieldMetadataItem)) {
|
||||
throw new Error(
|
||||
`Field metadata item not found for view filter ${viewFilter.id} and field metadata id ${viewFilter.fieldMetadataId}`,
|
||||
);
|
||||
// Todo: we we don't throw an error yet as we have race condition on view change
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const filterType = getFilterTypeFromFieldType(
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useContextStoreObjectMetadataItemOrThrow } from '@/context-store/hooks/useContextStoreObjectMetadataItemOrThrow';
|
||||
import { prefetchViewsFromObjectMetadataItemFamilySelector } from '@/prefetch/states/selector/prefetchViewsFromObjectMetadataItemFamilySelector';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { useGetCurrentView } from '@/views/hooks/useGetCurrentView';
|
||||
import { ViewType } from '@/views/types/ViewType';
|
||||
import { useGetAvailableFieldsForKanban } from '@/views/view-picker/hooks/useGetAvailableFieldsForKanban';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
@ -14,6 +15,7 @@ import { viewPickerKanbanFieldMetadataIdComponentState } from '@/views/view-pick
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { viewPickerSelectedIconComponentState } from '@/views/view-picker/states/viewPickerSelectedIconComponentState';
|
||||
import { viewPickerTypeComponentState } from '@/views/view-picker/states/viewPickerTypeComponentState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
export const ViewPickerContentEffect = () => {
|
||||
@ -44,7 +46,13 @@ export const ViewPickerContentEffect = () => {
|
||||
viewPickerIsPersistingComponentState,
|
||||
);
|
||||
|
||||
const { viewsOnCurrentObject } = useGetCurrentView();
|
||||
const { objectMetadataItem } = useContextStoreObjectMetadataItemOrThrow();
|
||||
const viewsOnCurrentObject = useRecoilValue(
|
||||
prefetchViewsFromObjectMetadataItemFamilySelector({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
);
|
||||
|
||||
const referenceView = viewsOnCurrentObject.find(
|
||||
(view) => view.id === viewPickerReferenceViewId,
|
||||
);
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
import { FavoriteFolderPicker } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPicker';
|
||||
import { FavoriteFolderPickerEffect } from '@/favorites/favorite-folder-picker/components/FavoriteFolderPickerEffect';
|
||||
import { FavoriteFolderPickerComponentInstanceContext } from '@/favorites/favorite-folder-picker/scopes/FavoriteFolderPickerScope';
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||
import { DropdownScope } from '@/ui/layout/dropdown/scopes/DropdownScope';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||
import { View } from '@/views/types/View';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { viewPickerReferenceViewIdComponentState } from '@/views/view-picker/states/viewPickerReferenceViewIdComponentState';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
export const ViewPickerFavoriteFoldersDropdown = () => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
const [viewPickerReferenceViewId] = useRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
);
|
||||
|
||||
const view = views.find((view) => view.id === viewPickerReferenceViewId);
|
||||
const view = useRecoilValue(
|
||||
prefetchViewFromViewIdFamilySelector({
|
||||
viewId: viewPickerReferenceViewId ?? '',
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
<FavoriteFolderPickerComponentInstanceContext
|
||||
|
||||
@ -24,6 +24,7 @@ const StyledBoldDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
export const ViewPickerListContent = () => {
|
||||
const { currentViewWithCombinedFiltersAndSorts, viewsOnCurrentObject } =
|
||||
useGetCurrentView();
|
||||
|
||||
const setViewPickerReferenceViewId = useSetRecoilComponentStateV2(
|
||||
viewPickerReferenceViewIdComponentState,
|
||||
);
|
||||
|
||||
@ -1,45 +1,31 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useDropdownV2 } from '@/ui/layout/dropdown/hooks/useDropdownV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { VIEW_PICKER_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerDropdownId';
|
||||
import { VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerKanbanFieldDropdownId';
|
||||
import { VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID } from '@/views/view-picker/constants/ViewPickerViewTypeDropdownId';
|
||||
import { useViewPickerMode } from '@/views/view-picker/hooks/useViewPickerMode';
|
||||
import { viewPickerIsPersistingComponentState } from '@/views/view-picker/states/viewPickerIsPersistingComponentState';
|
||||
import { viewPickerModeComponentState } from '@/views/view-picker/states/viewPickerModeComponentState';
|
||||
|
||||
export const useCloseAndResetViewPicker = () => {
|
||||
const { setViewPickerMode } = useViewPickerMode();
|
||||
const setViewPickerMode = useSetRecoilComponentStateV2(
|
||||
viewPickerModeComponentState,
|
||||
);
|
||||
|
||||
const setViewPickerIsPersisting = useSetRecoilComponentStateV2(
|
||||
viewPickerIsPersistingComponentState,
|
||||
);
|
||||
|
||||
const { closeDropdown: closeViewPickerDropdown } = useDropdown(
|
||||
VIEW_PICKER_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const { closeDropdown: closeKanbanFieldDropdown } = useDropdown(
|
||||
VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID,
|
||||
);
|
||||
|
||||
const { closeDropdown: closeTypeDropdown } = useDropdown(
|
||||
VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID,
|
||||
);
|
||||
const { closeDropdown } = useDropdownV2();
|
||||
|
||||
const closeAndResetViewPicker = useCallback(() => {
|
||||
setViewPickerIsPersisting(false);
|
||||
setViewPickerMode('list');
|
||||
closeKanbanFieldDropdown();
|
||||
closeTypeDropdown();
|
||||
closeViewPickerDropdown();
|
||||
}, [
|
||||
closeKanbanFieldDropdown,
|
||||
closeTypeDropdown,
|
||||
closeViewPickerDropdown,
|
||||
setViewPickerIsPersisting,
|
||||
setViewPickerMode,
|
||||
]);
|
||||
closeDropdown(VIEW_PICKER_KANBAN_FIELD_DROPDOWN_ID);
|
||||
closeDropdown(VIEW_PICKER_VIEW_TYPE_DROPDOWN_ID);
|
||||
closeDropdown(VIEW_PICKER_DROPDOWN_ID);
|
||||
}, [closeDropdown, setViewPickerIsPersisting, setViewPickerMode]);
|
||||
|
||||
return { closeAndResetViewPicker };
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user