Simplify last visited (#10259)
In this PR, I'm simplifying the lastVisitedView / Object logic: - removing fallback logic as it's not useful - splitting hooks into smaller hooks (to avoir re-renders) - removing componentState on those states that are global
This commit is contained in:
@ -48,6 +48,7 @@ export const MainContextStoreProvider = () => {
|
|||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const viewIdQueryParam = searchParams.get('viewId');
|
const viewIdQueryParam = searchParams.get('viewId');
|
||||||
|
|
||||||
|
// Todo: this is triggering a lot of re-renders as we update the viewFields, we should introduce a state here
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||||
|
|
||||||
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||||
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
|
import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId';
|
||||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
@ -22,15 +22,11 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
setMainContextStoreComponentInstanceId,
|
setMainContextStoreComponentInstanceId,
|
||||||
] = useRecoilState(mainContextStoreComponentInstanceIdState);
|
] = useRecoilState(mainContextStoreComponentInstanceIdState);
|
||||||
|
|
||||||
const { getLastVisitedViewIdFromObjectNamePlural, setLastVisitedView } =
|
const { setLastVisitedViewForObjectMetadataNamePlural } =
|
||||||
useLastVisitedView();
|
useSetLastVisitedViewForObjectMetadataNamePlural();
|
||||||
|
|
||||||
const { lastVisitedObjectMetadataItemId, setLastVisitedObjectMetadataItem } =
|
const { setLastVisitedObjectMetadataId } =
|
||||||
useLastVisitedObjectMetadataItem();
|
useSetLastVisitedObjectMetadataId();
|
||||||
|
|
||||||
const lastVisitedViewId = getLastVisitedViewIdFromObjectNamePlural(
|
|
||||||
objectMetadataItem.namePlural,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [contextStoreCurrentViewId, setContextStoreCurrentViewId] =
|
const [contextStoreCurrentViewId, setContextStoreCurrentViewId] =
|
||||||
useRecoilComponentStateV2(
|
useRecoilComponentStateV2(
|
||||||
@ -60,16 +56,14 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewId !== lastVisitedViewId) {
|
setLastVisitedViewForObjectMetadataNamePlural({
|
||||||
setLastVisitedView({
|
objectNamePlural: objectMetadataItem.namePlural,
|
||||||
objectNamePlural: objectMetadataItem.namePlural,
|
viewId: viewId,
|
||||||
viewId: viewId,
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objectMetadataItem.id !== lastVisitedObjectMetadataItemId) {
|
setLastVisitedObjectMetadataId({
|
||||||
setLastVisitedObjectMetadataItem(objectMetadataItem.namePlural);
|
objectMetadataItemId: objectMetadataItem.id,
|
||||||
}
|
});
|
||||||
|
|
||||||
if (contextStoreCurrentViewId !== viewId) {
|
if (contextStoreCurrentViewId !== viewId) {
|
||||||
setContextStoreCurrentViewId(viewId);
|
setContextStoreCurrentViewId(viewId);
|
||||||
@ -77,16 +71,14 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
}, [
|
}, [
|
||||||
contextStoreCurrentObjectMetadataId,
|
contextStoreCurrentObjectMetadataId,
|
||||||
contextStoreCurrentViewId,
|
contextStoreCurrentViewId,
|
||||||
lastVisitedObjectMetadataItemId,
|
|
||||||
lastVisitedViewId,
|
|
||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
mainContextStoreComponentInstanceIdToSet,
|
mainContextStoreComponentInstanceIdToSet,
|
||||||
objectMetadataItem,
|
objectMetadataItem,
|
||||||
objectMetadataItem.namePlural,
|
objectMetadataItem.namePlural,
|
||||||
setContextStoreCurrentObjectMetadataId,
|
setContextStoreCurrentObjectMetadataId,
|
||||||
setContextStoreCurrentViewId,
|
setContextStoreCurrentViewId,
|
||||||
setLastVisitedObjectMetadataItem,
|
setLastVisitedObjectMetadataId,
|
||||||
setLastVisitedView,
|
setLastVisitedViewForObjectMetadataNamePlural,
|
||||||
setMainContextStoreComponentInstanceId,
|
setMainContextStoreComponentInstanceId,
|
||||||
viewId,
|
viewId,
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
|
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||||
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
import { ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
@ -16,8 +16,9 @@ export const useDefaultHomePagePath = () => {
|
|||||||
const { activeObjectMetadataItems, alphaSortedActiveObjectMetadataItems } =
|
const { activeObjectMetadataItems, alphaSortedActiveObjectMetadataItems } =
|
||||||
useFilteredObjectMetadataItems();
|
useFilteredObjectMetadataItems();
|
||||||
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
const { records: views } = usePrefetchedData<View>(PrefetchKey.AllViews);
|
||||||
const { lastVisitedObjectMetadataItemId } =
|
const lastVisitedObjectMetadataItemId = useRecoilValue(
|
||||||
useLastVisitedObjectMetadataItem();
|
lastVisitedObjectMetadataItemIdState,
|
||||||
|
);
|
||||||
|
|
||||||
const getActiveObjectMetadataItemMatchingId = useCallback(
|
const getActiveObjectMetadataItemMatchingId = useCallback(
|
||||||
(objectMetadataId: string) => {
|
(objectMetadataId: string) => {
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|
||||||
import { lastVisitedObjectMetadataItemIdStateSelector } from '@/navigation/states/selectors/lastVisitedObjectMetadataItemIdStateSelector';
|
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
|
||||||
import { AppPath } from '@/types/AppPath';
|
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
|
||||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
|
||||||
|
|
||||||
export const useLastVisitedObjectMetadataItem = () => {
|
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
|
||||||
const scopeId = currentWorkspace?.id ?? '';
|
|
||||||
|
|
||||||
const lastVisitedObjectMetadataItemIdState = extractComponentState(
|
|
||||||
lastVisitedObjectMetadataItemIdStateSelector,
|
|
||||||
scopeId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [lastVisitedObjectMetadataItemId, setLastVisitedObjectMetadataItemId] =
|
|
||||||
useRecoilState(lastVisitedObjectMetadataItemIdState);
|
|
||||||
|
|
||||||
const {
|
|
||||||
findActiveObjectMetadataItemByNamePlural,
|
|
||||||
alphaSortedActiveObjectMetadataItems,
|
|
||||||
} = useFilteredObjectMetadataItems();
|
|
||||||
|
|
||||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
|
||||||
navigationMemorizedUrlState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setFallbackForLastVisitedObjectMetadataItem = (
|
|
||||||
objectMetadataItemId: string,
|
|
||||||
) => {
|
|
||||||
const isDeactivateDefault = isDeeplyEqual(
|
|
||||||
lastVisitedObjectMetadataItemId,
|
|
||||||
objectMetadataItemId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [newFallbackObjectMetadataItem] =
|
|
||||||
alphaSortedActiveObjectMetadataItems.filter(
|
|
||||||
(item) => item.id !== objectMetadataItemId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDeactivateDefault) {
|
|
||||||
setLastVisitedObjectMetadataItemId(newFallbackObjectMetadataItem.id);
|
|
||||||
setNavigationMemorizedUrl(
|
|
||||||
getAppPath(AppPath.RecordIndexPage, {
|
|
||||||
objectNamePlural: newFallbackObjectMetadataItem.namePlural,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const setLastVisitedObjectMetadataItem = (objectNamePlural: string) => {
|
|
||||||
const fallbackObjectMetadataItem =
|
|
||||||
findActiveObjectMetadataItemByNamePlural(objectNamePlural);
|
|
||||||
|
|
||||||
if (isDefined(fallbackObjectMetadataItem)) {
|
|
||||||
setLastVisitedObjectMetadataItemId(fallbackObjectMetadataItem.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
lastVisitedObjectMetadataItemId,
|
|
||||||
setLastVisitedObjectMetadataItem,
|
|
||||||
setFallbackForLastVisitedObjectMetadataItem,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@ -1,54 +1,15 @@
|
|||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||||
import { lastVisitedViewPerObjectMetadataItemStateSelector } from '@/navigation/states/selectors/lastVisitedViewPerObjectMetadataItemStateSelector';
|
|
||||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||||
import { extractComponentState } from '@/ui/utilities/state/component-state/utils/extractComponentState';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
export const useLastVisitedView = () => {
|
export const useLastVisitedView = () => {
|
||||||
const currentWorkspace = useRecoilValue(currentWorkspaceState);
|
const lastVisitedViewPerObjectMetadataItem = useRecoilValue(
|
||||||
const scopeId = currentWorkspace?.id ?? '';
|
lastVisitedViewPerObjectMetadataItemState,
|
||||||
|
|
||||||
const lastVisitedViewPerObjectMetadataItemState = extractComponentState(
|
|
||||||
lastVisitedViewPerObjectMetadataItemStateSelector,
|
|
||||||
scopeId,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const [
|
|
||||||
lastVisitedViewPerObjectMetadataItem,
|
|
||||||
setLastVisitedViewPerObjectMetadataItem,
|
|
||||||
] = useRecoilState(lastVisitedViewPerObjectMetadataItemState);
|
|
||||||
|
|
||||||
const { findActiveObjectMetadataItemByNamePlural } =
|
const { findActiveObjectMetadataItemByNamePlural } =
|
||||||
useFilteredObjectMetadataItems();
|
useFilteredObjectMetadataItems();
|
||||||
|
|
||||||
const setFallbackForLastVisitedView = (objectMetadataItemId: string) => {
|
|
||||||
/* ...{} allows us to pass value as undefined to remove that particular key
|
|
||||||
even though param type is of type Record<string,string> */
|
|
||||||
|
|
||||||
setLastVisitedViewPerObjectMetadataItem({
|
|
||||||
...{},
|
|
||||||
[objectMetadataItemId]: undefined,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const setLastVisitedView = ({
|
|
||||||
objectNamePlural,
|
|
||||||
viewId,
|
|
||||||
}: {
|
|
||||||
objectNamePlural: string;
|
|
||||||
viewId: string;
|
|
||||||
}) => {
|
|
||||||
const objectMetadataItem =
|
|
||||||
findActiveObjectMetadataItemByNamePlural(objectNamePlural);
|
|
||||||
|
|
||||||
if (isDefined(objectMetadataItem)) {
|
|
||||||
setLastVisitedViewPerObjectMetadataItem({
|
|
||||||
[objectMetadataItem.id]: viewId,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getLastVisitedViewIdFromObjectNamePlural = (
|
const getLastVisitedViewIdFromObjectNamePlural = (
|
||||||
objectNamePlural: string,
|
objectNamePlural: string,
|
||||||
) => {
|
) => {
|
||||||
@ -65,9 +26,7 @@ export const useLastVisitedView = () => {
|
|||||||
return lastVisitedViewPerObjectMetadataItem?.[objectMetadataItemId];
|
return lastVisitedViewPerObjectMetadataItem?.[objectMetadataItemId];
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
setLastVisitedView,
|
|
||||||
getLastVisitedViewIdFromObjectNamePlural,
|
getLastVisitedViewIdFromObjectNamePlural,
|
||||||
getLastVisitedViewIdFromObjectMetadataItemId,
|
getLastVisitedViewIdFromObjectMetadataItemId,
|
||||||
setFallbackForLastVisitedView,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
||||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
export const useOpenSettingsMenu = () => {
|
export const useOpenSettingsMenu = () => {
|
||||||
const [, setIsNavigationDrawerExpanded] = useRecoilState(
|
const setIsNavigationDrawerExpanded = useSetRecoilState(
|
||||||
isNavigationDrawerExpandedState,
|
isNavigationDrawerExpandedState,
|
||||||
);
|
);
|
||||||
const [, setCurrentMobileNavigationDrawer] = useRecoilState(
|
const setCurrentMobileNavigationDrawer = useSetRecoilState(
|
||||||
currentMobileNavigationDrawerState,
|
currentMobileNavigationDrawerState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const useSetLastVisitedObjectMetadataId = () => {
|
||||||
|
const setLastVisitedObjectMetadataId = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
({ objectMetadataItemId }: { objectMetadataItemId: string }) => {
|
||||||
|
const objectMetadataItems = snapshot
|
||||||
|
.getLoadable(objectMetadataItemsState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
|
(item) => item.id === objectMetadataItemId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastVisitedObjectMetadataItemId = snapshot
|
||||||
|
.getLoadable(lastVisitedObjectMetadataItemIdState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
if (
|
||||||
|
isDefined(objectMetadataItem) &&
|
||||||
|
lastVisitedObjectMetadataItemId !== objectMetadataItemId
|
||||||
|
) {
|
||||||
|
set(lastVisitedObjectMetadataItemIdState, objectMetadataItemId);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setLastVisitedObjectMetadataId,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||||
|
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||||
|
import { useLazyPrefetchedData } from '@/prefetch/hooks/useLazyPrefetchData';
|
||||||
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
|
export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||||
|
const { records: views, findManyRecords } = useLazyPrefetchedData<View>(
|
||||||
|
PrefetchKey.AllViews,
|
||||||
|
);
|
||||||
|
|
||||||
|
const setLastVisitedViewForObjectMetadataNamePlural = useRecoilCallback(
|
||||||
|
({ set, snapshot }) =>
|
||||||
|
async ({
|
||||||
|
objectNamePlural,
|
||||||
|
viewId,
|
||||||
|
}: {
|
||||||
|
objectNamePlural: string;
|
||||||
|
viewId: string;
|
||||||
|
}) => {
|
||||||
|
await findManyRecords();
|
||||||
|
|
||||||
|
const view = views.find((view: View) => view.id === viewId);
|
||||||
|
|
||||||
|
const objectMetadataItems = snapshot
|
||||||
|
.getLoadable(objectMetadataItemsState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
|
(item) => item.namePlural === objectNamePlural,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(objectMetadataItem) || !isDefined(view)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (view.objectMetadataId !== objectMetadataItem.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastVisitedViewPerObjectMetadataItem = snapshot
|
||||||
|
.getLoadable(lastVisitedViewPerObjectMetadataItemState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
const lastVisitedViewId =
|
||||||
|
lastVisitedViewPerObjectMetadataItem?.[objectMetadataItem?.id];
|
||||||
|
|
||||||
|
if (isDefined(objectMetadataItem) && lastVisitedViewId !== viewId) {
|
||||||
|
set(lastVisitedViewPerObjectMetadataItemState, {
|
||||||
|
...lastVisitedViewPerObjectMetadataItem,
|
||||||
|
[objectMetadataItem.id]: viewId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[findManyRecords, views],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setLastVisitedViewForObjectMetadataNamePlural,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -1,10 +1,7 @@
|
|||||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
import { createState } from 'twenty-ui';
|
||||||
import { localStorageEffect } from '~/utils/recoil-effects';
|
import { localStorageEffect } from '~/utils/recoil-effects';
|
||||||
|
|
||||||
export const lastVisitedObjectMetadataItemIdState = createComponentState<Record<
|
export const lastVisitedObjectMetadataItemIdState = createState<string | null>({
|
||||||
string,
|
|
||||||
string
|
|
||||||
> | null>({
|
|
||||||
key: 'lastVisitedObjectMetadataItemIdState',
|
key: 'lastVisitedObjectMetadataItemIdState',
|
||||||
defaultValue: null,
|
defaultValue: null,
|
||||||
effects: [localStorageEffect()],
|
effects: [localStorageEffect()],
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
import { createState } from 'twenty-ui';
|
||||||
import { localStorageEffect } from '~/utils/recoil-effects';
|
import { localStorageEffect } from '~/utils/recoil-effects';
|
||||||
|
|
||||||
export const lastVisitedViewPerObjectMetadataItemState =
|
export const lastVisitedViewPerObjectMetadataItemState = createState<Record<
|
||||||
createComponentState<Record<string, string> | null>({
|
string,
|
||||||
key: 'lastVisitedViewPerObjectMetadataItemState',
|
string
|
||||||
defaultValue: null,
|
> | null>({
|
||||||
effects: [localStorageEffect()],
|
key: 'lastVisitedViewPerObjectMetadataItemState',
|
||||||
});
|
defaultValue: null,
|
||||||
|
effects: [localStorageEffect()],
|
||||||
|
});
|
||||||
|
|||||||
@ -1,24 +0,0 @@
|
|||||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
|
||||||
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
|
|
||||||
|
|
||||||
export const lastVisitedObjectMetadataItemIdStateSelector =
|
|
||||||
createComponentSelector<string | null>({
|
|
||||||
key: 'lastVisitedObjectMetadataItemIdStateSelector',
|
|
||||||
get:
|
|
||||||
({ scopeId }: { scopeId: string }) =>
|
|
||||||
({ get }) => {
|
|
||||||
const state = get(lastVisitedObjectMetadataItemIdState({ scopeId }));
|
|
||||||
return state?.['last_visited_object']
|
|
||||||
? state['last_visited_object']
|
|
||||||
: null;
|
|
||||||
},
|
|
||||||
set:
|
|
||||||
({ scopeId }: { scopeId: string }) =>
|
|
||||||
({ set }, newValue) => {
|
|
||||||
set(lastVisitedObjectMetadataItemIdState({ scopeId }), {
|
|
||||||
...(typeof newValue === 'string' && {
|
|
||||||
last_visited_object: newValue,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@ -1,34 +0,0 @@
|
|||||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
|
||||||
import { createComponentSelector } from '@/ui/utilities/state/component-state/utils/createComponentSelector';
|
|
||||||
import { isDefined } from 'twenty-shared';
|
|
||||||
|
|
||||||
export const lastVisitedViewPerObjectMetadataItemStateSelector =
|
|
||||||
createComponentSelector<Record<string, string> | null>({
|
|
||||||
key: 'lastVisitedViewPerObjectMetadataItemStateSelector',
|
|
||||||
get:
|
|
||||||
({ scopeId }: { scopeId: string }) =>
|
|
||||||
({ get }) => {
|
|
||||||
const state = get(
|
|
||||||
lastVisitedViewPerObjectMetadataItemState({ scopeId }),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isDefined(state?.['last_visited_object'])) {
|
|
||||||
const { last_visited_object: _last_visited_object, ...rest } = state;
|
|
||||||
return rest;
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
},
|
|
||||||
set:
|
|
||||||
({ scopeId }: { scopeId: string }) =>
|
|
||||||
({ set, get }, newValue) => {
|
|
||||||
const currentLastVisitedViewPerObjectMetadataItems = get(
|
|
||||||
lastVisitedViewPerObjectMetadataItemStateSelector({ scopeId }),
|
|
||||||
);
|
|
||||||
|
|
||||||
set(lastVisitedViewPerObjectMetadataItemState({ scopeId }), {
|
|
||||||
...currentLastVisitedViewPerObjectMetadataItems,
|
|
||||||
...newValue,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@ -1,4 +1,6 @@
|
|||||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
|
import { mainContextStoreComponentInstanceIdState } from '@/context-store/states/mainContextStoreComponentInstanceId';
|
||||||
|
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
@ -7,9 +9,11 @@ import { NavigationDrawerItem } from '@/ui/navigation/navigation-drawer/componen
|
|||||||
import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer';
|
import { NavigationDrawerItemsCollapsableContainer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerItemsCollapsableContainer';
|
||||||
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
||||||
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
import { getObjectMetadataItemViews } from '@/views/utils/getObjectMetadataItemViews';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { AnimatedExpandableContainer, useIcons } from 'twenty-ui';
|
import { AnimatedExpandableContainer, useIcons } from 'twenty-ui';
|
||||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
import { getAppPath } from '~/utils/navigation/getAppPath';
|
||||||
|
|
||||||
@ -27,20 +31,29 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
|
|||||||
views,
|
views,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getIcon } = useIcons();
|
const mainContextStoreComponentInstanceId = useRecoilValue(
|
||||||
const currentPath = useLocation().pathname;
|
mainContextStoreComponentInstanceIdState,
|
||||||
const { getLastVisitedViewIdFromObjectMetadataItemId } = useLastVisitedView();
|
|
||||||
|
|
||||||
const lastVisitedViewId = getLastVisitedViewIdFromObjectMetadataItemId(
|
|
||||||
objectMetadataItem.id,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const viewId = lastVisitedViewId ?? objectMetadataViews[0]?.id;
|
const contextStoreCurrentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
mainContextStoreComponentInstanceId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastVisitedViewPerObjectMetadataItem = useRecoilValue(
|
||||||
|
lastVisitedViewPerObjectMetadataItemState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const lastVisitedViewId =
|
||||||
|
lastVisitedViewPerObjectMetadataItem?.[objectMetadataItem.id];
|
||||||
|
|
||||||
|
const { getIcon } = useIcons();
|
||||||
|
const currentPath = useLocation().pathname;
|
||||||
|
|
||||||
const navigationPath = getAppPath(
|
const navigationPath = getAppPath(
|
||||||
AppPath.RecordIndexPage,
|
AppPath.RecordIndexPage,
|
||||||
{ objectNamePlural: objectMetadataItem.namePlural },
|
{ objectNamePlural: objectMetadataItem.namePlural },
|
||||||
viewId ? { viewId } : undefined,
|
lastVisitedViewId ? { viewId: lastVisitedViewId } : undefined,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isActive =
|
const isActive =
|
||||||
@ -62,7 +75,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedSubItemIndex = sortedObjectMetadataViews.findIndex(
|
const selectedSubItemIndex = sortedObjectMetadataViews.findIndex(
|
||||||
(view) => viewId === view.id,
|
(view) => contextStoreCurrentViewId === view.id,
|
||||||
);
|
);
|
||||||
|
|
||||||
const subItemArrayLength = sortedObjectMetadataViews.length;
|
const subItemArrayLength = sortedObjectMetadataViews.length;
|
||||||
@ -93,7 +106,7 @@ export const NavigationDrawerItemForObjectMetadataItem = ({
|
|||||||
{ objectNamePlural: objectMetadataItem.namePlural },
|
{ objectNamePlural: objectMetadataItem.namePlural },
|
||||||
{ viewId: view.id },
|
{ viewId: view.id },
|
||||||
)}
|
)}
|
||||||
active={viewId === view.id}
|
active={contextStoreCurrentViewId === view.id}
|
||||||
subItemState={getNavigationSubItemLeftAdornment({
|
subItemState={getNavigationSubItemLeftAdornment({
|
||||||
index,
|
index,
|
||||||
arrayLength: subItemArrayLength,
|
arrayLength: subItemArrayLength,
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
|
export const useFilterableFieldMetadataItems = (
|
||||||
|
objectMetadataItemId: string,
|
||||||
|
) => {
|
||||||
|
const filterableFieldMetadataItems = useRecoilValue(
|
||||||
|
availableFieldMetadataItemsForFilterFamilySelector({
|
||||||
|
objectMetadataItemId,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
return { filterableFieldMetadataItems };
|
||||||
|
};
|
||||||
@ -1,14 +1,11 @@
|
|||||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
export const useFilterableFieldMetadataItemsInRecordIndexContext = () => {
|
export const useFilterableFieldMetadataItemsInRecordIndexContext = () => {
|
||||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
|
|
||||||
const filterableFieldMetadataItems = useRecoilValue(
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||||
availableFieldMetadataItemsForFilterFamilySelector({
|
objectMetadataItem.id,
|
||||||
objectMetadataItemId: objectMetadataItem.id,
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return { filterableFieldMetadataItems };
|
return { filterableFieldMetadataItems };
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import { RecordIndexActionMenu } from '@/action-menu/components/RecordIndexActio
|
|||||||
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
import { ContextStoreCurrentViewTypeEffect } from '@/context-store/components/ContextStoreCurrentViewTypeEffect';
|
||||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
import { useSetRecordGroup } from '@/object-record/record-group/hooks/useSetRecordGroup';
|
||||||
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
import { RecordIndexFiltersToContextStoreEffect } from '@/object-record/record-index/components/RecordIndexFiltersToContextStoreEffect';
|
||||||
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
import { RecordIndexTableContainerEffect } from '@/object-record/record-index/components/RecordIndexTableContainerEffect';
|
||||||
@ -180,8 +180,9 @@ export const RecordIndexContainer = () => {
|
|||||||
contextStoreTargetedRecordsRuleComponentState,
|
contextStoreTargetedRecordsRuleComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { filterableFieldMetadataItems } =
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
objectMetadataItem.id,
|
||||||
|
);
|
||||||
|
|
||||||
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
||||||
FeatureFlagKey.IsCommandMenuV2Enabled,
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
||||||
|
|||||||
@ -0,0 +1,30 @@
|
|||||||
|
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||||
|
import { RecordGqlOperationFilter } from '@/object-record/graphql/types/RecordGqlOperationFilter';
|
||||||
|
import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRecords';
|
||||||
|
import { ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||||
|
import { PREFETCH_CONFIG } from '@/prefetch/constants/PrefetchConfig';
|
||||||
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
|
|
||||||
|
export const useLazyPrefetchedData = <T extends ObjectRecord>(
|
||||||
|
prefetchKey: PrefetchKey,
|
||||||
|
filter?: RecordGqlOperationFilter,
|
||||||
|
) => {
|
||||||
|
const { operationSignatureFactory, objectNameSingular } =
|
||||||
|
PREFETCH_CONFIG[prefetchKey];
|
||||||
|
|
||||||
|
const { objectMetadataItem } = useObjectMetadataItem({
|
||||||
|
objectNameSingular,
|
||||||
|
});
|
||||||
|
|
||||||
|
const recordGqlFields =
|
||||||
|
operationSignatureFactory({ objectMetadataItem }).fields ?? filter;
|
||||||
|
const { records, findManyRecords } = useLazyFindManyRecords<T>({
|
||||||
|
objectNameSingular: objectNameSingular,
|
||||||
|
recordGqlFields,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
findManyRecords,
|
||||||
|
records,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -9,8 +9,6 @@ import {
|
|||||||
useIcons,
|
useIcons,
|
||||||
} from 'twenty-ui';
|
} from 'twenty-ui';
|
||||||
|
|
||||||
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
|
|
||||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
|
import { SettingsSummaryCard } from '@/settings/components/SettingsSummaryCard';
|
||||||
import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag';
|
import { SettingsDataModelObjectTypeTag } from '@/settings/data-model/objects/components/SettingsDataModelObjectTypeTag';
|
||||||
@ -44,12 +42,8 @@ export const SettingsObjectSummaryCard = ({
|
|||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { getIcon } = useIcons();
|
const { getIcon } = useIcons();
|
||||||
const Icon = getIcon(iconKey);
|
const Icon = getIcon(iconKey);
|
||||||
const objectMetadataItemId = objectMetadataItem.id;
|
|
||||||
|
|
||||||
const { closeDropdown } = useDropdown(dropdownId);
|
const { closeDropdown } = useDropdown(dropdownId);
|
||||||
const { setFallbackForLastVisitedView } = useLastVisitedView();
|
|
||||||
const { setFallbackForLastVisitedObjectMetadataItem } =
|
|
||||||
useLastVisitedObjectMetadataItem();
|
|
||||||
|
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
onEdit();
|
onEdit();
|
||||||
@ -57,8 +51,6 @@ export const SettingsObjectSummaryCard = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleDeactivate = () => {
|
const handleDeactivate = () => {
|
||||||
setFallbackForLastVisitedObjectMetadataItem(objectMetadataItemId);
|
|
||||||
setFallbackForLastVisitedView(objectMetadataItemId);
|
|
||||||
onDeactivate();
|
onDeactivate();
|
||||||
closeDropdown();
|
closeDropdown();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -3,10 +3,8 @@ import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
|||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
import { FormProvider, useForm } from 'react-hook-form';
|
import { FormProvider, useForm } from 'react-hook-form';
|
||||||
import { Button, H2Title, IconArchive, Section } from 'twenty-ui';
|
import { Button, H2Title, IconArchive, Section } from 'twenty-ui';
|
||||||
import { z, ZodError } from 'zod';
|
import { ZodError, z } from 'zod';
|
||||||
|
|
||||||
import { useLastVisitedObjectMetadataItem } from '@/navigation/hooks/useLastVisitedObjectMetadataItem';
|
|
||||||
import { useLastVisitedView } from '@/navigation/hooks/useLastVisitedView';
|
|
||||||
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
|
import { useUpdateOneObjectMetadataItem } from '@/object-metadata/hooks/useUpdateOneObjectMetadataItem';
|
||||||
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
import { RecordFieldValueSelectorContextProvider } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext';
|
||||||
import {
|
import {
|
||||||
@ -17,11 +15,9 @@ import {
|
|||||||
import { settingsDataModelObjectIdentifiersFormSchema } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm';
|
import { settingsDataModelObjectIdentifiersFormSchema } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectIdentifiersForm';
|
||||||
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
|
import { SettingsDataModelObjectSettingsFormCard } from '@/settings/data-model/objects/forms/components/SettingsDataModelObjectSettingsFormCard';
|
||||||
import { settingsUpdateObjectInputSchema } from '@/settings/data-model/validation-schemas/settingsUpdateObjectInputSchema';
|
import { settingsUpdateObjectInputSchema } from '@/settings/data-model/validation-schemas/settingsUpdateObjectInputSchema';
|
||||||
import { AppPath } from '@/types/AppPath';
|
|
||||||
import { SettingsPath } from '@/types/SettingsPath';
|
import { SettingsPath } from '@/types/SettingsPath';
|
||||||
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
|
||||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||||
import { navigationMemorizedUrlState } from '@/ui/navigation/states/navigationMemorizedUrlState';
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import pick from 'lodash.pick';
|
import pick from 'lodash.pick';
|
||||||
@ -29,7 +25,6 @@ import { useSetRecoilState } from 'recoil';
|
|||||||
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
|
||||||
import { updatedObjectNamePluralState } from '~/pages/settings/data-model/states/updatedObjectNamePluralState';
|
import { updatedObjectNamePluralState } from '~/pages/settings/data-model/states/updatedObjectNamePluralState';
|
||||||
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/compute-metadata-name-from-label.utils';
|
||||||
import { getAppPath } from '~/utils/navigation/getAppPath';
|
|
||||||
|
|
||||||
const objectEditFormSchema = z
|
const objectEditFormSchema = z
|
||||||
.object({})
|
.object({})
|
||||||
@ -63,9 +58,6 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { updateOneObjectMetadataItem } = useUpdateOneObjectMetadataItem();
|
const { updateOneObjectMetadataItem } = useUpdateOneObjectMetadataItem();
|
||||||
const { lastVisitedObjectMetadataItemId } =
|
|
||||||
useLastVisitedObjectMetadataItem();
|
|
||||||
const { getLastVisitedViewIdFromObjectMetadataItemId } = useLastVisitedView();
|
|
||||||
|
|
||||||
const formConfig = useForm<SettingsDataModelObjectEditFormValues>({
|
const formConfig = useForm<SettingsDataModelObjectEditFormValues>({
|
||||||
mode: 'onTouched',
|
mode: 'onTouched',
|
||||||
@ -73,10 +65,6 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
|||||||
});
|
});
|
||||||
const { isDirty } = formConfig.formState;
|
const { isDirty } = formConfig.formState;
|
||||||
|
|
||||||
const setNavigationMemorizedUrl = useSetRecoilState(
|
|
||||||
navigationMemorizedUrlState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const getUpdatePayload = (
|
const getUpdatePayload = (
|
||||||
formValues: SettingsDataModelObjectEditFormValues,
|
formValues: SettingsDataModelObjectEditFormValues,
|
||||||
) => {
|
) => {
|
||||||
@ -143,19 +131,6 @@ export const ObjectSettings = ({ objectMetadataItem }: ObjectSettingsProps) => {
|
|||||||
|
|
||||||
formConfig.reset(undefined, { keepValues: true });
|
formConfig.reset(undefined, { keepValues: true });
|
||||||
|
|
||||||
if (lastVisitedObjectMetadataItemId === objectMetadataItem.id) {
|
|
||||||
const lastVisitedView = getLastVisitedViewIdFromObjectMetadataItemId(
|
|
||||||
objectMetadataItem.id,
|
|
||||||
);
|
|
||||||
setNavigationMemorizedUrl(
|
|
||||||
getAppPath(
|
|
||||||
AppPath.RecordIndexPage,
|
|
||||||
{ objectNamePlural: objectNamePluralForRedirection },
|
|
||||||
{ viewId: lastVisitedView },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
navigate(SettingsPath.ObjectDetail, {
|
navigate(SettingsPath.ObjectDetail, {
|
||||||
objectNamePlural: objectNamePluralForRedirection,
|
objectNamePlural: objectNamePluralForRedirection,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { contextStoreCurrentObjectMetadataIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataIdComponentState';
|
||||||
|
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 { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
import { usePrefetchedData } from '@/prefetch/hooks/usePrefetchedData';
|
||||||
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
import { PrefetchKey } from '@/prefetch/types/PrefetchKey';
|
||||||
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
import { useRecoilComponentFamilyStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { currentViewIdComponentState } from '@/views/states/currentViewIdComponentState';
|
|
||||||
import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
||||||
import { View } from '@/views/types/View';
|
import { View } from '@/views/types/View';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
|
import { useRecoilValue } from 'recoil';
|
||||||
import { isDefined } from 'twenty-shared';
|
import { isDefined } from 'twenty-shared';
|
||||||
|
|
||||||
export const ViewBarRecordFilterEffect = () => {
|
export const ViewBarRecordFilterEffect = () => {
|
||||||
@ -17,7 +20,20 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
PrefetchKey.AllViews,
|
PrefetchKey.AllViews,
|
||||||
);
|
);
|
||||||
|
|
||||||
const currentViewId = useRecoilComponentValueV2(currentViewIdComponentState);
|
const currentViewId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentViewIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const contextStoreCurrentObjectMetadataId = useRecoilComponentValueV2(
|
||||||
|
contextStoreCurrentObjectMetadataIdComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const objectMetadataItems = useRecoilValue(objectMetadataItemsState);
|
||||||
|
|
||||||
|
const objectMetadataItem = objectMetadataItems.find(
|
||||||
|
(objectMetadataItem) =>
|
||||||
|
objectMetadataItem.id === contextStoreCurrentObjectMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
const [
|
const [
|
||||||
hasInitializedCurrentRecordFilters,
|
hasInitializedCurrentRecordFilters,
|
||||||
@ -25,7 +41,7 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
] = useRecoilComponentFamilyStateV2(
|
] = useRecoilComponentFamilyStateV2(
|
||||||
hasInitializedCurrentRecordFiltersComponentFamilyState,
|
hasInitializedCurrentRecordFiltersComponentFamilyState,
|
||||||
{
|
{
|
||||||
viewId: currentViewId,
|
viewId: currentViewId ?? undefined,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -37,13 +53,18 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { filterableFieldMetadataItems } =
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
objectMetadataItem?.id,
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDataPrefetched && !hasInitializedCurrentRecordFilters) {
|
if (isDataPrefetched && !hasInitializedCurrentRecordFilters) {
|
||||||
const currentView = views.find((view) => view.id === currentViewId);
|
const currentView = views.find((view) => view.id === currentViewId);
|
||||||
|
|
||||||
|
if (currentView?.objectMetadataId !== objectMetadataItem?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isDefined(currentView)) {
|
if (isDefined(currentView)) {
|
||||||
setCurrentRecordFilters(
|
setCurrentRecordFilters(
|
||||||
mapViewFiltersToFilters(
|
mapViewFiltersToFilters(
|
||||||
@ -63,6 +84,7 @@ export const ViewBarRecordFilterEffect = () => {
|
|||||||
currentRecordFilters,
|
currentRecordFilters,
|
||||||
hasInitializedCurrentRecordFilters,
|
hasInitializedCurrentRecordFilters,
|
||||||
setHasInitializedCurrentRecordFilters,
|
setHasInitializedCurrentRecordFilters,
|
||||||
|
objectMetadataItem?.id,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
import { useFilterableFieldMetadataItems } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItems';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
|
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { ViewFilter } from '@/views/types/ViewFilter';
|
import { ViewFilter } from '@/views/types/ViewFilter';
|
||||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||||
@ -9,8 +10,11 @@ export const useApplyViewFiltersToCurrentRecordFilters = () => {
|
|||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { filterableFieldMetadataItems } =
|
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
|
||||||
|
const { filterableFieldMetadataItems } = useFilterableFieldMetadataItems(
|
||||||
|
objectMetadataItem.id,
|
||||||
|
);
|
||||||
|
|
||||||
const applyViewFiltersToCurrentRecordFilters = (
|
const applyViewFiltersToCurrentRecordFilters = (
|
||||||
viewFilters: ViewFilter[],
|
viewFilters: ViewFilter[],
|
||||||
|
|||||||
@ -43,7 +43,8 @@ export const RecordIndexPage = () => {
|
|||||||
mainContextStoreComponentInstanceId,
|
mainContextStoreComponentInstanceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const recordIndexId = `${objectNamePlural}-${contextStoreCurrentViewId}`;
|
// Todo: if we want the recordIndexId to contain the viewId, we need to remove the Effects otherwise we will have race condition on view change
|
||||||
|
const recordIndexId = `${objectNamePlural}`;
|
||||||
|
|
||||||
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
const { objectNameSingular } = useObjectNameSingularFromPlural({
|
||||||
objectNamePlural,
|
objectNamePlural,
|
||||||
|
|||||||
Reference in New Issue
Block a user