View module refactor with atomic recoil component instance states (#6810)
This PR refactors the view module to implement utils that avoid having to create hooks to inject the scope id in the states, like `useViewStates`, each componentState will know its unique related InstanceContext (which holds the instanceId), and thus will be able to retrieve it itself. We keep the naming componentState as it reflects the fact that those states are tied to instances of a component (or its children). We introduce the instance word where it is needed, in place of scopeId for example, to precise the fact that we handle instances of component state, one for each instance of a component. For example, the currentViewId is a state that is tied to an instance of the ViewBar, but as we can switch between views, we want currentViewId to be a componentState tied to an instance of the ViewBar component. This PR also refactors view filter and sort states to fix this issue : https://github.com/twentyhq/twenty/issues/6837 and other problems involving resetting those states between page navigation. Fixes https://github.com/twentyhq/twenty/issues/6837 --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
@ -1,91 +0,0 @@
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { extractComponentReadOnlySelector } from '@/ui/utilities/state/component-state/utils/extractComponentReadOnlySelector';
|
||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
||||
import { availableFieldDefinitionsComponentState } from '@/views/states/availableFieldDefinitionsComponentState';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { entityCountInCurrentViewComponentState } from '@/views/states/entityCountInCurrentViewComponentState';
|
||||
import { isCurrentViewKeyIndexComponentState } from '@/views/states/isCurrentViewIndexComponentState';
|
||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||
import { isViewBarExpandedComponentState } from '@/views/states/isViewBarExpandedComponentState';
|
||||
import { onCurrentViewChangeComponentState } from '@/views/states/onCurrentViewChangeComponentState';
|
||||
import { canPersistViewComponentSelector } from '@/views/states/selectors/canPersistViewComponentSelector';
|
||||
import { unsavedToDeleteViewFilterIdsComponentState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentState';
|
||||
import { unsavedToDeleteViewSortIdsComponentState } from '@/views/states/unsavedToDeleteViewSortIdsComponentState';
|
||||
import { unsavedToUpsertViewFiltersComponentState } from '@/views/states/unsavedToUpsertViewFiltersComponentState';
|
||||
import { unsavedToUpsertViewSortsComponentState } from '@/views/states/unsavedToUpsertViewSortsComponentState';
|
||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||
|
||||
import { ViewScopeInternalContext } from '../../scopes/scope-internal-context/ViewScopeInternalContext';
|
||||
|
||||
export const useViewStates = (viewComponentId?: string) => {
|
||||
const componentId = useAvailableScopeIdOrThrow(
|
||||
ViewScopeInternalContext,
|
||||
viewComponentId,
|
||||
);
|
||||
|
||||
return {
|
||||
componentId,
|
||||
currentViewIdState: extractComponentState(
|
||||
currentViewIdComponentState,
|
||||
componentId,
|
||||
),
|
||||
availableFieldDefinitionsState: extractComponentState(
|
||||
availableFieldDefinitionsComponentState,
|
||||
componentId,
|
||||
),
|
||||
availableFilterDefinitionsState: extractComponentState(
|
||||
availableFilterDefinitionsComponentState,
|
||||
componentId,
|
||||
),
|
||||
availableSortDefinitionsState: extractComponentState(
|
||||
availableSortDefinitionsComponentState,
|
||||
componentId,
|
||||
),
|
||||
canPersistViewSelector: extractComponentReadOnlySelector(
|
||||
canPersistViewComponentSelector,
|
||||
componentId,
|
||||
),
|
||||
isViewBarExpandedState: extractComponentState(
|
||||
isViewBarExpandedComponentState,
|
||||
componentId,
|
||||
),
|
||||
onCurrentViewChangeState: extractComponentState(
|
||||
onCurrentViewChangeComponentState,
|
||||
componentId,
|
||||
),
|
||||
entityCountInCurrentViewState: extractComponentState(
|
||||
entityCountInCurrentViewComponentState,
|
||||
componentId,
|
||||
),
|
||||
viewObjectMetadataIdState: extractComponentState(
|
||||
viewObjectMetadataIdComponentState,
|
||||
componentId,
|
||||
),
|
||||
unsavedToUpsertViewFiltersState: extractComponentState(
|
||||
unsavedToUpsertViewFiltersComponentState,
|
||||
componentId,
|
||||
),
|
||||
unsavedToUpsertViewSortsState: extractComponentState(
|
||||
unsavedToUpsertViewSortsComponentState,
|
||||
componentId,
|
||||
),
|
||||
unsavedToDeleteViewFilterIdsState: extractComponentState(
|
||||
unsavedToDeleteViewFilterIdsComponentState,
|
||||
componentId,
|
||||
),
|
||||
unsavedToDeleteViewSortIdsState: extractComponentState(
|
||||
unsavedToDeleteViewSortIdsComponentState,
|
||||
componentId,
|
||||
),
|
||||
isPersistingViewFieldsState: extractComponentState(
|
||||
isPersistingViewFieldsComponentState,
|
||||
componentId,
|
||||
),
|
||||
isCurrentViewKeyIndexState: extractComponentState(
|
||||
isCurrentViewKeyIndexComponentState,
|
||||
componentId,
|
||||
),
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,24 @@
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
export const useChangeView = (viewBarComponentId?: string) => {
|
||||
const { resetUnsavedViewStates } =
|
||||
useResetUnsavedViewStates(viewBarComponentId);
|
||||
|
||||
const [, setSearchParams] = useSearchParams();
|
||||
|
||||
const setViewInUrl = (viewId: string) => {
|
||||
setSearchParams(() => {
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('view', viewId);
|
||||
return searchParams;
|
||||
});
|
||||
};
|
||||
|
||||
const changeView = async (viewId: string) => {
|
||||
setViewInUrl(viewId);
|
||||
resetUnsavedViewStates(viewId);
|
||||
};
|
||||
|
||||
return { changeView };
|
||||
};
|
||||
@ -1,162 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
const {
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
currentViewIdState,
|
||||
} = useViewStates(viewBarComponentId);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const upsertCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (upsertedFilter: Filter) => {
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
);
|
||||
|
||||
const currentViewId = getSnapshotValue(snapshot, currentViewIdState);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingFilterInCurrentView = currentView.viewFilters.find(
|
||||
(viewFilter) =>
|
||||
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find(
|
||||
(viewFilter) =>
|
||||
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingFilterInUnsavedFilters)) {
|
||||
const updatedFilters = unsavedToUpsertViewFilters.map((viewFilter) =>
|
||||
viewFilter.fieldMetadataId ===
|
||||
matchingFilterInUnsavedFilters.fieldMetadataId
|
||||
? { ...viewFilter, ...upsertedFilter, id: viewFilter.id }
|
||||
: viewFilter,
|
||||
);
|
||||
|
||||
set(unsavedToUpsertViewFiltersState, updatedFilters);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingFilterInCurrentView)) {
|
||||
set(unsavedToUpsertViewFiltersState, [
|
||||
...unsavedToUpsertViewFilters,
|
||||
{
|
||||
...matchingFilterInCurrentView,
|
||||
...upsertedFilter,
|
||||
id: matchingFilterInCurrentView.id,
|
||||
},
|
||||
]);
|
||||
set(
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToDeleteViewFilterIds.filter(
|
||||
(id) => id !== matchingFilterInCurrentView.id,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
set(unsavedToUpsertViewFiltersState, [
|
||||
...unsavedToUpsertViewFilters,
|
||||
{
|
||||
...upsertedFilter,
|
||||
__typename: 'ViewFilter',
|
||||
} satisfies ViewFilter,
|
||||
]);
|
||||
},
|
||||
[
|
||||
currentViewIdState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
],
|
||||
);
|
||||
const removeCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (fieldId: string) => {
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
);
|
||||
|
||||
const currentViewId = getSnapshotValue(snapshot, currentViewIdState);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingFilterInCurrentView = currentView.viewFilters.find(
|
||||
(viewFilter) => viewFilter.id === fieldId,
|
||||
);
|
||||
|
||||
const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find(
|
||||
(viewFilter) => viewFilter.id === fieldId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingFilterInUnsavedFilters)) {
|
||||
set(
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToUpsertViewFilters.filter(
|
||||
(viewFilter) => viewFilter.id !== fieldId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(matchingFilterInCurrentView)) {
|
||||
set(unsavedToDeleteViewFilterIdsState, [
|
||||
...new Set([
|
||||
...unsavedToDeleteViewFilterIds,
|
||||
matchingFilterInCurrentView.id,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentViewIdState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
upsertCombinedViewFilter,
|
||||
removeCombinedViewFilter,
|
||||
};
|
||||
};
|
||||
@ -1,159 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { Sort } from '@/object-record/object-sort-dropdown/types/Sort';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
const {
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
currentViewIdState,
|
||||
} = useViewStates(viewBarComponentId);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const upsertCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (upsertedSort: Sort) => {
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsState,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
);
|
||||
|
||||
const currentViewId = getSnapshotValue(snapshot, currentViewIdState);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingSortInCurrentView = currentView.viewSorts.find(
|
||||
(viewSort) =>
|
||||
viewSort.fieldMetadataId === upsertedSort.fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingSortInUnsavedSorts = unsavedToUpsertViewSorts.find(
|
||||
(viewSort) =>
|
||||
viewSort.fieldMetadataId === upsertedSort.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingSortInUnsavedSorts)) {
|
||||
const updatedSorts = unsavedToUpsertViewSorts.map((viewSort) =>
|
||||
viewSort.id === matchingSortInUnsavedSorts.id
|
||||
? { ...viewSort, ...upsertedSort }
|
||||
: viewSort,
|
||||
);
|
||||
|
||||
set(unsavedToUpsertViewSortsState, updatedSorts);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingSortInCurrentView)) {
|
||||
set(unsavedToUpsertViewSortsState, [
|
||||
...unsavedToUpsertViewSorts,
|
||||
{ ...matchingSortInCurrentView, ...upsertedSort },
|
||||
]);
|
||||
set(
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToDeleteViewSortIds.filter(
|
||||
(id) => id !== matchingSortInCurrentView.id,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
set(unsavedToUpsertViewSortsState, [
|
||||
...unsavedToUpsertViewSorts,
|
||||
{
|
||||
...upsertedSort,
|
||||
id: v4(),
|
||||
__typename: 'ViewSort',
|
||||
} satisfies ViewSort,
|
||||
]);
|
||||
},
|
||||
[
|
||||
currentViewIdState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
],
|
||||
);
|
||||
const removeCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (fieldMetadataId: string) => {
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsState,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
);
|
||||
|
||||
const currentViewId = getSnapshotValue(snapshot, currentViewIdState);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingSortInCurrentView = currentView.viewSorts.find(
|
||||
(viewSort) => viewSort.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingSortInUnsavedSorts = unsavedToUpsertViewSorts.find(
|
||||
(viewSort) => viewSort.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingSortInUnsavedSorts)) {
|
||||
set(
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToUpsertViewSorts.filter(
|
||||
(viewSort) => viewSort.fieldMetadataId !== fieldMetadataId,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingSortInCurrentView)) {
|
||||
set(unsavedToDeleteViewSortIdsState, [
|
||||
...new Set([
|
||||
...unsavedToDeleteViewSortIds,
|
||||
matchingSortInCurrentView.id,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentViewIdState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
],
|
||||
);
|
||||
return {
|
||||
upsertCombinedViewSort,
|
||||
removeCombinedViewSort,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,34 @@
|
||||
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
|
||||
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
|
||||
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useCreateViewFiltersAndSorts = () => {
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const { createViewSortRecords } = usePersistViewSortRecords();
|
||||
|
||||
const { createViewFilterRecords } = usePersistViewFilterRecords();
|
||||
|
||||
const createViewFiltersAndSorts = async (
|
||||
viewIdToCreateOn: string,
|
||||
filtersToCreate: ViewFilter[],
|
||||
sortsToCreate: ViewSort[],
|
||||
) => {
|
||||
const view = await getViewFromCache(viewIdToCreateOn);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await createViewSortRecords(sortsToCreate, view);
|
||||
await createViewFilterRecords(filtersToCreate, view);
|
||||
};
|
||||
|
||||
return {
|
||||
createViewFiltersAndSorts,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,122 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
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';
|
||||
import { useCreateViewFiltersAndSorts } from '@/views/hooks/useCreateViewFiltersAndSorts';
|
||||
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 { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { View } from '@/views/types/View';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
import { v4 } from 'uuid';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useCreateViewFromCurrentView = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const isPersistingViewFieldsCallbackState = useRecoilComponentCallbackStateV2(
|
||||
isPersistingViewFieldsComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const { createOneRecord } = useCreateOneRecord<View>({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const { createViewFieldRecords } = usePersistViewFieldRecords();
|
||||
|
||||
const { createViewFiltersAndSorts } = useCreateViewFiltersAndSorts();
|
||||
|
||||
const { getViewSortsCombined } = useGetViewSortsCombined(viewBarComponentId);
|
||||
const { getViewFiltersCombined } =
|
||||
useGetViewFiltersCombined(viewBarComponentId);
|
||||
|
||||
const createViewFromCurrentView = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (
|
||||
{
|
||||
id,
|
||||
name,
|
||||
icon,
|
||||
kanbanFieldMetadataId,
|
||||
type,
|
||||
}: Partial<
|
||||
Pick<
|
||||
GraphQLView,
|
||||
'id' | 'name' | 'icon' | 'kanbanFieldMetadataId' | 'type'
|
||||
>
|
||||
>,
|
||||
shouldCopyFiltersAndSorts?: boolean,
|
||||
) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Here we might instead want to get view from unsaved filters ?
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, true);
|
||||
|
||||
const newView = await createOneRecord({
|
||||
id: id ?? v4(),
|
||||
name: name ?? view.name,
|
||||
icon: icon ?? view.icon,
|
||||
key: null,
|
||||
kanbanFieldMetadataId:
|
||||
kanbanFieldMetadataId ?? view.kanbanFieldMetadataId,
|
||||
type: type ?? view.type,
|
||||
objectMetadataId: view.objectMetadataId,
|
||||
});
|
||||
|
||||
if (isUndefinedOrNull(newView)) {
|
||||
throw new Error('Failed to create view');
|
||||
}
|
||||
|
||||
await createViewFieldRecords(view.viewFields, newView);
|
||||
|
||||
if (shouldCopyFiltersAndSorts === true) {
|
||||
const sourceViewCombinedFilters = getViewFiltersCombined(view.id);
|
||||
const sourceViewCombinedSorts = getViewSortsCombined(view.id);
|
||||
|
||||
await createViewFiltersAndSorts(
|
||||
newView.id,
|
||||
sourceViewCombinedFilters,
|
||||
sourceViewCombinedSorts,
|
||||
);
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsCallbackState, false);
|
||||
},
|
||||
[
|
||||
createOneRecord,
|
||||
createViewFieldRecords,
|
||||
getViewSortsCombined,
|
||||
getViewFiltersCombined,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
isPersistingViewFieldsCallbackState,
|
||||
createViewFiltersAndSorts,
|
||||
],
|
||||
);
|
||||
|
||||
return { createViewFromCurrentView };
|
||||
};
|
||||
@ -0,0 +1,101 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
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 { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useDeleteCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
const unsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const deleteCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (fieldId: string) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingFilterInCurrentView = currentView.viewFilters.find(
|
||||
(viewFilter) => viewFilter.id === fieldId,
|
||||
);
|
||||
|
||||
const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find(
|
||||
(viewFilter) => viewFilter.id === fieldId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingFilterInUnsavedFilters)) {
|
||||
set(
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
unsavedToUpsertViewFilters.filter(
|
||||
(viewFilter) => viewFilter.id !== fieldId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isDefined(matchingFilterInCurrentView)) {
|
||||
set(
|
||||
unsavedToDeleteViewFilterIdsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
[
|
||||
...new Set([
|
||||
...unsavedToDeleteViewFilterIds,
|
||||
matchingFilterInCurrentView.id,
|
||||
]),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
deleteCombinedViewFilter,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,100 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
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 { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useDeleteCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const deleteCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (fieldMetadataId: string) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingSortInCurrentView = currentView.viewSorts.find(
|
||||
(viewSort) => viewSort.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingSortInUnsavedSorts = unsavedToUpsertViewSorts.find(
|
||||
(viewSort) => viewSort.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingSortInUnsavedSorts)) {
|
||||
set(
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }),
|
||||
unsavedToUpsertViewSorts.filter(
|
||||
(viewSort) => viewSort.fieldMetadataId !== fieldMetadataId,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingSortInCurrentView)) {
|
||||
set(
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||
[
|
||||
...new Set([
|
||||
...unsavedToDeleteViewSortIds,
|
||||
matchingSortInCurrentView.id,
|
||||
]),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
deleteCombinedViewSort,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,18 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useDeleteView = () => {
|
||||
const { deleteOneRecord } = useDeleteOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const deleteView = useRecoilCallback(
|
||||
() => async (viewId: string) => {
|
||||
await deleteOneRecord(viewId);
|
||||
},
|
||||
[deleteOneRecord],
|
||||
);
|
||||
|
||||
return { deleteView };
|
||||
};
|
||||
@ -0,0 +1,67 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
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 '~/utils/isDefined';
|
||||
|
||||
export const useGetViewFiltersCombined = (viewBarComponentId?: string) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const unsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const getViewFiltersCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = views.find((view) => view.id === viewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
`Cannot get view with id ${viewId}, because it cannot be found in client cache data.`,
|
||||
);
|
||||
}
|
||||
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const combinedViewFilters = getCombinedViewFilters(
|
||||
view.viewFilters,
|
||||
unsavedToUpsertViewFilters,
|
||||
unsavedToDeleteViewFilterIds,
|
||||
);
|
||||
|
||||
return combinedViewFilters;
|
||||
},
|
||||
[
|
||||
views,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
getViewFiltersCombined,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,68 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
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 '~/utils/isDefined';
|
||||
|
||||
// TODO: fix naming
|
||||
export const useGetViewSortsCombined = (viewBarComponentId?: string) => {
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const getViewSortsCombined = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
(viewId: string) => {
|
||||
const view = views.find((view) => view.id === viewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new Error(
|
||||
`Cannot get view with id ${viewId}, because it cannot be found in client cache data.`,
|
||||
);
|
||||
}
|
||||
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: view.id }),
|
||||
);
|
||||
|
||||
const combinedViewSorts = getCombinedViewSorts(
|
||||
view.viewSorts,
|
||||
unsavedToUpsertViewSorts,
|
||||
unsavedToDeleteViewSortIds,
|
||||
);
|
||||
|
||||
return combinedViewSorts;
|
||||
},
|
||||
[
|
||||
views,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
getViewSortsCombined,
|
||||
};
|
||||
};
|
||||
@ -1,39 +1,46 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
|
||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||
import { useAvailableScopeIdOrThrow } from '@/ui/utilities/recoil-scope/scopes-internal/hooks/useAvailableScopeId';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { ViewScopeInternalContext } from '@/views/scopes/scope-internal-context/ViewScopeInternalContext';
|
||||
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 { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
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 { combinedViewFilters } from '@/views/utils/combinedViewFilters';
|
||||
import { combinedViewSorts } from '@/views/utils/combinedViewSorts';
|
||||
import { getCombinedViewFilters } from '@/views/utils/getCombinedViewFilters';
|
||||
import { getCombinedViewSorts } from '@/views/utils/getCombinedViewSorts';
|
||||
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useGetCurrentView = (viewBarComponentId?: string) => {
|
||||
const componentId = useAvailableScopeIdOrThrow(
|
||||
ViewScopeInternalContext,
|
||||
viewBarComponentId,
|
||||
export const useGetCurrentView = (viewBarInstanceId?: string) => {
|
||||
const instanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
ViewComponentInstanceContext,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||
|
||||
const {
|
||||
currentViewIdState,
|
||||
viewObjectMetadataIdState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
isCurrentViewKeyIndexState,
|
||||
} = useViewStates(componentId);
|
||||
const currentViewId = useRecoilComponentValueV2(
|
||||
currentViewIdComponentState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const currentViewId = useRecoilValue(currentViewIdState);
|
||||
const viewObjectMetadataId = useRecoilValue(viewObjectMetadataIdState);
|
||||
const setIsCurrentViewKeyIndex = useSetRecoilState(
|
||||
isCurrentViewKeyIndexState,
|
||||
const viewObjectMetadataId = useRecoilComponentValueV2(
|
||||
viewObjectMetadataIdComponentState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const setIsCurrentViewKeyIndex = useSetRecoilComponentStateV2(
|
||||
isCurrentViewKeyIndexComponentState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const currentViewFromCurrentViewId = views.find(
|
||||
@ -46,6 +53,8 @@ export const useGetCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
const currentView = currentViewId ? currentViewFromCurrentViewId : indexView;
|
||||
|
||||
const viewId = currentViewId ?? indexView?.id;
|
||||
|
||||
useEffect(() => {
|
||||
setIsCurrentViewKeyIndex(currentView?.key === 'INDEX');
|
||||
}, [currentView, setIsCurrentViewKeyIndex]);
|
||||
@ -55,22 +64,33 @@ export const useGetCurrentView = (viewBarComponentId?: string) => {
|
||||
views,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilters = useRecoilValue(
|
||||
unsavedToUpsertViewFiltersState,
|
||||
const unsavedToUpsertViewFilters = useRecoilComponentFamilyValueV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
const unsavedToUpsertViewSorts = useRecoilValue(
|
||||
unsavedToUpsertViewSortsState,
|
||||
|
||||
const unsavedToUpsertViewSorts = useRecoilComponentFamilyValueV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
const unsavedToDeleteViewFilterIds = useRecoilValue(
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
|
||||
const unsavedToDeleteViewFilterIds = useRecoilComponentFamilyValueV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
const unsavedToDeleteViewSortIds = useRecoilValue(
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
|
||||
const unsavedToDeleteViewSortIds = useRecoilComponentFamilyValueV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
{ viewId },
|
||||
instanceId,
|
||||
);
|
||||
|
||||
if (!isDefined(currentView)) {
|
||||
return {
|
||||
componentId,
|
||||
instanceId,
|
||||
currentViewWithSavedFiltersAndSorts: undefined,
|
||||
currentViewWithCombinedFiltersAndSorts: undefined,
|
||||
viewsOnCurrentObject: viewsOnCurrentObject ?? [],
|
||||
@ -79,12 +99,12 @@ export const useGetCurrentView = (viewBarComponentId?: string) => {
|
||||
|
||||
const currentViewWithCombinedFiltersAndSorts = {
|
||||
...currentView,
|
||||
viewFilters: combinedViewFilters(
|
||||
viewFilters: getCombinedViewFilters(
|
||||
currentView.viewFilters,
|
||||
unsavedToUpsertViewFilters,
|
||||
unsavedToDeleteViewFilterIds,
|
||||
),
|
||||
viewSorts: combinedViewSorts(
|
||||
viewSorts: getCombinedViewSorts(
|
||||
currentView.viewSorts,
|
||||
unsavedToUpsertViewSorts,
|
||||
unsavedToDeleteViewSortIds,
|
||||
@ -92,9 +112,10 @@ export const useGetCurrentView = (viewBarComponentId?: string) => {
|
||||
};
|
||||
|
||||
return {
|
||||
componentId,
|
||||
instanceId,
|
||||
currentViewWithSavedFiltersAndSorts: currentView,
|
||||
currentViewWithCombinedFiltersAndSorts,
|
||||
viewsOnCurrentObject: viewsOnCurrentObject ?? [],
|
||||
currentViewId,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,165 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useCreateOneRecord } from '@/object-record/hooks/useCreateOneRecord';
|
||||
import { useDeleteOneRecord } from '@/object-record/hooks/useDeleteOneRecord';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { useResetCurrentView } from '@/views/hooks/useResetCurrentView';
|
||||
import { useSaveCurrentViewFiltersAndSorts } from '@/views/hooks/useSaveCurrentViewFiltersAndSorts';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { View } from '@/views/types/View';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
export const useHandleViews = (viewBarComponentId?: string) => {
|
||||
const { resetCurrentView } = useResetCurrentView(viewBarComponentId);
|
||||
|
||||
const { currentViewIdState, isPersistingViewFieldsState } =
|
||||
useViewStates(viewBarComponentId);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const { deleteOneRecord } = useDeleteOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const { createOneRecord } = useCreateOneRecord<View>({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const { createViewFieldRecords } = usePersistViewFieldRecords();
|
||||
const { saveCurrentViewFilterAndSorts } =
|
||||
useSaveCurrentViewFiltersAndSorts(viewBarComponentId);
|
||||
|
||||
const [, setSearchParams] = useSearchParams();
|
||||
|
||||
const removeView = useRecoilCallback(
|
||||
() => async (viewId: string) => {
|
||||
await deleteOneRecord(viewId);
|
||||
},
|
||||
[deleteOneRecord],
|
||||
);
|
||||
|
||||
const createView = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async ({
|
||||
id,
|
||||
name,
|
||||
icon,
|
||||
kanbanFieldMetadataId,
|
||||
type,
|
||||
}: Partial<
|
||||
Pick<
|
||||
GraphQLView,
|
||||
'id' | 'name' | 'icon' | 'kanbanFieldMetadataId' | 'type'
|
||||
>
|
||||
>) => {
|
||||
const currentViewId = getSnapshotValue(snapshot, currentViewIdState);
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsState, true);
|
||||
|
||||
const newView = await createOneRecord({
|
||||
id: id ?? v4(),
|
||||
name: name ?? view.name,
|
||||
icon: icon ?? view.icon,
|
||||
key: null,
|
||||
kanbanFieldMetadataId:
|
||||
kanbanFieldMetadataId ?? view.kanbanFieldMetadataId,
|
||||
type: type ?? view.type,
|
||||
objectMetadataId: view.objectMetadataId,
|
||||
});
|
||||
|
||||
if (isUndefinedOrNull(newView)) {
|
||||
throw new Error('Failed to create view');
|
||||
}
|
||||
|
||||
await createViewFieldRecords(view.viewFields, newView);
|
||||
await saveCurrentViewFilterAndSorts(newView.id);
|
||||
set(isPersistingViewFieldsState, false);
|
||||
},
|
||||
[
|
||||
createOneRecord,
|
||||
createViewFieldRecords,
|
||||
currentViewIdState,
|
||||
getViewFromCache,
|
||||
isPersistingViewFieldsState,
|
||||
saveCurrentViewFilterAndSorts,
|
||||
],
|
||||
);
|
||||
|
||||
const changeViewInUrl = useCallback(
|
||||
(viewId: string) => {
|
||||
setSearchParams(() => {
|
||||
const searchParams = new URLSearchParams();
|
||||
searchParams.set('view', viewId);
|
||||
return searchParams;
|
||||
});
|
||||
},
|
||||
[setSearchParams],
|
||||
);
|
||||
|
||||
const selectView = useRecoilCallback(
|
||||
() => async (viewId: string) => {
|
||||
changeViewInUrl(viewId);
|
||||
resetCurrentView();
|
||||
},
|
||||
[changeViewInUrl, resetCurrentView],
|
||||
);
|
||||
|
||||
const updateCurrentView = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (view: Partial<GraphQLView>) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdState)
|
||||
.getValue();
|
||||
if (isDefined(currentViewId)) {
|
||||
await updateOneRecord({
|
||||
idToUpdate: currentViewId,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
},
|
||||
[currentViewIdState, updateOneRecord],
|
||||
);
|
||||
|
||||
const updateView = useRecoilCallback(
|
||||
() => async (view: Partial<GraphQLView>) => {
|
||||
if (isDefined(view.id)) {
|
||||
await updateOneRecord({
|
||||
idToUpdate: view.id,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
},
|
||||
[updateOneRecord],
|
||||
);
|
||||
|
||||
return {
|
||||
selectView,
|
||||
updateCurrentView,
|
||||
updateView,
|
||||
removeView,
|
||||
createView,
|
||||
};
|
||||
};
|
||||
@ -1,26 +1,29 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { availableFieldDefinitionsComponentState } from '@/views/states/availableFieldDefinitionsComponentState';
|
||||
import { availableFilterDefinitionsComponentState } from '@/views/states/availableFilterDefinitionsComponentState';
|
||||
import { availableSortDefinitionsComponentState } from '@/views/states/availableSortDefinitionsComponentState';
|
||||
import { viewObjectMetadataIdComponentState } from '@/views/states/viewObjectMetadataIdComponentState';
|
||||
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
|
||||
export const useInitViewBar = (viewBarComponentId?: string) => {
|
||||
const {
|
||||
availableFieldDefinitionsState,
|
||||
availableSortDefinitionsState,
|
||||
availableFilterDefinitionsState,
|
||||
viewObjectMetadataIdState,
|
||||
} = useViewStates(viewBarComponentId);
|
||||
|
||||
const setAvailableFieldDefinitions = useSetRecoilState(
|
||||
availableFieldDefinitionsState,
|
||||
);
|
||||
const setAvailableSortDefinitions = useSetRecoilState(
|
||||
availableSortDefinitionsState,
|
||||
);
|
||||
const setAvailableFilterDefinitions = useSetRecoilState(
|
||||
availableFilterDefinitionsState,
|
||||
export const useInitViewBar = (viewBarInstanceId?: string) => {
|
||||
const setAvailableFieldDefinitions = useSetRecoilComponentStateV2(
|
||||
availableFieldDefinitionsComponentState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const setViewObjectMetadataId = useSetRecoilState(viewObjectMetadataIdState);
|
||||
const setAvailableSortDefinitions = useSetRecoilComponentStateV2(
|
||||
availableSortDefinitionsComponentState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const setAvailableFilterDefinitions = useSetRecoilComponentStateV2(
|
||||
availableFilterDefinitionsComponentState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const setViewObjectMetadataId = useSetRecoilComponentStateV2(
|
||||
viewObjectMetadataIdComponentState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
return {
|
||||
setAvailableFieldDefinitions,
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
|
||||
export const useResetCurrentView = (viewBarComponentId?: string) => {
|
||||
const {
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
} = useViewStates(viewBarComponentId);
|
||||
|
||||
const resetCurrentView = useRecoilCallback(
|
||||
({ set }) =>
|
||||
async () => {
|
||||
set(unsavedToDeleteViewFilterIdsState, []);
|
||||
set(unsavedToDeleteViewSortIdsState, []);
|
||||
set(unsavedToUpsertViewFiltersState, []);
|
||||
set(unsavedToUpsertViewSortsState, []);
|
||||
},
|
||||
[
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
resetCurrentView,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,52 @@
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useResetUnsavedViewStates = (viewBarInstanceId?: string) => {
|
||||
const setUnsavedToDeleteViewFilterIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const setUnsavedToDeleteViewSortIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const setUnsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
viewBarInstanceId,
|
||||
);
|
||||
|
||||
const resetUnsavedViewStates = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(viewId: string) => {
|
||||
set(setUnsavedToDeleteViewFilterIdsCallbackState({ viewId }), []);
|
||||
set(setUnsavedToDeleteViewSortIdsCallbackState({ viewId }), []);
|
||||
set(setUnsavedToUpsertViewFiltersCallbackState({ viewId }), []);
|
||||
set(unsavedToUpsertViewSortsCallbackState({ viewId }), []);
|
||||
},
|
||||
[
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
setUnsavedToUpsertViewFiltersCallbackState,
|
||||
setUnsavedToDeleteViewSortIdsCallbackState,
|
||||
setUnsavedToDeleteViewFilterIdsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
resetUnsavedViewStates,
|
||||
};
|
||||
};
|
||||
@ -1,8 +1,10 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFieldRecords } from '@/views/hooks/internal/usePersistViewFieldRecords';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { isPersistingViewFieldsComponentState } from '@/views/states/isPersistingViewFieldsComponentState';
|
||||
import { ViewField } from '@/views/types/ViewField';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
@ -14,21 +16,28 @@ export const useSaveCurrentViewFields = (viewBarComponentId?: string) => {
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const { isPersistingViewFieldsState, currentViewIdState } =
|
||||
useViewStates(viewBarComponentId);
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const isPersistingViewFieldsCallbackState = useRecoilComponentCallbackStateV2(
|
||||
isPersistingViewFieldsComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const saveViewFields = useRecoilCallback(
|
||||
({ set, snapshot }) =>
|
||||
async (viewFieldsToSave: ViewField[]) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdState)
|
||||
.getLoadable(currentViewIdCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(isPersistingViewFieldsState, true);
|
||||
set(isPersistingViewFieldsCallbackState, true);
|
||||
|
||||
const view = await getViewFromCache(currentViewId);
|
||||
|
||||
@ -85,13 +94,13 @@ export const useSaveCurrentViewFields = (viewBarComponentId?: string) => {
|
||||
updateViewFieldRecords(viewFieldsToUpdate),
|
||||
]);
|
||||
|
||||
set(isPersistingViewFieldsState, false);
|
||||
set(isPersistingViewFieldsCallbackState, false);
|
||||
},
|
||||
[
|
||||
createViewFieldRecords,
|
||||
currentViewIdState,
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
isPersistingViewFieldsState,
|
||||
isPersistingViewFieldsCallbackState,
|
||||
updateViewFieldRecords,
|
||||
],
|
||||
);
|
||||
|
||||
@ -1,11 +1,16 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { getSnapshotValue } from '@/ui/utilities/recoil-scope/utils/getSnapshotValue';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { usePersistViewFilterRecords } from '@/views/hooks/internal/usePersistViewFilterRecords';
|
||||
import { usePersistViewSortRecords } from '@/views/hooks/internal/usePersistViewSortRecords';
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useGetViewFromCache } from '@/views/hooks/useGetViewFromCache';
|
||||
import { useResetCurrentView } from '@/views/hooks/useResetCurrentView';
|
||||
import { useResetUnsavedViewStates } from '@/views/hooks/useResetUnsavedViewStates';
|
||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
||||
import { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
|
||||
@ -14,13 +19,34 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
) => {
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const {
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
currentViewIdState,
|
||||
} = useViewStates(viewBarComponentId);
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const {
|
||||
createViewSortRecords,
|
||||
@ -34,19 +60,20 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
deleteViewFilterRecords,
|
||||
} = usePersistViewFilterRecords();
|
||||
|
||||
const { resetCurrentView } = useResetCurrentView(viewBarComponentId);
|
||||
const { resetUnsavedViewStates } =
|
||||
useResetUnsavedViewStates(viewBarComponentId);
|
||||
|
||||
const saveViewSorts = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewId: string) => {
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const view = await getViewFromCache(viewId);
|
||||
@ -76,8 +103,8 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
createViewSortRecords,
|
||||
deleteViewSortRecords,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewSortIdsState,
|
||||
unsavedToUpsertViewSortsState,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
updateViewSortRecords,
|
||||
],
|
||||
);
|
||||
@ -87,12 +114,12 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
async (viewId: string) => {
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToDeleteViewFilterIdsCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId }),
|
||||
);
|
||||
|
||||
const view = await getViewFromCache(viewId);
|
||||
@ -123,28 +150,36 @@ export const useSaveCurrentViewFiltersAndSorts = (
|
||||
createViewFilterRecords,
|
||||
deleteViewFilterRecords,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewFilterIdsState,
|
||||
unsavedToUpsertViewFiltersState,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
updateViewFilterRecords,
|
||||
],
|
||||
);
|
||||
|
||||
const saveCurrentViewFilterAndSorts = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (viewId?: string) => {
|
||||
async (viewIdFromProps?: string) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdState)
|
||||
.getLoadable(currentViewIdCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await saveViewFilters(viewId ?? currentViewId);
|
||||
await saveViewSorts(viewId ?? currentViewId);
|
||||
resetCurrentView();
|
||||
const viewId = viewIdFromProps ?? currentViewId;
|
||||
|
||||
await saveViewFilters(viewId);
|
||||
await saveViewSorts(viewId);
|
||||
|
||||
resetUnsavedViewStates(viewId);
|
||||
},
|
||||
[currentViewIdState, resetCurrentView, saveViewFilters, saveViewSorts],
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
resetUnsavedViewStates,
|
||||
saveViewFilters,
|
||||
saveViewSorts,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@ -1,12 +1,10 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
|
||||
import { useViewStates } from '@/views/hooks/internal/useViewStates';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { entityCountInCurrentViewComponentState } from '@/views/states/entityCountInCurrentViewComponentState';
|
||||
|
||||
export const useSetRecordCountInCurrentView = (viewBarComponentId?: string) => {
|
||||
const { entityCountInCurrentViewState } = useViewStates(viewBarComponentId);
|
||||
|
||||
const setEntityCountInCurrentView = useSetRecoilState(
|
||||
entityCountInCurrentViewState,
|
||||
const setEntityCountInCurrentView = useSetRecoilComponentStateV2(
|
||||
entityCountInCurrentViewComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
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 '~/utils/isDefined';
|
||||
|
||||
export const useUpdateCurrentView = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const updateCurrentView = useRecoilCallback(
|
||||
({ snapshot }) =>
|
||||
async (view: Partial<GraphQLView>) => {
|
||||
const currentViewId = snapshot
|
||||
.getLoadable(currentViewIdCallbackState)
|
||||
.getValue();
|
||||
|
||||
if (isDefined(currentViewId)) {
|
||||
await updateOneRecord({
|
||||
idToUpdate: currentViewId,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
},
|
||||
[currentViewIdCallbackState, updateOneRecord],
|
||||
);
|
||||
|
||||
return {
|
||||
updateCurrentView,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,27 @@
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||
import { GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
|
||||
export const useUpdateView = () => {
|
||||
const { updateOneRecord } = useUpdateOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.View,
|
||||
});
|
||||
|
||||
const updateView = useRecoilCallback(
|
||||
() => async (view: Partial<GraphQLView>) => {
|
||||
if (isDefined(view.id)) {
|
||||
await updateOneRecord({
|
||||
idToUpdate: view.id,
|
||||
updateOneRecordInput: view,
|
||||
});
|
||||
}
|
||||
},
|
||||
[updateOneRecord],
|
||||
);
|
||||
|
||||
return {
|
||||
updateView,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,131 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||
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 { unsavedToDeleteViewFilterIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewFilterIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewFiltersComponentFamilyState } from '@/views/states/unsavedToUpsertViewFiltersComponentFamilyState';
|
||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useUpsertCombinedViewFilters = (viewBarComponentId?: string) => {
|
||||
const unsavedToUpsertViewFiltersCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewFiltersComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewFilterIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const upsertCombinedViewFilter = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (upsertedFilter: Filter) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewFilters = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewFilterIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewFilterIdsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingFilterInCurrentView = currentView.viewFilters.find(
|
||||
(viewFilter) =>
|
||||
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingFilterInUnsavedFilters = unsavedToUpsertViewFilters.find(
|
||||
(viewFilter) =>
|
||||
viewFilter.fieldMetadataId === upsertedFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingFilterInUnsavedFilters)) {
|
||||
const updatedFilters = unsavedToUpsertViewFilters.map((viewFilter) =>
|
||||
viewFilter.fieldMetadataId ===
|
||||
matchingFilterInUnsavedFilters.fieldMetadataId
|
||||
? { ...viewFilter, ...upsertedFilter, id: viewFilter.id }
|
||||
: viewFilter,
|
||||
);
|
||||
|
||||
set(
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
updatedFilters,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingFilterInCurrentView)) {
|
||||
set(
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
[
|
||||
...unsavedToUpsertViewFilters,
|
||||
{
|
||||
...matchingFilterInCurrentView,
|
||||
...upsertedFilter,
|
||||
id: matchingFilterInCurrentView.id,
|
||||
},
|
||||
],
|
||||
);
|
||||
set(
|
||||
unsavedToDeleteViewFilterIdsCallbackState({
|
||||
viewId: currentViewId,
|
||||
}),
|
||||
unsavedToDeleteViewFilterIds.filter(
|
||||
(id) => id !== matchingFilterInCurrentView.id,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
set(
|
||||
unsavedToUpsertViewFiltersCallbackState({ viewId: currentViewId }),
|
||||
[
|
||||
...unsavedToUpsertViewFilters,
|
||||
{
|
||||
...upsertedFilter,
|
||||
__typename: 'ViewFilter',
|
||||
} satisfies ViewFilter,
|
||||
],
|
||||
);
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewFilterIdsCallbackState,
|
||||
unsavedToUpsertViewFiltersCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
upsertCombinedViewFilter,
|
||||
};
|
||||
};
|
||||
@ -0,0 +1,123 @@
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
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 { unsavedToDeleteViewSortIdsComponentFamilyState } from '@/views/states/unsavedToDeleteViewSortIdsComponentFamilyState';
|
||||
import { unsavedToUpsertViewSortsComponentFamilyState } from '@/views/states/unsavedToUpsertViewSortsComponentFamilyState';
|
||||
import { ViewSort } from '@/views/types/ViewSort';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const useUpsertCombinedViewSorts = (viewBarComponentId?: string) => {
|
||||
const currentViewIdCallbackState = useRecoilComponentCallbackStateV2(
|
||||
currentViewIdComponentState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSortsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToUpsertViewSortsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIdsCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
unsavedToDeleteViewSortIdsComponentFamilyState,
|
||||
viewBarComponentId,
|
||||
);
|
||||
|
||||
const { getViewFromCache } = useGetViewFromCache();
|
||||
|
||||
const upsertCombinedViewSort = useRecoilCallback(
|
||||
({ snapshot, set }) =>
|
||||
async (upsertedSort: Sort) => {
|
||||
const currentViewId = getSnapshotValue(
|
||||
snapshot,
|
||||
currentViewIdCallbackState,
|
||||
);
|
||||
|
||||
const unsavedToUpsertViewSorts = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
const unsavedToDeleteViewSortIds = getSnapshotValue(
|
||||
snapshot,
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||
);
|
||||
|
||||
if (!currentViewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentView = await getViewFromCache(currentViewId);
|
||||
|
||||
if (!currentView) {
|
||||
return;
|
||||
}
|
||||
|
||||
const matchingSortInCurrentView = currentView.viewSorts.find(
|
||||
(viewSort) =>
|
||||
viewSort.fieldMetadataId === upsertedSort.fieldMetadataId,
|
||||
);
|
||||
|
||||
const matchingSortInUnsavedSorts = unsavedToUpsertViewSorts.find(
|
||||
(viewSort) =>
|
||||
viewSort.fieldMetadataId === upsertedSort.fieldMetadataId,
|
||||
);
|
||||
|
||||
if (isDefined(matchingSortInUnsavedSorts)) {
|
||||
const updatedSorts = unsavedToUpsertViewSorts.map((viewSort) =>
|
||||
viewSort.id === matchingSortInUnsavedSorts.id
|
||||
? { ...viewSort, ...upsertedSort }
|
||||
: viewSort,
|
||||
);
|
||||
|
||||
set(
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }),
|
||||
updatedSorts,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(matchingSortInCurrentView)) {
|
||||
set(
|
||||
unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }),
|
||||
[
|
||||
...unsavedToUpsertViewSorts,
|
||||
{ ...matchingSortInCurrentView, ...upsertedSort },
|
||||
],
|
||||
);
|
||||
set(
|
||||
unsavedToDeleteViewSortIdsCallbackState({ viewId: currentViewId }),
|
||||
unsavedToDeleteViewSortIds.filter(
|
||||
(id) => id !== matchingSortInCurrentView.id,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
set(unsavedToUpsertViewSortsCallbackState({ viewId: currentViewId }), [
|
||||
...unsavedToUpsertViewSorts,
|
||||
{
|
||||
...upsertedSort,
|
||||
id: v4(),
|
||||
__typename: 'ViewSort',
|
||||
} satisfies ViewSort,
|
||||
]);
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
getViewFromCache,
|
||||
unsavedToDeleteViewSortIdsCallbackState,
|
||||
unsavedToUpsertViewSortsCallbackState,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
upsertCombinedViewSort,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user