Improve Jotai work (#18205)
This commit is contained in:
+2
-2
@@ -9,8 +9,8 @@ type DateLocaleState = {
|
||||
localeCatalog: Locale;
|
||||
};
|
||||
|
||||
export const dateLocaleStateV2 = createStateV2<DateLocaleState>({
|
||||
key: 'dateLocaleStateV2',
|
||||
export const dateLocaleState = createStateV2<DateLocaleState>({
|
||||
key: 'dateLocaleState',
|
||||
defaultValue: {
|
||||
locale: undefined,
|
||||
localeCatalog: enUS,
|
||||
+5
-4
@@ -7,7 +7,6 @@ import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/s
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
import { useActiveWorkflowVersionsWithManualTrigger } from '@/workflow/hooks/useActiveWorkflowVersionsWithManualTrigger';
|
||||
@@ -20,6 +19,7 @@ import { useCallback } from 'react';
|
||||
import { QUERY_MAX_RECORDS } from 'twenty-shared/constants';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useRunWorkflowRecordActions = ({
|
||||
objectMetadataItem,
|
||||
@@ -28,6 +28,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
skip?: boolean;
|
||||
}) => {
|
||||
const store = useStore();
|
||||
const { getIcon } = useIcons();
|
||||
const { enqueueWarningSnackBar } = useSnackBar();
|
||||
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
|
||||
@@ -88,7 +89,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
const objectNamePlural = objectMetadataItem.namePlural;
|
||||
const selectedRecords = limitedSelectedRecordIds
|
||||
.map((recordId) =>
|
||||
jotaiStore.get(recordStoreFamilyState.atomFamily(recordId)),
|
||||
store.get(recordStoreFamilyState.atomFamily(recordId)),
|
||||
)
|
||||
.filter(isDefined);
|
||||
|
||||
@@ -101,7 +102,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
});
|
||||
} else {
|
||||
for (const selectedRecordId of limitedSelectedRecordIds) {
|
||||
const selectedRecord = jotaiStore.get(
|
||||
const selectedRecord = store.get(
|
||||
recordStoreFamilyState.atomFamily(selectedRecordId),
|
||||
);
|
||||
|
||||
@@ -117,7 +118,7 @@ export const useRunWorkflowRecordActions = ({
|
||||
}
|
||||
}
|
||||
},
|
||||
[runWorkflowVersion, objectMetadataItem, enqueueWarningSnackBar],
|
||||
[runWorkflowVersion, objectMetadataItem, enqueueWarningSnackBar, store],
|
||||
);
|
||||
|
||||
return activeWorkflowVersions
|
||||
|
||||
-4
@@ -1,13 +1,9 @@
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const useSelectedRecordIdOrThrow = () => {
|
||||
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
if (
|
||||
|
||||
-4
@@ -1,13 +1,9 @@
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { useRecordIndexIdFromCurrentContextStore } from '@/object-record/record-index/hooks/useRecordIndexIdFromCurrentContextStore';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const useSelectedRecordIds = () => {
|
||||
const { recordIndexId } = useRecordIndexIdFromCurrentContextStore();
|
||||
|
||||
const contextStoreTargetedRecordsRule = useRecoilComponentValueV2(
|
||||
contextStoreTargetedRecordsRuleComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
if (
|
||||
|
||||
+3
-2
@@ -4,10 +4,11 @@ import { useGetUpdatableWorkflowVersionOrThrow } from '@/workflow/hooks/useGetUp
|
||||
import { getWorkflowVisualizerComponentInstanceId } from '@/workflow/utils/getWorkflowVisualizerComponentInstanceId';
|
||||
import { workflowDiagramComponentState } from '@/workflow/workflow-diagram/states/workflowDiagramComponentState';
|
||||
import { useTidyUpWorkflowVersion } from '@/workflow/workflow-version/hooks/useTidyUpWorkflowVersion';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const TidyUpWorkflowSingleRecordAction = () => {
|
||||
const store = useStore();
|
||||
const recordId = useSelectedRecordIdOrThrow();
|
||||
const { tidyUpWorkflowVersion } = useTidyUpWorkflowVersion();
|
||||
const instanceId = getWorkflowVisualizerComponentInstanceId({
|
||||
@@ -20,7 +21,7 @@ export const TidyUpWorkflowSingleRecordAction = () => {
|
||||
const workflowDiagramAtom = workflowDiagramComponentState.atomFamily({
|
||||
instanceId,
|
||||
});
|
||||
const workflowDiagram = jotaiStore.get(workflowDiagramAtom);
|
||||
const workflowDiagram = store.get(workflowDiagramAtom);
|
||||
|
||||
if (!isDefined(workflowDiagram)) {
|
||||
return;
|
||||
|
||||
+6
-5
@@ -21,17 +21,18 @@ import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/ho
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
|
||||
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { useCallback, useContext, useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useShouldActionBeRegisteredParams = ({
|
||||
objectMetadataItem,
|
||||
}: {
|
||||
objectMetadataItem?: ObjectMetadataItem;
|
||||
}): ShouldBeRegisteredFunctionParams => {
|
||||
const store = useStore();
|
||||
const { sortedFavorites: favorites } = useFavorites();
|
||||
const { navigationMenuItems } = usePrefetchedNavigationMenuItemsData();
|
||||
const isNavigationMenuItemEditingEnabled = useIsFeatureEnabled(
|
||||
@@ -119,24 +120,24 @@ export const useShouldActionBeRegisteredParams = ({
|
||||
|
||||
const getObjectReadPermission = useCallback(
|
||||
(objectMetadataNameSingular: string) => {
|
||||
return jotaiStore.get(
|
||||
return store.get(
|
||||
objectPermissionsFamilySelector.selectorFamily({
|
||||
objectNameSingular: objectMetadataNameSingular,
|
||||
}),
|
||||
).canRead;
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
const getObjectWritePermission = useCallback(
|
||||
(objectMetadataNameSingular: string) => {
|
||||
return jotaiStore.get(
|
||||
return store.get(
|
||||
objectPermissionsFamilySelector.selectorFamily({
|
||||
objectNameSingular: objectMetadataNameSingular,
|
||||
}),
|
||||
).canUpdate;
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
const forceRegisteredActionsByKey = useRecoilValueV2(
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ import {
|
||||
Section,
|
||||
} from 'twenty-ui/layout';
|
||||
import { type TimelineCalendarEventsWithTotal } from '~/generated/graphql';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
box-sizing: border-box;
|
||||
@@ -49,7 +49,7 @@ const StyledTitleContainer = styled.div`
|
||||
export const CalendarEventsCard = () => {
|
||||
const { t } = useLingui();
|
||||
const targetRecord = useTargetRecord();
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
|
||||
const [query, queryName] =
|
||||
targetRecord.targetObjectNameSingular === CoreObjectNameSingular.Person
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValu
|
||||
import styled from '@emotion/styled';
|
||||
import { t } from '@lingui/core/macro';
|
||||
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||
|
||||
type EmailThreadHeaderProps = {
|
||||
@@ -43,7 +43,7 @@ export const EmailThreadHeader = ({
|
||||
subject,
|
||||
lastMessageSentAt,
|
||||
}: EmailThreadHeaderProps) => {
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
const lastMessageSentAtFormatted = beautifyPastDateRelativeToNow(
|
||||
lastMessageSentAt,
|
||||
localeCatalog,
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import { ParticipantChip } from '@/activities/components/ParticipantChip';
|
||||
import { type EmailThreadMessageParticipant } from '@/activities/emails/types/EmailThreadMessageParticipant';
|
||||
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
|
||||
import { AppTooltip, TooltipPosition } from 'twenty-ui/display';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import {
|
||||
beautifyPastDateRelativeToNow,
|
||||
formatToHumanReadableDate,
|
||||
@@ -31,7 +31,7 @@ export const EmailThreadMessageSender = ({
|
||||
sender,
|
||||
sentAt,
|
||||
}: EmailThreadMessageSenderProps) => {
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
const tooltipId = `date-tooltip-${sentAt.replace(/[^a-zA-Z0-9]/g, '-')}`;
|
||||
|
||||
return (
|
||||
|
||||
+7
-5
@@ -1,6 +1,5 @@
|
||||
import { type ActivityTargetWithTargetRecord } from '@/activities/types/ActivityTargetObject';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useMultipleRecordPickerOpen } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerOpen';
|
||||
import { useMultipleRecordPickerPerformSearch } from '@/object-record/record-picker/multiple-record-picker/hooks/useMultipleRecordPickerPerformSearch';
|
||||
@@ -10,6 +9,7 @@ import { multipleRecordPickerSearchableObjectMetadataItemsComponentState } from
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type OpenActivityTargetCellEditModeProps = {
|
||||
recordPickerInstanceId: string;
|
||||
@@ -18,6 +18,7 @@ type OpenActivityTargetCellEditModeProps = {
|
||||
|
||||
// TODO: deprecate this once we are supporting one to many through relations
|
||||
export const useOpenActivityTargetCellEditMode = () => {
|
||||
const store = useStore();
|
||||
const { performSearch: multipleRecordPickerPerformSearch } =
|
||||
useMultipleRecordPickerPerformSearch();
|
||||
const { openMultipleRecordPicker } = useMultipleRecordPickerOpen();
|
||||
@@ -29,7 +30,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
recordPickerInstanceId,
|
||||
activityTargetObjectRecords,
|
||||
}: OpenActivityTargetCellEditModeProps) => {
|
||||
const objectMetadataItems = jotaiStore
|
||||
const objectMetadataItems = store
|
||||
.get(objectMetadataItemsState.atom)
|
||||
.filter(
|
||||
(objectMetadataItem) =>
|
||||
@@ -41,7 +42,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
CoreObjectNameSingular.WorkspaceMember,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
multipleRecordPickerPickableMorphItemsComponentState.atomFamily({
|
||||
instanceId: recordPickerInstanceId,
|
||||
}),
|
||||
@@ -54,7 +55,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
})),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
multipleRecordPickerSearchableObjectMetadataItemsComponentState.atomFamily(
|
||||
{
|
||||
instanceId: recordPickerInstanceId,
|
||||
@@ -63,7 +64,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
objectMetadataItems,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
multipleRecordPickerSearchFilterComponentState.atomFamily({
|
||||
instanceId: recordPickerInstanceId,
|
||||
}),
|
||||
@@ -102,6 +103,7 @@ export const useOpenActivityTargetCellEditMode = () => {
|
||||
multipleRecordPickerPerformSearch,
|
||||
openMultipleRecordPicker,
|
||||
pushFocusItemToFocusStack,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@ import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataI
|
||||
import { getObjectRecordIdentifier } from '@/object-metadata/utils/getObjectRecordIdentifier';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||
import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons';
|
||||
@@ -99,7 +99,7 @@ export const EventRow = ({
|
||||
allowRequestsToTwentyIconsState,
|
||||
);
|
||||
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
|
||||
const { recordId } = useContext(TimelineActivityContext);
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { LightCopyIconButton } from '@/object-record/record-field/ui/components/
|
||||
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
|
||||
import { type ExtendedUIMessage } from 'twenty-shared/ai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||
|
||||
const StyledMessageBubble = styled.div<{ isUser?: boolean }>`
|
||||
@@ -141,7 +141,7 @@ export const AIChatMessage = ({
|
||||
isLastMessageStreaming: boolean;
|
||||
error?: Error | null;
|
||||
}) => {
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
|
||||
const isUser = message.role === AgentMessageRole.USER;
|
||||
const showError =
|
||||
|
||||
@@ -6,9 +6,9 @@ import { AppRootErrorFallback } from '@/error-handler/components/AppRootErrorFal
|
||||
import { ExceptionHandlerProvider } from '@/error-handler/components/ExceptionHandlerProvider';
|
||||
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
|
||||
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { i18n } from '@lingui/core';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { HelmetProvider } from 'react-helmet-async';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
@@ -35,7 +35,6 @@ import { PageFocusId } from '@/types/PageFocusId';
|
||||
import { useResetFocusStackToFocusItem } from '@/ui/utilities/focus/hooks/useResetFocusStackToFocusItem';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { AppBasePath, AppPath, CommandMenuPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { AnalyticsType } from '~/generated-metadata/graphql';
|
||||
@@ -43,10 +42,12 @@ import { usePageChangeEffectNavigateLocation } from '~/hooks/usePageChangeEffect
|
||||
import { useInitializeQueryParamState } from '~/modules/app/hooks/useInitializeQueryParamState';
|
||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||
import { getPageTitleFromPath } from '~/utils/title-utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
// TODO: break down into smaller functions and / or hooks
|
||||
// - moved usePageChangeEffectNavigateLocation into dedicated hook
|
||||
export const PageChangeEffect = () => {
|
||||
const store = useStore();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [previousLocation, setPreviousLocation] = useState('');
|
||||
@@ -99,12 +100,12 @@ export const PageChangeEffect = () => {
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const closeCommandMenuUnlessOnEditPage = useCallback(() => {
|
||||
const currentPage = jotaiStore.get(commandMenuPageState.atom);
|
||||
const currentPage = store.get(commandMenuPageState.atom);
|
||||
if (currentPage === CommandMenuPages.NavigationMenuItemEdit) {
|
||||
return;
|
||||
}
|
||||
closeCommandMenu();
|
||||
}, [closeCommandMenu]);
|
||||
}, [closeCommandMenu, store]);
|
||||
|
||||
const { resetFocusStackToFocusItem } = useResetFocusStackToFocusItem();
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
|
||||
import { currentPageLayoutIdState } from '@/page-layout/states/currentPageLayoutIdState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { hasInitializedFieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/hasInitializedFieldsWidgetGroupsDraftComponentState';
|
||||
import { isPageLayoutInEditModeComponentState } from '@/page-layout/states/isPageLayoutInEditModeComponentState';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
@@ -12,22 +11,24 @@ import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLa
|
||||
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useExecuteTasksOnAnyLocationChange = () => {
|
||||
const store = useStore();
|
||||
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
|
||||
|
||||
const resetPageLayoutEditMode = useCallback(() => {
|
||||
const pageLayoutId = jotaiStore.get(currentPageLayoutIdState.atom);
|
||||
const pageLayoutId = store.get(currentPageLayoutIdState.atom);
|
||||
|
||||
if (isDefined(pageLayoutId)) {
|
||||
const pageLayoutPersisted = jotaiStore.get(
|
||||
const pageLayoutPersisted = store.get(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
|
||||
if (isDefined(pageLayoutPersisted)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
@@ -41,7 +42,7 @@ export const useExecuteTasksOnAnyLocationChange = () => {
|
||||
);
|
||||
|
||||
const tabLayouts = convertPageLayoutToTabLayouts(pageLayoutPersisted);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutCurrentLayoutsComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
@@ -49,37 +50,37 @@ export const useExecuteTasksOnAnyLocationChange = () => {
|
||||
);
|
||||
}
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
isPageLayoutInEditModeComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutIsInitializedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasInitializedFieldsWidgetGroupsDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
{},
|
||||
);
|
||||
|
||||
jotaiStore.set(currentPageLayoutIdState.atom, null);
|
||||
store.set(currentPageLayoutIdState.atom, null);
|
||||
}
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreIsPageInEditModeComponentState.atomFamily({
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
}, []);
|
||||
}, [store]);
|
||||
|
||||
/**
|
||||
* Be careful to put idempotent tasks here.
|
||||
|
||||
@@ -3,16 +3,17 @@ import { useCallback } from 'react';
|
||||
import { billingCheckoutSessionState } from '@/auth/states/billingCheckoutSessionState';
|
||||
import { type BillingCheckoutSession } from '@/auth/types/billingCheckoutSession.type';
|
||||
import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import deepEqual from 'deep-equal';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
// Initialize state that are hydrated from query parameters
|
||||
// We used to use recoil-sync to do this, but it was causing issues with Firefox
|
||||
export const useInitializeQueryParamState = () => {
|
||||
const store = useStore();
|
||||
const initializeQueryParamState = useCallback(() => {
|
||||
const handlers = {
|
||||
billingCheckoutSession: (value: string) => {
|
||||
const billingCheckoutSession = jotaiStore.get(
|
||||
const billingCheckoutSession = store.get(
|
||||
billingCheckoutSessionState.atom,
|
||||
);
|
||||
|
||||
@@ -27,7 +28,7 @@ export const useInitializeQueryParamState = () => {
|
||||
'requirePaymentMethod' in parsedValue &&
|
||||
!deepEqual(billingCheckoutSession, parsedValue)
|
||||
) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
billingCheckoutSessionState.atom,
|
||||
parsedValue as BillingCheckoutSession,
|
||||
);
|
||||
@@ -38,7 +39,7 @@ export const useInitializeQueryParamState = () => {
|
||||
'Failed to parse billingCheckoutSession from URL',
|
||||
error,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
billingCheckoutSessionState.atom,
|
||||
BILLING_CHECKOUT_SESSION_DEFAULT_VALUE,
|
||||
);
|
||||
@@ -54,7 +55,7 @@ export const useInitializeQueryParamState = () => {
|
||||
handler(value);
|
||||
}
|
||||
}
|
||||
}, []);
|
||||
}, [store]);
|
||||
|
||||
return { initializeQueryParamState };
|
||||
};
|
||||
|
||||
@@ -22,7 +22,9 @@ export const VerifyLoginTokenEffect = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!clientConfigLoaded) return;
|
||||
if (!clientConfigLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDefined(loginToken)) {
|
||||
verifyLoginToken(loginToken);
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
|
||||
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
|
||||
import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
@@ -63,8 +62,10 @@ import { SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { cookieStorage } from '~/utils/cookie-storage';
|
||||
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useAuth = () => {
|
||||
const store = useStore();
|
||||
const setTokenPair = useSetRecoilStateV2(tokenPairState);
|
||||
const setLoginToken = useSetRecoilStateV2(loginTokenState);
|
||||
const setIsAppEffectRedirectEnabled = useSetRecoilStateV2(
|
||||
@@ -119,23 +120,19 @@ export const useAuth = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const clearSession = useCallback(async () => {
|
||||
const sseClient = jotaiStore.get(sseClientState.atom);
|
||||
const sseClient = store.get(sseClientState.atom);
|
||||
|
||||
sseClient?.dispose();
|
||||
|
||||
const emptySnapshot = snapshot_UNSTABLE();
|
||||
|
||||
const authProvidersValue = jotaiStore.get(workspaceAuthProvidersState.atom);
|
||||
const domainConfigurationValue = jotaiStore.get(
|
||||
domainConfigurationState.atom,
|
||||
);
|
||||
const workspacePublicDataValue = jotaiStore.get(
|
||||
workspacePublicDataState.atom,
|
||||
);
|
||||
const lastAuthenticatedMethod = jotaiStore.get(
|
||||
const authProvidersValue = store.get(workspaceAuthProvidersState.atom);
|
||||
const domainConfigurationValue = store.get(domainConfigurationState.atom);
|
||||
const workspacePublicDataValue = store.get(workspacePublicDataState.atom);
|
||||
const lastAuthenticatedMethod = store.get(
|
||||
lastAuthenticatedMethodState.atom,
|
||||
);
|
||||
const isCaptchaScriptLoadedValue = jotaiStore.get(
|
||||
const isCaptchaScriptLoadedValue = store.get(
|
||||
isCaptchaScriptLoadedState.atom,
|
||||
);
|
||||
|
||||
@@ -148,27 +145,27 @@ export const useAuth = () => {
|
||||
|
||||
goToRecoilSnapshot(initialSnapshot);
|
||||
|
||||
jotaiStore.set(workspaceAuthProvidersState.atom, authProvidersValue);
|
||||
jotaiStore.set(workspacePublicDataState.atom, workspacePublicDataValue);
|
||||
jotaiStore.set(domainConfigurationState.atom, domainConfigurationValue);
|
||||
jotaiStore.set(isCaptchaScriptLoadedState.atom, isCaptchaScriptLoadedValue);
|
||||
jotaiStore.set(lastAuthenticatedMethodState.atom, lastAuthenticatedMethod);
|
||||
store.set(workspaceAuthProvidersState.atom, authProvidersValue);
|
||||
store.set(workspacePublicDataState.atom, workspacePublicDataValue);
|
||||
store.set(domainConfigurationState.atom, domainConfigurationValue);
|
||||
store.set(isCaptchaScriptLoadedState.atom, isCaptchaScriptLoadedValue);
|
||||
store.set(lastAuthenticatedMethodState.atom, lastAuthenticatedMethod);
|
||||
|
||||
// Reset user-data Jotai states that were migrated from Recoil
|
||||
// (Recoil snapshot reset no longer handles these since they are Jotai V2)
|
||||
jotaiStore.set(tokenPairState.atom, null);
|
||||
jotaiStore.set(currentUserState.atom, null);
|
||||
jotaiStore.set(currentWorkspaceState.atom, null);
|
||||
jotaiStore.set(currentUserWorkspaceState.atom, null);
|
||||
jotaiStore.set(currentWorkspaceMemberState.atom, null);
|
||||
jotaiStore.set(currentWorkspaceMembersState.atom, []);
|
||||
jotaiStore.set(availableWorkspacesState.atom, {
|
||||
store.set(tokenPairState.atom, null);
|
||||
store.set(currentUserState.atom, null);
|
||||
store.set(currentWorkspaceState.atom, null);
|
||||
store.set(currentUserWorkspaceState.atom, null);
|
||||
store.set(currentWorkspaceMemberState.atom, null);
|
||||
store.set(currentWorkspaceMembersState.atom, []);
|
||||
store.set(availableWorkspacesState.atom, {
|
||||
availableWorkspacesForSignIn: [],
|
||||
availableWorkspacesForSignUp: [],
|
||||
});
|
||||
jotaiStore.set(loginTokenState.atom, null);
|
||||
jotaiStore.set(signInUpStepState.atom, SignInUpStep.Init);
|
||||
jotaiStore.set(coreViewsState.atom, []);
|
||||
store.set(loginTokenState.atom, null);
|
||||
store.set(signInUpStepState.atom, SignInUpStep.Init);
|
||||
store.set(coreViewsState.atom, []);
|
||||
|
||||
await client.clearStore();
|
||||
setLastAuthenticateWorkspaceDomain(null);
|
||||
@@ -180,6 +177,7 @@ export const useAuth = () => {
|
||||
setLastAuthenticateWorkspaceDomain,
|
||||
resetToMockedMetadata,
|
||||
navigate,
|
||||
store,
|
||||
]);
|
||||
|
||||
const handleSetAuthTokens = useCallback(
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import { captchaTokenState } from '@/captcha/states/captchaTokenState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useReadCaptchaToken = () => {
|
||||
const store = useStore();
|
||||
const readCaptchaToken = useCallback(() => {
|
||||
const existingCaptchaToken = jotaiStore.get(captchaTokenState.atom);
|
||||
const existingCaptchaToken = store.get(captchaTokenState.atom);
|
||||
|
||||
if (isDefined(existingCaptchaToken)) {
|
||||
return existingCaptchaToken;
|
||||
}
|
||||
}, []);
|
||||
}, [store]);
|
||||
|
||||
return { readCaptchaToken };
|
||||
};
|
||||
|
||||
@@ -3,12 +3,13 @@ import { isRequestingCaptchaTokenState } from '@/captcha/states/isRequestingCapt
|
||||
import { isCaptchaRequiredForPath } from '@/captcha/utils/isCaptchaRequiredForPath';
|
||||
import { captchaState } from '@/client-config/states/captchaState';
|
||||
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { assertIsDefinedOrThrow, isDefined } from 'twenty-shared/utils';
|
||||
import { CaptchaDriverType } from '~/generated-metadata/graphql';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useRequestFreshCaptchaToken = () => {
|
||||
const store = useStore();
|
||||
const setCaptchaToken = useSetRecoilStateV2(captchaTokenState);
|
||||
const setIsRequestingCaptchaToken = useSetRecoilStateV2(
|
||||
isRequestingCaptchaTokenState,
|
||||
@@ -19,7 +20,7 @@ export const useRequestFreshCaptchaToken = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const captcha = jotaiStore.get(captchaState.atom);
|
||||
const captcha = store.get(captchaState.atom);
|
||||
|
||||
if (!isDefined(captcha)) {
|
||||
return;
|
||||
@@ -52,7 +53,7 @@ export const useRequestFreshCaptchaToken = () => {
|
||||
},
|
||||
});
|
||||
}
|
||||
}, [setCaptchaToken, setIsRequestingCaptchaToken]);
|
||||
}, [setCaptchaToken, setIsRequestingCaptchaToken, store]);
|
||||
|
||||
return { requestFreshCaptchaToken };
|
||||
};
|
||||
|
||||
@@ -33,7 +33,7 @@ import { getClientConfig } from '@/client-config/utils/getClientConfig';
|
||||
import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons';
|
||||
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
|
||||
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type UseClientConfigResult = {
|
||||
data: { clientConfig: ClientConfig } | undefined;
|
||||
@@ -44,6 +44,7 @@ type UseClientConfigResult = {
|
||||
};
|
||||
|
||||
export const useClientConfig = (): UseClientConfigResult => {
|
||||
const store = useStore();
|
||||
const setIsAnalyticsEnabled = useSetRecoilStateV2(isAnalyticsEnabledState);
|
||||
const setDomainConfiguration = useSetRecoilStateV2(domainConfigurationState);
|
||||
const setAuthProviders = useSetRecoilStateV2(authProvidersState);
|
||||
@@ -191,7 +192,7 @@ export const useClientConfig = (): UseClientConfigResult => {
|
||||
setGoogleMessagingEnabled(clientConfig?.isGoogleMessagingEnabled);
|
||||
setGoogleCalendarEnabled(clientConfig?.isGoogleCalendarEnabled);
|
||||
setIsAttachmentPreviewEnabled(clientConfig?.isAttachmentPreviewEnabled);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
isAttachmentPreviewEnabledStateV2.atom,
|
||||
clientConfig?.isAttachmentPreviewEnabled,
|
||||
);
|
||||
@@ -252,6 +253,7 @@ export const useClientConfig = (): UseClientConfigResult => {
|
||||
setSentryConfig,
|
||||
setSupportChat,
|
||||
setAllowRequestsToTwentyIcons,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
FeatureFlagKey,
|
||||
FieldMetadataType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
|
||||
import { CommandMenuPageInfoLayout } from './CommandMenuPageInfoLayout';
|
||||
|
||||
@@ -67,7 +67,7 @@ export const CommandMenuRecordInfo = ({
|
||||
},
|
||||
);
|
||||
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleStateV2);
|
||||
const { localeCatalog } = useRecoilValueV2(dateLocaleState);
|
||||
const beautifiedCreatedAt = isNonEmptyString(recordCreatedAt)
|
||||
? beautifyPastDateRelativeToNow(recordCreatedAt, localeCatalog)
|
||||
: '';
|
||||
|
||||
+11
-8
@@ -1,4 +1,5 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
@@ -13,14 +14,16 @@ import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
{children}
|
||||
</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>
|
||||
<MemoryRouter
|
||||
initialEntries={['/one', '/two', { pathname: '/three' }]}
|
||||
initialIndex={1}
|
||||
>
|
||||
{children}
|
||||
</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
const renderHooks = () => {
|
||||
|
||||
+6
-3
@@ -1,4 +1,5 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
@@ -51,9 +52,11 @@ jest.mock('@/ui/layout/right-drawer/utils/emitSidePanelCloseEvent', () => ({
|
||||
}));
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
describe('useCommandMenuCloseAnimationCompleteCleanup', () => {
|
||||
|
||||
+6
-3
@@ -1,4 +1,5 @@
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
@@ -15,9 +16,11 @@ import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { IconList, IconSearch } from 'twenty-ui/display';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>
|
||||
<MemoryRouter>{children}</MemoryRouter>
|
||||
</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
const renderHooks = () => {
|
||||
|
||||
+4
-1
@@ -2,6 +2,7 @@ import { useCommandMenuUpdateNavigationMorphItemsByPage } from '@/command-menu/h
|
||||
import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
|
||||
@@ -9,7 +10,9 @@ const pageId = 'merge-page-id';
|
||||
const objectMetadataId = 'company-metadata-id';
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>{children}</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>{children}</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
const renderHooks = (initialRecordIds: string[]) => {
|
||||
|
||||
+4
-1
@@ -3,6 +3,7 @@ import { commandMenuNavigationStackState } from '@/command-menu/states/commandMe
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
@@ -24,7 +25,9 @@ const mockedNavigationStack = [
|
||||
];
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<RecoilRoot>{children}</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>{children}</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
);
|
||||
|
||||
describe('useUpdateCommandMenuPageInfo', () => {
|
||||
|
||||
@@ -7,13 +7,14 @@ import { addToNavPayloadRegistryStateV2 } from '@/navigation-menu-item/states/ad
|
||||
import { useCloseAnyOpenDropdown } from '@/ui/layout/dropdown/hooks/useCloseAnyOpenDropdown';
|
||||
import { emitSidePanelOpenEvent } from '@/ui/layout/right-drawer/utils/emitSidePanelOpenEvent';
|
||||
import { useRemoveFocusItemFromFocusStackById } from '@/ui/utilities/focus/hooks/useRemoveFocusItemFromFocusStackById';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { IconDotsVertical } from 'twenty-ui/display';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
const { closeAnyOpenDropdown } = useCloseAnyOpenDropdown();
|
||||
|
||||
@@ -21,18 +22,18 @@ export const useCommandMenu = () => {
|
||||
useRemoveFocusItemFromFocusStackById();
|
||||
|
||||
const closeCommandMenu = useCallback(() => {
|
||||
const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom);
|
||||
const isCommandMenuOpened = store.get(isCommandMenuOpenedStateV2.atom);
|
||||
|
||||
if (isCommandMenuOpened) {
|
||||
jotaiStore.set(addToNavPayloadRegistryStateV2.atom, new Map());
|
||||
jotaiStore.set(isCommandMenuOpenedStateV2.atom, false);
|
||||
jotaiStore.set(isCommandMenuClosingState.atom, true);
|
||||
store.set(addToNavPayloadRegistryStateV2.atom, new Map());
|
||||
store.set(isCommandMenuOpenedStateV2.atom, false);
|
||||
store.set(isCommandMenuClosingState.atom, true);
|
||||
closeAnyOpenDropdown();
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId: SIDE_PANEL_FOCUS_ID,
|
||||
});
|
||||
}
|
||||
}, [closeAnyOpenDropdown, removeFocusItemFromFocusStackById]);
|
||||
}, [closeAnyOpenDropdown, removeFocusItemFromFocusStackById, store]);
|
||||
|
||||
const openCommandMenu = useCallback(() => {
|
||||
emitSidePanelOpenEvent();
|
||||
@@ -46,16 +47,16 @@ export const useCommandMenu = () => {
|
||||
}, [closeAnyOpenDropdown, navigateCommandMenu]);
|
||||
|
||||
const toggleCommandMenu = useCallback(() => {
|
||||
const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom);
|
||||
const isCommandMenuOpened = store.get(isCommandMenuOpenedStateV2.atom);
|
||||
|
||||
jotaiStore.set(commandMenuSearchState.atom, '');
|
||||
store.set(commandMenuSearchState.atom, '');
|
||||
|
||||
if (isCommandMenuOpened) {
|
||||
closeCommandMenu();
|
||||
} else {
|
||||
openCommandMenu();
|
||||
}
|
||||
}, [closeCommandMenu, openCommandMenu]);
|
||||
}, [closeCommandMenu, openCommandMenu, store]);
|
||||
|
||||
return {
|
||||
openCommandMenu,
|
||||
|
||||
+21
-22
@@ -22,14 +22,15 @@ import { emitSidePanelCloseEvent } from '@/ui/layout/right-drawer/utils/emitSide
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID } from '@/workflow/workflow-steps/workflow-actions/code-action/constants/WorkflowLogicFunctionTabListComponentId';
|
||||
import { WorkflowLogicFunctionTabId } from '@/workflow/workflow-steps/workflow-actions/code-action/types/WorkflowLogicFunctionTabId';
|
||||
import { useCallback } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
const store = useStore();
|
||||
const { resetSelectedItem } = useSelectableList(
|
||||
COMMAND_MENU_LIST_SELECTABLE_LIST_ID,
|
||||
);
|
||||
@@ -44,7 +45,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
resetContextStoreStates(COMMAND_MENU_COMPONENT_INSTANCE_ID);
|
||||
resetContextStoreStates(COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID);
|
||||
|
||||
const currentPage = jotaiStore.get(commandMenuPageState.atom);
|
||||
const currentPage = store.get(commandMenuPageState.atom);
|
||||
|
||||
const isPageLayoutEditingPage =
|
||||
currentPage === CommandMenuPages.PageLayoutWidgetTypeSelect ||
|
||||
@@ -53,7 +54,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
currentPage === CommandMenuPages.PageLayoutTabSettings;
|
||||
|
||||
if (isPageLayoutEditingPage) {
|
||||
const targetedRecordsRule = jotaiStore.get(
|
||||
const targetedRecordsRule = store.get(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
@@ -64,24 +65,22 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
targetedRecordsRule.selectedRecordIds.length === 1
|
||||
) {
|
||||
const recordId = targetedRecordsRule.selectedRecordIds[0];
|
||||
const record = jotaiStore.get(
|
||||
recordStoreFamilyState.atomFamily(recordId),
|
||||
);
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
|
||||
if (isDefined(record) && isDefined(record.pageLayoutId)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutEditingWidgetIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutTabSettingsOpenTabIdComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
null,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
pageLayoutDraggedAreaComponentState.atomFamily({
|
||||
instanceId: record.pageLayoutId,
|
||||
}),
|
||||
@@ -91,35 +90,35 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
}
|
||||
}
|
||||
|
||||
jotaiStore.set(viewableRecordIdState.atom, null);
|
||||
jotaiStore.set(commandMenuPageState.atom, CommandMenuPages.Root);
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, {
|
||||
store.set(viewableRecordIdState.atom, null);
|
||||
store.set(commandMenuPageState.atom, CommandMenuPages.Root);
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
jotaiStore.set(isCommandMenuOpenedStateV2.atom, false);
|
||||
jotaiStore.set(commandMenuSearchState.atom, '');
|
||||
jotaiStore.set(commandMenuNavigationMorphItemsByPageState.atom, new Map());
|
||||
jotaiStore.set(commandMenuNavigationStackState.atom, []);
|
||||
store.set(isCommandMenuOpenedStateV2.atom, false);
|
||||
store.set(commandMenuSearchState.atom, '');
|
||||
store.set(commandMenuNavigationMorphItemsByPageState.atom, new Map());
|
||||
store.set(commandMenuNavigationStackState.atom, []);
|
||||
resetSelectedItem();
|
||||
jotaiStore.set(hasUserSelectedCommandState.atom, false);
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
|
||||
emitSidePanelCloseEvent();
|
||||
jotaiStore.set(isCommandMenuClosingState.atom, false);
|
||||
jotaiStore.set(
|
||||
store.set(isCommandMenuClosingState.atom, false);
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: WORKFLOW_LOGIC_FUNCTION_TAB_LIST_COMPONENT_ID,
|
||||
}),
|
||||
WorkflowLogicFunctionTabId.CODE,
|
||||
);
|
||||
|
||||
const morphItemsByPage = jotaiStore.get(
|
||||
const morphItemsByPage = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
for (const [pageId, morphItems] of morphItemsByPage) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId,
|
||||
@@ -129,7 +128,7 @@ export const useCommandMenuCloseAnimationCompleteCleanup = () => {
|
||||
null,
|
||||
);
|
||||
}
|
||||
}, [closeDropdown, resetContextStoreStates, resetSelectedItem]);
|
||||
}, [closeDropdown, resetContextStoreStates, resetSelectedItem, store]);
|
||||
|
||||
return {
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
|
||||
@@ -8,15 +8,16 @@ import { commandMenuPageState } from '@/command-menu/states/commandMenuPageState
|
||||
import { hasUserSelectedCommandState } from '@/command-menu/states/hasUserSelectedCommandState';
|
||||
import { getShowPageTabListComponentId } from '@/ui/layout/show-page/utils/getShowPageTabListComponentId';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { isNonEmptyArray } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useCommandMenuHistory = () => {
|
||||
const store = useStore();
|
||||
const { closeCommandMenu } = useCommandMenu();
|
||||
|
||||
const goBackFromCommandMenu = useCallback(() => {
|
||||
const currentNavigationStack = jotaiStore.get(
|
||||
const currentNavigationStack = store.get(
|
||||
commandMenuNavigationStackState.atom,
|
||||
);
|
||||
|
||||
@@ -28,17 +29,17 @@ export const useCommandMenuHistory = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
jotaiStore.set(commandMenuPageState.atom, lastNavigationStackItem.page);
|
||||
store.set(commandMenuPageState.atom, lastNavigationStackItem.page);
|
||||
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, {
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: lastNavigationStackItem.pageTitle,
|
||||
Icon: lastNavigationStackItem.pageIcon,
|
||||
instanceId: lastNavigationStackItem.pageId,
|
||||
});
|
||||
|
||||
jotaiStore.set(commandMenuNavigationStackState.atom, newNavigationStack);
|
||||
store.set(commandMenuNavigationStackState.atom, newNavigationStack);
|
||||
|
||||
const currentMorphItems = jotaiStore.get(
|
||||
const currentMorphItems = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
@@ -48,14 +49,14 @@ export const useCommandMenuHistory = () => {
|
||||
if (isDefined(removedItem)) {
|
||||
const newMorphItems = new Map(currentMorphItems);
|
||||
newMorphItems.delete(removedItem.pageId);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
newMorphItems,
|
||||
);
|
||||
|
||||
const morphItems = currentMorphItems.get(removedItem.pageId);
|
||||
if (isNonEmptyArray(morphItems)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId: removedItem.pageId,
|
||||
@@ -68,63 +69,63 @@ export const useCommandMenuHistory = () => {
|
||||
}
|
||||
}
|
||||
|
||||
jotaiStore.set(hasUserSelectedCommandState.atom, false);
|
||||
}, [closeCommandMenu]);
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
}, [closeCommandMenu, store]);
|
||||
|
||||
const navigateCommandMenuHistory = useCallback((pageIndex: number) => {
|
||||
const currentNavigationStack = jotaiStore.get(
|
||||
commandMenuNavigationStackState.atom,
|
||||
);
|
||||
|
||||
const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1);
|
||||
|
||||
jotaiStore.set(commandMenuNavigationStackState.atom, newNavigationStack);
|
||||
|
||||
const newNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(newNavigationStackItem)) {
|
||||
throw new Error(
|
||||
`No command menu navigation stack item found for index ${pageIndex}`,
|
||||
const navigateCommandMenuHistory = useCallback(
|
||||
(pageIndex: number) => {
|
||||
const currentNavigationStack = store.get(
|
||||
commandMenuNavigationStackState.atom,
|
||||
);
|
||||
}
|
||||
|
||||
jotaiStore.set(commandMenuPageState.atom, newNavigationStackItem.page);
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, {
|
||||
title: newNavigationStackItem.pageTitle,
|
||||
Icon: newNavigationStackItem.pageIcon,
|
||||
instanceId: newNavigationStackItem.pageId,
|
||||
});
|
||||
const currentMorphItems = jotaiStore.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
const newNavigationStack = currentNavigationStack.slice(0, pageIndex + 1);
|
||||
|
||||
for (const [pageId, morphItems] of currentMorphItems.entries()) {
|
||||
if (!newNavigationStack.some((item) => item.pageId === pageId)) {
|
||||
jotaiStore.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId,
|
||||
targetObjectId: morphItems[0].recordId,
|
||||
}),
|
||||
}),
|
||||
null,
|
||||
store.set(commandMenuNavigationStackState.atom, newNavigationStack);
|
||||
|
||||
const newNavigationStackItem = newNavigationStack.at(-1);
|
||||
|
||||
if (!isDefined(newNavigationStackItem)) {
|
||||
throw new Error(
|
||||
`No command menu navigation stack item found for index ${pageIndex}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const newMorphItems = new Map(
|
||||
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
||||
newNavigationStack.some((item) => item.pageId === pageId),
|
||||
),
|
||||
);
|
||||
store.set(commandMenuPageState.atom, newNavigationStackItem.page);
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: newNavigationStackItem.pageTitle,
|
||||
Icon: newNavigationStackItem.pageIcon,
|
||||
instanceId: newNavigationStackItem.pageId,
|
||||
});
|
||||
const currentMorphItems = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
newMorphItems,
|
||||
);
|
||||
for (const [pageId, morphItems] of currentMorphItems.entries()) {
|
||||
if (!newNavigationStack.some((item) => item.pageId === pageId)) {
|
||||
store.set(
|
||||
activeTabIdComponentState.atomFamily({
|
||||
instanceId: getShowPageTabListComponentId({
|
||||
pageId,
|
||||
targetObjectId: morphItems[0].recordId,
|
||||
}),
|
||||
}),
|
||||
null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
jotaiStore.set(hasUserSelectedCommandState.atom, false);
|
||||
}, []);
|
||||
const newMorphItems = new Map(
|
||||
Array.from(currentMorphItems.entries()).filter(([pageId]) =>
|
||||
newNavigationStack.some((item) => item.pageId === pageId),
|
||||
),
|
||||
);
|
||||
|
||||
store.set(commandMenuNavigationMorphItemsByPageState.atom, newMorphItems);
|
||||
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
goBackFromCommandMenu,
|
||||
|
||||
+5
-4
@@ -1,6 +1,6 @@
|
||||
import { commandMenuNavigationMorphItemsByPageState } from '@/command-menu/states/commandMenuNavigationMorphItemsByPageState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type UpdateNavigationMorphItemsByPageParams = {
|
||||
pageId: string;
|
||||
@@ -9,13 +9,14 @@ type UpdateNavigationMorphItemsByPageParams = {
|
||||
};
|
||||
|
||||
export const useCommandMenuUpdateNavigationMorphItemsByPage = () => {
|
||||
const store = useStore();
|
||||
const updateCommandMenuNavigationMorphItemsByPage = useCallback(
|
||||
async ({
|
||||
pageId,
|
||||
objectMetadataId,
|
||||
objectRecordIds,
|
||||
}: UpdateNavigationMorphItemsByPageParams) => {
|
||||
const currentMorphItems = jotaiStore.get(
|
||||
const currentMorphItems = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
@@ -26,12 +27,12 @@ export const useCommandMenuUpdateNavigationMorphItemsByPage = () => {
|
||||
|
||||
const newMorphItemsMap = new Map(currentMorphItems);
|
||||
newMorphItemsMap.set(pageId, newMorphItems);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
newMorphItemsMap,
|
||||
);
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+21
-20
@@ -7,10 +7,11 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreIsPageInEditModeComponentState } from '@/context-store/states/contextStoreIsPageInEditModeComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useCopyContextStoreStates = () => {
|
||||
const store = useStore();
|
||||
const copyContextStoreStates = useCallback(
|
||||
({
|
||||
instanceIdToCopyFrom,
|
||||
@@ -19,124 +20,124 @@ export const useCopyContextStoreStates = () => {
|
||||
instanceIdToCopyFrom: string;
|
||||
instanceIdToCopyTo: string;
|
||||
}) => {
|
||||
const contextStoreCurrentObjectMetadataItemId = jotaiStore.get(
|
||||
const contextStoreCurrentObjectMetadataItemId = store.get(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreCurrentObjectMetadataItemId,
|
||||
);
|
||||
|
||||
const contextStoreTargetedRecordsRule = jotaiStore.get(
|
||||
const contextStoreTargetedRecordsRule = store.get(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreTargetedRecordsRule,
|
||||
);
|
||||
|
||||
const contextStoreNumberOfSelectedRecords = jotaiStore.get(
|
||||
const contextStoreNumberOfSelectedRecords = store.get(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreNumberOfSelectedRecords,
|
||||
);
|
||||
|
||||
const contextStoreFilters = jotaiStore.get(
|
||||
const contextStoreFilters = store.get(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreFilters,
|
||||
);
|
||||
|
||||
const contextStoreFilterGroups = jotaiStore.get(
|
||||
const contextStoreFilterGroups = store.get(
|
||||
contextStoreFilterGroupsComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreFilterGroupsComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreFilterGroups,
|
||||
);
|
||||
|
||||
const contextStoreAnyFieldFilterValue = jotaiStore.get(
|
||||
const contextStoreAnyFieldFilterValue = store.get(
|
||||
contextStoreAnyFieldFilterValueComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreAnyFieldFilterValueComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreAnyFieldFilterValue,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewId = jotaiStore.get(
|
||||
const contextStoreCurrentViewId = store.get(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreCurrentViewId,
|
||||
);
|
||||
|
||||
const contextStoreCurrentViewType = jotaiStore.get(
|
||||
const contextStoreCurrentViewType = store.get(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreCurrentViewType,
|
||||
);
|
||||
|
||||
const contextStoreIsFullTabWidgetInEditMode = jotaiStore.get(
|
||||
const contextStoreIsFullTabWidgetInEditMode = store.get(
|
||||
contextStoreIsPageInEditModeComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyFrom,
|
||||
}),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreIsPageInEditModeComponentState.atomFamily({
|
||||
instanceId: instanceIdToCopyTo,
|
||||
}),
|
||||
contextStoreIsFullTabWidgetInEditMode,
|
||||
);
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return { copyContextStoreStates };
|
||||
|
||||
@@ -13,11 +13,11 @@ import { isCommandMenuOpenedStateV2 } from '@/command-menu/states/isCommandMenuO
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { type CommandMenuPages } from 'twenty-shared/types';
|
||||
import { type IconComponent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export type CommandMenuNavigationStackItem = {
|
||||
page: CommandMenuPages;
|
||||
@@ -28,6 +28,7 @@ export type CommandMenuNavigationStackItem = {
|
||||
};
|
||||
|
||||
export const useNavigateCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
|
||||
const { commandMenuCloseAnimationCompleteCleanup } =
|
||||
@@ -36,9 +37,9 @@ export const useNavigateCommandMenu = () => {
|
||||
const { pushFocusItemToFocusStack } = usePushFocusItemToFocusStack();
|
||||
|
||||
const openCommandMenu = useCallback(() => {
|
||||
const isCommandMenuOpened = jotaiStore.get(isCommandMenuOpenedStateV2.atom);
|
||||
const isCommandMenuOpened = store.get(isCommandMenuOpenedStateV2.atom);
|
||||
|
||||
const isCommandMenuClosing = jotaiStore.get(isCommandMenuClosingState.atom);
|
||||
const isCommandMenuClosing = store.get(isCommandMenuClosingState.atom);
|
||||
|
||||
if (isCommandMenuClosing) {
|
||||
commandMenuCloseAnimationCompleteCleanup();
|
||||
@@ -64,12 +65,13 @@ export const useNavigateCommandMenu = () => {
|
||||
instanceIdToCopyTo: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
jotaiStore.set(isCommandMenuOpenedStateV2.atom, true);
|
||||
jotaiStore.set(hasUserSelectedCommandState.atom, false);
|
||||
store.set(isCommandMenuOpenedStateV2.atom, true);
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
}, [
|
||||
copyContextStoreStates,
|
||||
commandMenuCloseAnimationCompleteCleanup,
|
||||
pushFocusItemToFocusStack,
|
||||
store,
|
||||
]);
|
||||
|
||||
const navigateCommandMenu = useCallback(
|
||||
@@ -88,15 +90,15 @@ export const useNavigateCommandMenu = () => {
|
||||
const computedPageId = pageId || v4();
|
||||
|
||||
openCommandMenu();
|
||||
jotaiStore.set(commandMenuPageState.atom, page);
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, {
|
||||
store.set(commandMenuPageState.atom, page);
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: pageTitle,
|
||||
Icon: pageIcon,
|
||||
instanceId: computedPageId,
|
||||
});
|
||||
|
||||
if (focusTitleInput) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuShouldFocusTitleInputComponentState.atomFamily({
|
||||
instanceId: computedPageId,
|
||||
}),
|
||||
@@ -104,16 +106,14 @@ export const useNavigateCommandMenu = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const isCommandMenuClosing = jotaiStore.get(
|
||||
isCommandMenuClosingState.atom,
|
||||
);
|
||||
const isCommandMenuClosing = store.get(isCommandMenuClosingState.atom);
|
||||
|
||||
const currentNavigationStack = isCommandMenuClosing
|
||||
? []
|
||||
: jotaiStore.get(commandMenuNavigationStackState.atom);
|
||||
: store.get(commandMenuNavigationStackState.atom);
|
||||
|
||||
if (resetNavigationStack) {
|
||||
jotaiStore.set(commandMenuNavigationStackState.atom, [
|
||||
store.set(commandMenuNavigationStackState.atom, [
|
||||
{
|
||||
page,
|
||||
pageTitle,
|
||||
@@ -123,12 +123,9 @@ export const useNavigateCommandMenu = () => {
|
||||
},
|
||||
]);
|
||||
|
||||
jotaiStore.set(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
new Map(),
|
||||
);
|
||||
store.set(commandMenuNavigationMorphItemsByPageState.atom, new Map());
|
||||
} else {
|
||||
jotaiStore.set(commandMenuNavigationStackState.atom, [
|
||||
store.set(commandMenuNavigationStackState.atom, [
|
||||
...currentNavigationStack,
|
||||
{
|
||||
page,
|
||||
@@ -140,7 +137,7 @@ export const useNavigateCommandMenu = () => {
|
||||
]);
|
||||
}
|
||||
},
|
||||
[openCommandMenu],
|
||||
[openCommandMenu, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+4
-3
@@ -1,20 +1,21 @@
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { IconCalendarEvent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useOpenCalendarEventInCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const openCalendarEventInCommandMenu = useCallback(
|
||||
(calendarEventId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
@@ -53,7 +54,7 @@ export const useOpenCalendarEventInCommandMenu = () => {
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+4
-3
@@ -1,20 +1,21 @@
|
||||
import { useNavigateCommandMenu } from '@/command-menu/hooks/useNavigateCommandMenu';
|
||||
import { viewableRecordIdComponentState } from '@/command-menu/pages/record-page/states/viewableRecordIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { IconMail } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useOpenEmailThreadInCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
|
||||
const openEmailThreadInCommandMenu = useCallback(
|
||||
(emailThreadId: string) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
@@ -53,7 +54,7 @@ export const useOpenEmailThreadInCommandMenu = () => {
|
||||
pageId: pageComponentInstanceId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+3
-2
@@ -1,11 +1,12 @@
|
||||
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
|
||||
import { viewableFrontComponentIdComponentState } from '@/command-menu/pages/front-component/states/viewableFrontComponentIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
import { type IconComponent } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useOpenFrontComponentInCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { navigateCommandMenu } = useCommandMenu();
|
||||
|
||||
const openFrontComponentInCommandMenu = ({
|
||||
@@ -21,7 +22,7 @@ export const useOpenFrontComponentInCommandMenu = () => {
|
||||
}) => {
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
viewableFrontComponentIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
|
||||
+4
-2
@@ -6,11 +6,11 @@ import { useLazyFindManyRecords } from '@/object-record/hooks/useLazyFindManyRec
|
||||
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { msg, t } from '@lingui/core/macro';
|
||||
import { useCallback } from 'react';
|
||||
import { IconArrowMerge } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type UseOpenMergeRecordsPageInCommandMenuProps = {
|
||||
objectNameSingular: string;
|
||||
@@ -21,6 +21,7 @@ export const useOpenMergeRecordsPageInCommandMenu = ({
|
||||
objectNameSingular,
|
||||
objectRecordIds,
|
||||
}: UseOpenMergeRecordsPageInCommandMenuProps) => {
|
||||
const store = useStore();
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
@@ -43,7 +44,7 @@ export const useOpenMergeRecordsPageInCommandMenu = ({
|
||||
const openMergeRecordsPageInCommandMenu = useCallback(async () => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -71,6 +72,7 @@ export const useOpenMergeRecordsPageInCommandMenu = ({
|
||||
upsertRecordsInStore,
|
||||
navigateCommandMenu,
|
||||
updateCommandMenuNavigationMorphItemsByPage,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
+19
-19
@@ -15,7 +15,6 @@ import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objec
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { getIconColorForObjectType } from '@/object-metadata/utils/getIconColorForObjectType';
|
||||
import { viewableRecordIdState } from '@/object-record/record-right-drawer/states/viewableRecordIdState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { CommandMenuPages } from 'twenty-shared/types';
|
||||
|
||||
import { useRunWorkflowRunOpeningInCommandMenuSideEffects } from '@/workflow/hooks/useRunWorkflowRunOpeningInCommandMenuSideEffects';
|
||||
@@ -25,8 +24,10 @@ import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useIcons } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useOpenRecordInCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const theme = useTheme();
|
||||
const { getIcon } = useIcons();
|
||||
|
||||
@@ -46,14 +47,12 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
isNewRecord?: boolean;
|
||||
resetNavigationStack?: boolean;
|
||||
}) => {
|
||||
const navigationStack = jotaiStore.get(
|
||||
commandMenuNavigationStackState.atom,
|
||||
);
|
||||
const navigationStack = store.get(commandMenuNavigationStackState.atom);
|
||||
|
||||
const currentNavigationStackItem = navigationStack.at(-1);
|
||||
|
||||
if (isDefined(currentNavigationStackItem)) {
|
||||
const currentRecordId = jotaiStore.get(
|
||||
const currentRecordId = store.get(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: currentNavigationStackItem.pageId,
|
||||
}),
|
||||
@@ -66,21 +65,21 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
|
||||
const pageComponentInstanceId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
viewableRecordNameSingularComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectNameSingular,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
viewableRecordIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
recordId,
|
||||
);
|
||||
jotaiStore.set(viewableRecordIdState.atom, recordId);
|
||||
store.set(viewableRecordIdState.atom, recordId);
|
||||
|
||||
const objectMetadataItem = jotaiStore.get(
|
||||
const objectMetadataItem = store.get(
|
||||
objectMetadataItemFamilySelector.selectorFamily({
|
||||
objectName: objectNameSingular,
|
||||
objectNameType: 'singular',
|
||||
@@ -93,14 +92,14 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
);
|
||||
}
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
objectMetadataItem.id,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
@@ -110,43 +109,43 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
},
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
1,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
ContextStoreViewType.ShowPage,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
jotaiStore.get(
|
||||
store.get(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreIsPageInEditModeComponentState.atomFamily({
|
||||
instanceId: pageComponentInstanceId,
|
||||
}),
|
||||
jotaiStore.get(
|
||||
store.get(
|
||||
contextStoreIsPageInEditModeComponentState.atomFamily({
|
||||
instanceId: MAIN_CONTEXT_STORE_INSTANCE_ID,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
const currentMorphItems = jotaiStore.get(
|
||||
const currentMorphItems = store.get(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
);
|
||||
|
||||
@@ -158,7 +157,7 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
const newMorphItemsMap = new Map(currentMorphItems);
|
||||
newMorphItemsMap.set(pageComponentInstanceId, [morphItemToAdd]);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuNavigationMorphItemsByPageState.atom,
|
||||
newMorphItemsMap,
|
||||
);
|
||||
@@ -197,6 +196,7 @@ export const useOpenRecordInCommandMenu = () => {
|
||||
navigateCommandMenu,
|
||||
runWorkflowRunOpeningInCommandMenuSideEffects,
|
||||
theme,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+52
-48
@@ -5,63 +5,67 @@ import { contextStoreFilterGroupsComponentState } from '@/context-store/states/c
|
||||
import { contextStoreFiltersComponentState } from '@/context-store/states/contextStoreFiltersComponentState';
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useResetContextStoreStates = () => {
|
||||
const resetContextStoreStates = useCallback((instanceId: string) => {
|
||||
jotaiStore.set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
const store = useStore();
|
||||
const resetContextStoreStates = useCallback(
|
||||
(instanceId: string) => {
|
||||
store.set(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
);
|
||||
store.set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
{
|
||||
mode: 'selection',
|
||||
selectedRecordIds: [],
|
||||
},
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
store.set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
store.set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreFilterGroupsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
store.set(
|
||||
contextStoreFilterGroupsComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreAnyFieldFilterValueComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
'',
|
||||
);
|
||||
store.set(
|
||||
contextStoreAnyFieldFilterValueComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
'',
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
}, []);
|
||||
store.set(
|
||||
contextStoreCurrentViewIdComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
return { resetContextStoreStates };
|
||||
};
|
||||
|
||||
+11
-10
@@ -10,10 +10,11 @@ import { contextStoreFiltersComponentState } from '@/context-store/states/contex
|
||||
import { contextStoreNumberOfSelectedRecordsComponentState } from '@/context-store/states/contextStoreNumberOfSelectedRecordsComponentState';
|
||||
import { contextStoreTargetedRecordsRuleComponentState } from '@/context-store/states/contextStoreTargetedRecordsRuleComponentState';
|
||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useSetGlobalCommandMenuContext = () => {
|
||||
const store = useStore();
|
||||
const { copyContextStoreStates } = useCopyContextStoreStates();
|
||||
|
||||
const setGlobalCommandMenuContext = useCallback(() => {
|
||||
@@ -22,7 +23,7 @@ export const useSetGlobalCommandMenuContext = () => {
|
||||
instanceIdToCopyTo: COMMAND_MENU_PREVIOUS_COMPONENT_INSTANCE_ID,
|
||||
});
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreTargetedRecordsRuleComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
@@ -32,49 +33,49 @@ export const useSetGlobalCommandMenuContext = () => {
|
||||
},
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreNumberOfSelectedRecordsComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
0,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreFiltersComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreFilterGroupsComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreAnyFieldFilterValueComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
'',
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
contextStoreCurrentViewTypeComponentState.atomFamily({
|
||||
instanceId: COMMAND_MENU_COMPONENT_INSTANCE_ID,
|
||||
}),
|
||||
ContextStoreViewType.Table,
|
||||
);
|
||||
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, {
|
||||
store.set(commandMenuPageInfoState.atom, {
|
||||
title: undefined,
|
||||
Icon: undefined,
|
||||
instanceId: '',
|
||||
});
|
||||
|
||||
jotaiStore.set(hasUserSelectedCommandState.atom, false);
|
||||
}, [copyContextStoreStates]);
|
||||
store.set(hasUserSelectedCommandState.atom, false);
|
||||
}, [copyContextStoreStates, store]);
|
||||
|
||||
return {
|
||||
setGlobalCommandMenuContext,
|
||||
|
||||
+7
-6
@@ -1,10 +1,11 @@
|
||||
import { commandMenuNavigationStackState } from '@/command-menu/states/commandMenuNavigationStackState';
|
||||
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { type IconComponent, IconDotsVertical } from 'twenty-ui/display';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useUpdateCommandMenuPageInfo = () => {
|
||||
const store = useStore();
|
||||
const updateCommandMenuPageInfo = useCallback(
|
||||
({
|
||||
pageTitle,
|
||||
@@ -13,7 +14,7 @@ export const useUpdateCommandMenuPageInfo = () => {
|
||||
pageTitle?: string;
|
||||
pageIcon?: IconComponent;
|
||||
}) => {
|
||||
const commandMenuPageInfo = jotaiStore.get(commandMenuPageInfoState.atom);
|
||||
const commandMenuPageInfo = store.get(commandMenuPageInfoState.atom);
|
||||
|
||||
const newCommandMenuPageInfo = {
|
||||
...commandMenuPageInfo,
|
||||
@@ -21,9 +22,9 @@ export const useUpdateCommandMenuPageInfo = () => {
|
||||
Icon: pageIcon ?? commandMenuPageInfo.Icon ?? IconDotsVertical,
|
||||
};
|
||||
|
||||
jotaiStore.set(commandMenuPageInfoState.atom, newCommandMenuPageInfo);
|
||||
store.set(commandMenuPageInfoState.atom, newCommandMenuPageInfo);
|
||||
|
||||
const commandMenuNavigationStack = jotaiStore.get(
|
||||
const commandMenuNavigationStack = store.get(
|
||||
commandMenuNavigationStackState.atom,
|
||||
);
|
||||
|
||||
@@ -44,12 +45,12 @@ export const useUpdateCommandMenuPageInfo = () => {
|
||||
},
|
||||
];
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuNavigationStackState.atom,
|
||||
newCommandMenuNavigationStack,
|
||||
);
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -3,7 +3,6 @@ import { commandMenuWorkflowIdComponentState } from '@/command-menu/pages/workfl
|
||||
import { commandMenuWorkflowRunIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowRunIdComponentState';
|
||||
import { commandMenuWorkflowStepIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowStepIdComponentState';
|
||||
import { commandMenuWorkflowVersionIdComponentState } from '@/command-menu/pages/workflow/states/commandMenuWorkflowVersionIdComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { type WorkflowRunStepStatus } from '@/workflow/types/Workflow';
|
||||
import { useSetInitialWorkflowRunRightDrawerTab } from '@/workflow/workflow-diagram/hooks/useSetInitialWorkflowRunRightDrawerTab';
|
||||
import { workflowSelectedNodeComponentState } from '@/workflow/workflow-diagram/states/workflowSelectedNodeComponentState';
|
||||
@@ -17,8 +16,10 @@ import {
|
||||
IconSettingsAutomation,
|
||||
} from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useWorkflowCommandMenu = () => {
|
||||
const store = useStore();
|
||||
const { navigateCommandMenu } = useNavigateCommandMenu();
|
||||
const { setInitialWorkflowRunRightDrawerTab } =
|
||||
useSetInitialWorkflowRunRightDrawerTab();
|
||||
@@ -27,7 +28,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
(workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -41,14 +42,14 @@ export const useWorkflowCommandMenu = () => {
|
||||
pageId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
const openWorkflowCreateStepInCommandMenu = useCallback(
|
||||
(workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -62,7 +63,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
pageId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
const openWorkflowEditStepInCommandMenu = useCallback(
|
||||
@@ -74,7 +75,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -82,14 +83,14 @@ export const useWorkflowCommandMenu = () => {
|
||||
);
|
||||
|
||||
if (isDefined(stepId)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowStepIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
stepId,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
workflowSelectedNodeComponentState.atomFamily({
|
||||
instanceId: workflowId,
|
||||
}),
|
||||
@@ -104,14 +105,14 @@ export const useWorkflowCommandMenu = () => {
|
||||
pageId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
const openWorkflowEditStepTypeInCommandMenu = useCallback(
|
||||
(workflowId: string) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -125,7 +126,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
pageId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
const openWorkflowViewStepInCommandMenu = useCallback(
|
||||
@@ -144,13 +145,13 @@ export const useWorkflowCommandMenu = () => {
|
||||
}) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
workflowId,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowVersionIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
@@ -158,14 +159,14 @@ export const useWorkflowCommandMenu = () => {
|
||||
);
|
||||
|
||||
if (isDefined(stepId)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowStepIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
stepId,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
workflowSelectedNodeComponentState.atomFamily({
|
||||
instanceId: workflowVersionId,
|
||||
}),
|
||||
@@ -180,7 +181,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
pageId,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu],
|
||||
[navigateCommandMenu, store],
|
||||
);
|
||||
|
||||
const openWorkflowRunViewStepInCommandMenu = useCallback(
|
||||
@@ -201,26 +202,26 @@ export const useWorkflowCommandMenu = () => {
|
||||
}) => {
|
||||
const pageId = v4();
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
workflowId,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowRunIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
workflowRunId,
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
commandMenuWorkflowStepIdComponentState.atomFamily({
|
||||
instanceId: pageId,
|
||||
}),
|
||||
workflowSelectedNode,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
workflowSelectedNodeComponentState.atomFamily({
|
||||
instanceId: workflowRunId,
|
||||
}),
|
||||
@@ -239,7 +240,7 @@ export const useWorkflowCommandMenu = () => {
|
||||
stepExecutionStatus,
|
||||
});
|
||||
},
|
||||
[navigateCommandMenu, setInitialWorkflowRunRightDrawerTab],
|
||||
[navigateCommandMenu, setInitialWorkflowRunRightDrawerTab, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+6
-6
@@ -49,12 +49,12 @@ export const ChartFiltersSettings = ({
|
||||
const { updateCurrentWidgetConfig } =
|
||||
useUpdateCurrentWidgetConfig(pageLayoutId);
|
||||
|
||||
const currentRecordFiltersAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const currentRecordFilters = useRecoilComponentStateCallbackStateV2(
|
||||
currentRecordFiltersComponentState,
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const currentRecordFilterGroupsAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const currentRecordFilterGroups = useRecoilComponentStateCallbackStateV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
instanceId,
|
||||
);
|
||||
@@ -63,15 +63,15 @@ export const ChartFiltersSettings = ({
|
||||
const chartWidgetConfiguration = widget.configuration;
|
||||
|
||||
const handleFiltersUpdate = () => {
|
||||
const currentRecordFilters = store.get(currentRecordFiltersAtom);
|
||||
const currentRecordFilterGroups = store.get(currentRecordFilterGroupsAtom);
|
||||
const existingRecordFilters = store.get(currentRecordFilters);
|
||||
const existingRecordFilterGroups = store.get(currentRecordFilterGroups);
|
||||
|
||||
updateCurrentWidgetConfig({
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
configToUpdate: {
|
||||
filter: {
|
||||
recordFilters: currentRecordFilters,
|
||||
recordFilterGroups: currentRecordFilterGroups,
|
||||
recordFilters: existingRecordFilters,
|
||||
recordFilterGroups: existingRecordFilterGroups,
|
||||
},
|
||||
} satisfies Partial<ChartWidgetConfiguration>,
|
||||
});
|
||||
|
||||
+7
-6
@@ -5,11 +5,12 @@ import { currentRecordFilterGroupsComponentState } from '@/object-record/record-
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { hasInitializedCurrentRecordFilterGroupsComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFilterGroupsComponentFamilyState';
|
||||
import { hasInitializedCurrentRecordFiltersComponentFamilyState } from '@/views/states/hasInitializedCurrentRecordFiltersComponentFamilyState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useResetChartDraftFiltersSettings = () => {
|
||||
const store = useStore();
|
||||
const { pageLayoutId } = usePageLayoutIdFromContextStoreTargetedRecord();
|
||||
|
||||
const { widgetInEditMode } = useWidgetInEditMode(pageLayoutId);
|
||||
@@ -25,7 +26,7 @@ export const useResetChartDraftFiltersSettings = () => {
|
||||
objectMetadataItemId: objectMetadataItemId,
|
||||
});
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasInitializedCurrentRecordFilterGroupsComponentFamilyState.atomFamily({
|
||||
familyKey: {},
|
||||
instanceId,
|
||||
@@ -33,7 +34,7 @@ export const useResetChartDraftFiltersSettings = () => {
|
||||
false,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasInitializedCurrentRecordFiltersComponentFamilyState.atomFamily({
|
||||
familyKey: {},
|
||||
instanceId,
|
||||
@@ -41,16 +42,16 @@ export const useResetChartDraftFiltersSettings = () => {
|
||||
false,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
currentRecordFiltersComponentState.atomFamily({ instanceId }),
|
||||
[],
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
currentRecordFilterGroupsComponentState.atomFamily({ instanceId }),
|
||||
[],
|
||||
);
|
||||
},
|
||||
[widgetInEditMode],
|
||||
[widgetInEditMode, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+4
-4
@@ -7,7 +7,7 @@ import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useUpdateCurrentWidgetConfig = (pageLayoutIdFromProps: string) => {
|
||||
const pageLayoutDraftAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const pageLayoutDraft = useRecoilComponentStateCallbackStateV2(
|
||||
pageLayoutDraftComponentState,
|
||||
pageLayoutIdFromProps,
|
||||
);
|
||||
@@ -27,8 +27,8 @@ export const useUpdateCurrentWidgetConfig = (pageLayoutIdFromProps: string) => {
|
||||
objectMetadataId?: string | null;
|
||||
configToUpdate?: Partial<PageLayoutWidget['configuration']>;
|
||||
}) => {
|
||||
const prev = store.get(pageLayoutDraftAtom);
|
||||
store.set(pageLayoutDraftAtom, {
|
||||
const prev = store.get(pageLayoutDraft);
|
||||
store.set(pageLayoutDraft, {
|
||||
...prev,
|
||||
tabs: prev.tabs.map((tab) => ({
|
||||
...tab,
|
||||
@@ -47,7 +47,7 @@ export const useUpdateCurrentWidgetConfig = (pageLayoutIdFromProps: string) => {
|
||||
})),
|
||||
});
|
||||
},
|
||||
[pageLayoutDraftAtom, currentlyEditingWidgetId, store],
|
||||
[pageLayoutDraft, currentlyEditingWidgetId, store],
|
||||
);
|
||||
|
||||
return { updateCurrentWidgetConfig };
|
||||
|
||||
+4
-5
@@ -2,13 +2,12 @@ import { useCallback } from 'react';
|
||||
|
||||
import { billingCheckoutSessionState } from '@/auth/states/billingCheckoutSessionState';
|
||||
import { BILLING_CHECKOUT_SESSION_DEFAULT_VALUE } from '@/billing/constants/BillingCheckoutSessionDefaultValue';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useBuildSearchParamsFromUrlSyncedStates = () => {
|
||||
const store = useStore();
|
||||
const buildSearchParamsFromUrlSyncedStates = useCallback(async () => {
|
||||
const billingCheckoutSession = jotaiStore.get(
|
||||
billingCheckoutSessionState.atom,
|
||||
);
|
||||
const billingCheckoutSession = store.get(billingCheckoutSessionState.atom);
|
||||
|
||||
const output = {
|
||||
...(billingCheckoutSession !== BILLING_CHECKOUT_SESSION_DEFAULT_VALUE
|
||||
@@ -19,7 +18,7 @@ export const useBuildSearchParamsFromUrlSyncedStates = () => {
|
||||
};
|
||||
|
||||
return output;
|
||||
}, []);
|
||||
}, [store]);
|
||||
|
||||
return {
|
||||
buildSearchParamsFromUrlSyncedStates,
|
||||
|
||||
+7
-6
@@ -8,11 +8,11 @@ import { useFavorites } from '@/favorites/hooks/useFavorites';
|
||||
import { usePrefetchedFavoritesFoldersData } from '@/favorites/hooks/usePrefetchedFavoritesFoldersData';
|
||||
import { type FavoriteFolder } from '@/favorites/types/FavoriteFolder';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentFamilyStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentFamilyStateCallbackStateV2';
|
||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilComponentStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type FavoriteFolderPickerEffectProps = {
|
||||
record?: ObjectRecord;
|
||||
@@ -21,10 +21,11 @@ type FavoriteFolderPickerEffectProps = {
|
||||
export const FavoriteFolderPickerEffect = ({
|
||||
record,
|
||||
}: FavoriteFolderPickerEffectProps) => {
|
||||
const store = useStore();
|
||||
const [favoriteFolderIdsPicker, setFavoriteFolderIdsPicker] =
|
||||
useRecoilComponentStateV2(favoriteFolderIdsPickerComponentState);
|
||||
|
||||
const favoriteFolderPickerFamilyAtom =
|
||||
const favoriteFolderPickerFamily =
|
||||
useRecoilComponentFamilyStateCallbackStateV2(
|
||||
favoriteFolderPickerComponentFamilyState,
|
||||
);
|
||||
@@ -39,15 +40,15 @@ export const FavoriteFolderPickerEffect = ({
|
||||
const updateFolders = useCallback(
|
||||
(folders: FavoriteFolder[]) => {
|
||||
folders.forEach((folder) => {
|
||||
const atom = favoriteFolderPickerFamilyAtom(folder.id);
|
||||
const currentFolder = jotaiStore.get(atom);
|
||||
const atom = favoriteFolderPickerFamily(folder.id);
|
||||
const currentFolder = store.get(atom);
|
||||
|
||||
if (!isDeeplyEqual(folder, currentFolder)) {
|
||||
jotaiStore.set(atom, folder);
|
||||
store.set(atom, folder);
|
||||
}
|
||||
});
|
||||
},
|
||||
[favoriteFolderPickerFamilyAtom],
|
||||
[favoriteFolderPickerFamily, store],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
+5
-5
@@ -26,7 +26,7 @@ export const useFavoriteFolderPicker = ({
|
||||
record,
|
||||
objectNameSingular,
|
||||
}: useFavoriteFolderPickerProps): useFavoriteFolderPickerReturnType => {
|
||||
const favoriteFoldersMultiSelectCheckedAtom =
|
||||
const favoriteFoldersMultiSelectChecked =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
favoriteFolderPickerCheckedComponentState,
|
||||
);
|
||||
@@ -70,7 +70,7 @@ export const useFavoriteFolderPicker = ({
|
||||
await deleteFavorite(favoriteToDelete.id);
|
||||
};
|
||||
|
||||
const checkedIds = store.get(favoriteFoldersMultiSelectCheckedAtom);
|
||||
const checkedIds = store.get(favoriteFoldersMultiSelectChecked);
|
||||
|
||||
const isAlreadyChecked = checkedIds.includes(folderId);
|
||||
|
||||
@@ -78,7 +78,7 @@ export const useFavoriteFolderPicker = ({
|
||||
await deleteFavoriteForRecord(folderId === 'no-folder');
|
||||
|
||||
const newCheckedIds = checkedIds.filter((id) => id !== folderId);
|
||||
store.set(favoriteFoldersMultiSelectCheckedAtom, newCheckedIds);
|
||||
store.set(favoriteFoldersMultiSelectChecked, newCheckedIds);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ export const useFavoriteFolderPicker = ({
|
||||
}
|
||||
|
||||
const newCheckedIds = [...checkedIds, folderId];
|
||||
store.set(favoriteFoldersMultiSelectCheckedAtom, newCheckedIds);
|
||||
store.set(favoriteFoldersMultiSelectChecked, newCheckedIds);
|
||||
},
|
||||
[
|
||||
favoriteFoldersMultiSelectCheckedAtom,
|
||||
favoriteFoldersMultiSelectChecked,
|
||||
createFavorite,
|
||||
deleteFavorite,
|
||||
favorites,
|
||||
|
||||
+5
-5
@@ -1,17 +1,17 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useMountHeadlessFrontComponent = () => {
|
||||
const store = useStore();
|
||||
const mountHeadlessFrontComponent = useCallback(
|
||||
(frontComponentId: string) => {
|
||||
jotaiStore.set(
|
||||
mountedHeadlessFrontComponentIdsState.atom,
|
||||
(previousIds) => new Set(previousIds).add(frontComponentId),
|
||||
store.set(mountedHeadlessFrontComponentIdsState.atom, (previousIds) =>
|
||||
new Set(previousIds).add(frontComponentId),
|
||||
);
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return mountHeadlessFrontComponent;
|
||||
|
||||
+8
-10
@@ -1,21 +1,19 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { mountedHeadlessFrontComponentIdsState } from '@/front-components/states/mountedHeadlessFrontComponentIdsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useUnmountHeadlessFrontComponent = () => {
|
||||
const store = useStore();
|
||||
const unmountHeadlessFrontComponent = useCallback(
|
||||
(frontComponentId: string) => {
|
||||
jotaiStore.set(
|
||||
mountedHeadlessFrontComponentIdsState.atom,
|
||||
(previousIds) => {
|
||||
const next = new Set(previousIds);
|
||||
next.delete(frontComponentId);
|
||||
return next;
|
||||
},
|
||||
);
|
||||
store.set(mountedHeadlessFrontComponentIdsState.atom, (previousIds) => {
|
||||
const next = new Set(previousIds);
|
||||
next.delete(frontComponentId);
|
||||
return next;
|
||||
});
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return unmountHeadlessFrontComponent;
|
||||
|
||||
+6
-2
@@ -20,8 +20,12 @@ export const ObjectMetadataProviderInitialEffect = () => {
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized) return;
|
||||
if (!isCurrentUserLoaded) return;
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
if (!isCurrentUserLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldLoadReal = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
|
||||
|
||||
+8
-14
@@ -15,20 +15,17 @@ import { type ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||
import { enUS } from 'date-fns/locale';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { type APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { AppPath, type ObjectPermissions } from 'twenty-shared/types';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
useGetCurrentUserQuery,
|
||||
type WorkspaceMember,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||
|
||||
export const UserMetadataProviderInitialEffect = () => {
|
||||
const location = useLocation();
|
||||
const isLoggedIn = useIsLogged();
|
||||
const currentUser = useRecoilValueV2(currentUserState);
|
||||
const store = useStore();
|
||||
@@ -53,28 +50,23 @@ export const UserMetadataProviderInitialEffect = () => {
|
||||
|
||||
const { initializeFormatPreferences } = useInitializeFormatPreferences();
|
||||
|
||||
const isOnAuthPath =
|
||||
isMatchingLocation(location, AppPath.Verify) ||
|
||||
isMatchingLocation(location, AppPath.VerifyEmail);
|
||||
|
||||
const updateLocaleCatalog = useCallback(
|
||||
async (newLocale: keyof typeof APP_LOCALES) => {
|
||||
const localeValue = store.get(dateLocaleStateV2.atom);
|
||||
const localeValue = store.get(dateLocaleState.atom);
|
||||
if (localeValue.locale !== newLocale) {
|
||||
getDateFnsLocale(newLocale).then((localeCatalog) => {
|
||||
const newValue = {
|
||||
locale: newLocale,
|
||||
localeCatalog: localeCatalog || enUS,
|
||||
};
|
||||
store.set(dateLocaleStateV2.atom, newValue);
|
||||
store.set(dateLocaleState.atom, newValue);
|
||||
});
|
||||
}
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
const shouldSkipUserQuery =
|
||||
!isLoggedIn || isDefined(currentUser) || isOnAuthPath;
|
||||
const shouldSkipUserQuery = !isLoggedIn || isDefined(currentUser);
|
||||
|
||||
const { data: userQueryData, loading: userQueryLoading } =
|
||||
useGetCurrentUserQuery({
|
||||
@@ -82,7 +74,9 @@ export const UserMetadataProviderInitialEffect = () => {
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized) return;
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn) {
|
||||
setIsCurrentUserLoaded(true);
|
||||
|
||||
+6
-2
@@ -48,8 +48,12 @@ export const ViewMetadataProviderInitialEffect = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized) return;
|
||||
if (!isCurrentUserLoaded) return;
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
if (!isCurrentUserLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn || !isWorkspaceActiveOrSuspended(currentWorkspace)) {
|
||||
setIsInitialized(true);
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { IconLink, IconPlus, IconTool, useIcons } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { FeatureFlagKey } from '~/generated-metadata/graphql';
|
||||
@@ -43,7 +42,7 @@ export const WorkspaceNavigationMenuItems = () => {
|
||||
const items = useWorkspaceSectionItems();
|
||||
const store = useStore();
|
||||
const enterEditMode = () => {
|
||||
const prefetchNavigationMenuItems = jotaiStore.get(
|
||||
const prefetchNavigationMenuItems = store.get(
|
||||
prefetchNavigationMenuItemsState.atom,
|
||||
);
|
||||
const workspaceNavigationMenuItems = filterWorkspaceNavigationMenuItems(
|
||||
|
||||
+4
-3
@@ -20,14 +20,15 @@ import { openNavigationMenuItemFolderIdsStateV2 } from '@/navigation-menu-item/s
|
||||
import { selectedNavigationMenuItemInEditModeStateV2 } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeStateV2';
|
||||
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
|
||||
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { isWorkspaceDroppableId } from '@/navigation-menu-item/utils/isWorkspaceDroppableId';
|
||||
import { validateAndExtractWorkspaceFolderId } from '@/navigation-menu-item/utils/validateAndExtractWorkspaceFolderId';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useHandleAddToNavigationDrop = () => {
|
||||
const store = useStore();
|
||||
const { addObjectToDraft } = useAddObjectToNavigationMenuDraft();
|
||||
const { addViewToDraft } = useAddViewToNavigationMenuDraft();
|
||||
const { addRecordToDraft } = useAddRecordToNavigationMenuDraft();
|
||||
@@ -64,8 +65,7 @@ export const useHandleAddToNavigationDrop = () => {
|
||||
}
|
||||
|
||||
const payload =
|
||||
jotaiStore.get(addToNavPayloadRegistryStateV2.atom).get(draggableId) ??
|
||||
null;
|
||||
store.get(addToNavPayloadRegistryStateV2.atom).get(draggableId) ?? null;
|
||||
if (!payload) {
|
||||
return;
|
||||
}
|
||||
@@ -203,6 +203,7 @@ export const useHandleAddToNavigationDrop = () => {
|
||||
setIsNavigationMenuInEditMode,
|
||||
setSelectedNavigationMenuItemInEditMode,
|
||||
workspaceNavigationMenuItems,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+4
-3
@@ -3,11 +3,12 @@ import { useCallback } from 'react';
|
||||
import { FIND_MANY_NAVIGATION_MENU_ITEMS } from '@/navigation-menu-item/graphql/queries/findManyNavigationMenuItems';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { prefetchNavigationMenuItemsState } from '@/prefetch/states/prefetchNavigationMenuItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
const store = useStore();
|
||||
const apolloCoreClient = useApolloCoreClient();
|
||||
const cache = apolloCoreClient.cache;
|
||||
|
||||
@@ -18,7 +19,7 @@ export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
const removeNavigationMenuItemsByTargetRecordIds = useCallback(
|
||||
(targetRecordIds: string[]) => {
|
||||
const targetRecordIdsSet = new Set(targetRecordIds);
|
||||
const currentNavigationMenuItems = jotaiStore.get(
|
||||
const currentNavigationMenuItems = store.get(
|
||||
prefetchNavigationMenuItemsState.atom,
|
||||
);
|
||||
|
||||
@@ -41,7 +42,7 @@ export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
};
|
||||
});
|
||||
},
|
||||
[cache, setNavigationMenuItemsState],
|
||||
[cache, setNavigationMenuItemsState, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { type ObjectPathInfo } from '@/navigation/types/ObjectPathInfo';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
@@ -12,8 +11,10 @@ import isEmpty from 'lodash.isempty';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { AppPath, SettingsPath } from 'twenty-shared/types';
|
||||
import { getAppPath, getSettingsPath, isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useDefaultHomePagePath = () => {
|
||||
const store = useStore();
|
||||
const currentUser = useRecoilValueV2(currentUserState);
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
@@ -69,7 +70,7 @@ export const useDefaultHomePagePath = () => {
|
||||
}, [getFirstView, readableAlphaSortedActiveNonSystemObjectMetadataItems]);
|
||||
|
||||
const getDefaultObjectPathInfo = useCallback(() => {
|
||||
const lastVisitedObjectMetadataItemId = jotaiStore.get(
|
||||
const lastVisitedObjectMetadataItemId = store.get(
|
||||
lastVisitedObjectMetadataItemIdState.atom,
|
||||
);
|
||||
|
||||
@@ -91,6 +92,7 @@ export const useDefaultHomePagePath = () => {
|
||||
firstObjectPathInfo,
|
||||
getActiveObjectMetadataItemMatchingId,
|
||||
getFirstView,
|
||||
store,
|
||||
]);
|
||||
|
||||
const defaultHomePagePath = useMemo(() => {
|
||||
|
||||
+6
-5
@@ -1,19 +1,20 @@
|
||||
import { lastVisitedObjectMetadataItemIdState } from '@/navigation/states/lastVisitedObjectMetadataItemIdState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useSetLastVisitedObjectMetadataId = () => {
|
||||
const store = useStore();
|
||||
const setLastVisitedObjectMetadataId = useCallback(
|
||||
({ objectMetadataItemId }: { objectMetadataItemId: string }) => {
|
||||
const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom);
|
||||
const objectMetadataItems = store.get(objectMetadataItemsState.atom);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.id === objectMetadataItemId,
|
||||
);
|
||||
|
||||
const lastVisitedObjectMetadataItemId = jotaiStore.get(
|
||||
const lastVisitedObjectMetadataItemId = store.get(
|
||||
lastVisitedObjectMetadataItemIdState.atom,
|
||||
);
|
||||
|
||||
@@ -21,13 +22,13 @@ export const useSetLastVisitedObjectMetadataId = () => {
|
||||
isDefined(objectMetadataItem) &&
|
||||
lastVisitedObjectMetadataItemId !== objectMetadataItemId
|
||||
) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
lastVisitedObjectMetadataItemIdState.atom,
|
||||
objectMetadataItemId,
|
||||
);
|
||||
}
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+7
-6
@@ -1,12 +1,13 @@
|
||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
const store = useStore();
|
||||
const setLastVisitedViewForObjectMetadataNamePlural = useCallback(
|
||||
async ({
|
||||
objectNamePlural,
|
||||
@@ -15,13 +16,13 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
objectNamePlural: string;
|
||||
viewId: string;
|
||||
}) => {
|
||||
const views = jotaiStore.get(coreViewsState.atom);
|
||||
const views = store.get(coreViewsState.atom);
|
||||
|
||||
const view = views.find(
|
||||
(view: CoreViewWithRelations) => view.id === viewId,
|
||||
);
|
||||
|
||||
const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom);
|
||||
const objectMetadataItems = store.get(objectMetadataItemsState.atom);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.namePlural === objectNamePlural,
|
||||
@@ -35,7 +36,7 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const lastVisitedViewPerObjectMetadataItem = jotaiStore.get(
|
||||
const lastVisitedViewPerObjectMetadataItem = store.get(
|
||||
lastVisitedViewPerObjectMetadataItemState.atom,
|
||||
);
|
||||
|
||||
@@ -43,13 +44,13 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
lastVisitedViewPerObjectMetadataItem?.[objectMetadataItem?.id];
|
||||
|
||||
if (isDefined(objectMetadataItem) && lastVisitedViewId !== viewId) {
|
||||
jotaiStore.set(lastVisitedViewPerObjectMetadataItemState.atom, {
|
||||
store.set(lastVisitedViewPerObjectMetadataItemState.atom, {
|
||||
...lastVisitedViewPerObjectMetadataItem,
|
||||
[objectMetadataItem.id]: viewId,
|
||||
});
|
||||
}
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+4
-3
@@ -1,10 +1,10 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getFieldMetadataItemByIdOrThrow } from '@/object-metadata/utils/getFieldMetadataItemByIdOrThrow';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type GetFieldMetadataItemByIdOrThrowResult = {
|
||||
fieldMetadataItem: FieldMetadataItem;
|
||||
@@ -12,16 +12,17 @@ type GetFieldMetadataItemByIdOrThrowResult = {
|
||||
};
|
||||
|
||||
export const useGetFieldMetadataItemByIdOrThrow = () => {
|
||||
const store = useStore();
|
||||
const getFieldMetadataItemByIdOrThrowCallback = useCallback(
|
||||
(fieldMetadataId: string): GetFieldMetadataItemByIdOrThrowResult => {
|
||||
const objectMetadataItems = jotaiStore.get(objectMetadataItemsState.atom);
|
||||
const objectMetadataItems = store.get(objectMetadataItemsState.atom);
|
||||
|
||||
return getFieldMetadataItemByIdOrThrow({
|
||||
fieldMetadataId,
|
||||
objectMetadataItems,
|
||||
});
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { objectMetadataItemFamilySelector } from '@/object-metadata/states/objectMetadataItemFamilySelector';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useGetRelationMetadata = () =>
|
||||
useCallback(
|
||||
export const useGetRelationMetadata = () => {
|
||||
const store = useStore();
|
||||
|
||||
return useCallback(
|
||||
({
|
||||
fieldMetadataItem,
|
||||
}: {
|
||||
@@ -19,7 +21,7 @@ export const useGetRelationMetadata = () =>
|
||||
|
||||
if (!relation) return null;
|
||||
|
||||
const relationObjectMetadataItem = jotaiStore.get(
|
||||
const relationObjectMetadataItem = store.get(
|
||||
objectMetadataItemFamilySelector.selectorFamily({
|
||||
objectName: relation.targetObjectMetadata.nameSingular,
|
||||
objectNameType: 'singular',
|
||||
@@ -40,5 +42,6 @@ export const useGetRelationMetadata = () =>
|
||||
relationType: relation.type,
|
||||
};
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
};
|
||||
|
||||
+7
-6
@@ -1,28 +1,29 @@
|
||||
import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useLoadMockedObjectMetadataItems = () => {
|
||||
const store = useStore();
|
||||
const loadMockedObjectMetadataItems = useCallback(async () => {
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
jotaiStore.get(objectMetadataItemsState.atom),
|
||||
store.get(objectMetadataItemsState.atom),
|
||||
generatedMockObjectMetadataItems,
|
||||
)
|
||||
) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
objectMetadataItemsState.atom,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
}
|
||||
|
||||
if (jotaiStore.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
jotaiStore.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
if (store.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
store.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
}
|
||||
}, []);
|
||||
}, [store]);
|
||||
|
||||
return {
|
||||
loadMockedObjectMetadataItems,
|
||||
|
||||
+8
-9
@@ -5,17 +5,18 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { enrichObjectMetadataItemsWithPermissions } from '@/object-metadata/utils/enrichObjectMetadataItemsWithPermissions';
|
||||
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { type FetchPolicy, useApolloClient } from '@apollo/client';
|
||||
import { useCallback } from 'react';
|
||||
import { type ObjectPermissions } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { type ObjectMetadataItemsQuery } from '~/generated-metadata/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useRefreshObjectMetadataItems = (
|
||||
fetchPolicy: FetchPolicy = 'network-only',
|
||||
) => {
|
||||
const store = useStore();
|
||||
const client = useApolloClient();
|
||||
|
||||
const replaceObjectMetadataItemIfDifferent = useCallback(
|
||||
@@ -25,9 +26,7 @@ export const useRefreshObjectMetadataItems = (
|
||||
'readableFields' | 'updatableFields'
|
||||
>[],
|
||||
) => {
|
||||
const currentUserWorkspace = jotaiStore.get(
|
||||
currentUserWorkspaceState.atom,
|
||||
);
|
||||
const currentUserWorkspace = store.get(currentUserWorkspaceState.atom);
|
||||
|
||||
if (!isDefined(currentUserWorkspace)) {
|
||||
return;
|
||||
@@ -52,21 +51,21 @@ export const useRefreshObjectMetadataItems = (
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
jotaiStore.get(objectMetadataItemsState.atom),
|
||||
store.get(objectMetadataItemsState.atom),
|
||||
newObjectMetadataItems,
|
||||
) &&
|
||||
newObjectMetadataItems.length > 0
|
||||
) {
|
||||
jotaiStore.set(objectMetadataItemsState.atom, newObjectMetadataItems);
|
||||
store.set(objectMetadataItemsState.atom, newObjectMetadataItems);
|
||||
}
|
||||
|
||||
if (jotaiStore.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
jotaiStore.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
if (store.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
store.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
}
|
||||
|
||||
return newObjectMetadataItems;
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
const refreshObjectMetadataItems = async () => {
|
||||
|
||||
+4
-3
@@ -1,13 +1,14 @@
|
||||
import { availableFieldMetadataItemsForFilterFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForFilterFamilySelector';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useGetDefaultFieldMetadataItemForFilter = () => {
|
||||
const store = useStore();
|
||||
const getDefaultFieldMetadataItemForFilter = useCallback(
|
||||
(objectMetadataItem: ObjectMetadataItem) => {
|
||||
const availableFieldMetadataItemsForFilter = jotaiStore.get(
|
||||
const availableFieldMetadataItemsForFilter = store.get(
|
||||
availableFieldMetadataItemsForFilterFamilySelector.selectorFamily({
|
||||
objectMetadataItemId: objectMetadataItem.id,
|
||||
}),
|
||||
@@ -30,7 +31,7 @@ export const useGetDefaultFieldMetadataItemForFilter = () => {
|
||||
|
||||
return { defaultFieldMetadataItemForFilter };
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+6
-4
@@ -6,12 +6,13 @@ import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentSelectorValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorValueV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentValueV2';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useSetAdvancedFilterDropdownStates = () => {
|
||||
const store = useStore();
|
||||
const rootLevelRecordFilterGroup = useRecoilComponentSelectorValueV2(
|
||||
rootLevelRecordFilterGroupComponentSelector,
|
||||
);
|
||||
@@ -38,21 +39,21 @@ export const useSetAdvancedFilterDropdownStates = () => {
|
||||
recordFilter.id,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
recordFilter,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
recordFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
subFieldNameUsedInDropdownComponentState.atomFamily({
|
||||
instanceId,
|
||||
}),
|
||||
@@ -84,6 +85,7 @@ export const useSetAdvancedFilterDropdownStates = () => {
|
||||
currentRecordFilterGroups,
|
||||
currentRecordFilters,
|
||||
rootLevelRecordFilterGroup,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
+6
-5
@@ -3,10 +3,11 @@ import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useSetRecordFilterUsedInAdvancedFilterDropdownRow = () => {
|
||||
const store = useStore();
|
||||
const setRecordFilterUsedInAdvancedFilterDropdownRow = useCallback(
|
||||
(recordFilter: RecordFilter) => {
|
||||
const advancedFilterRowObjectFilterDropdownComponentInstanceId =
|
||||
@@ -14,28 +15,28 @@ export const useSetRecordFilterUsedInAdvancedFilterDropdownRow = () => {
|
||||
recordFilter.id,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||
instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||
}),
|
||||
recordFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
selectedOperandInDropdownComponentState.atomFamily({
|
||||
instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||
}),
|
||||
recordFilter.operand,
|
||||
);
|
||||
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId: advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||
}),
|
||||
recordFilter,
|
||||
);
|
||||
},
|
||||
[],
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+7
-5
@@ -31,8 +31,8 @@ import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamily
|
||||
import { isFetchingMoreRecordsFamilyState } from '@/object-record/states/isFetchingMoreRecordsFamilyState';
|
||||
import { useFamilyRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useFamilyRecoilValueV2';
|
||||
import { useSetFamilyRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetFamilyRecoilStateV2';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
@@ -81,6 +81,7 @@ export const useFetchMoreRecordsWithPagination = <
|
||||
objectMetadataItem,
|
||||
onCompleted,
|
||||
}: UseFindManyRecordsStateParams<T>) => {
|
||||
const store = useStore();
|
||||
const queryIdentifier = getQueryIdentifier({
|
||||
objectNameSingular,
|
||||
filter,
|
||||
@@ -105,11 +106,11 @@ export const useFetchMoreRecordsWithPagination = <
|
||||
// TODO: put this into a util inspired from https://github.com/apollographql/apollo-client/blob/master/src/utilities/policies/pagination.ts
|
||||
// This function is equivalent to merge function + read function in field policy
|
||||
const fetchMoreRecords = useCallback(async () => {
|
||||
const hasNextPageLocal = jotaiStore.get(
|
||||
const hasNextPageLocal = store.get(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
);
|
||||
|
||||
const lastCursorLocal = jotaiStore.get(
|
||||
const lastCursorLocal = store.get(
|
||||
cursorFamilyState.atomFamily(queryIdentifier),
|
||||
);
|
||||
|
||||
@@ -147,11 +148,11 @@ export const useFetchMoreRecordsWithPagination = <
|
||||
fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo;
|
||||
|
||||
if (isDefined(pageInfo)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
cursorFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.endCursor ?? '',
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.hasNextPage ?? false,
|
||||
);
|
||||
@@ -205,6 +206,7 @@ export const useFetchMoreRecordsWithPagination = <
|
||||
onCompleted,
|
||||
handleFindManyRecordsError,
|
||||
queryIdentifier,
|
||||
store,
|
||||
]);
|
||||
|
||||
const totalCount = data?.[objectMetadataItem.namePlural]?.totalCount;
|
||||
|
||||
+5
-4
@@ -4,9 +4,9 @@ import { type RecordGqlOperationFindManyResult } from '@/object-record/graphql/t
|
||||
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
|
||||
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
|
||||
import { type OnFindManyRecordsCompleted } from '@/object-record/types/OnFindManyRecordsCompleted';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useHandleFindManyRecordsCompleted = <T>({
|
||||
queryIdentifier,
|
||||
@@ -17,6 +17,7 @@ export const useHandleFindManyRecordsCompleted = <T>({
|
||||
objectMetadataItem: ObjectMetadataItem;
|
||||
onCompleted?: OnFindManyRecordsCompleted<T>;
|
||||
}) => {
|
||||
const store = useStore();
|
||||
const handleFindManyRecordsCompleted = useCallback(
|
||||
(data: RecordGqlOperationFindManyResult) => {
|
||||
const pageInfo = data?.[objectMetadataItem.namePlural]?.pageInfo;
|
||||
@@ -31,17 +32,17 @@ export const useHandleFindManyRecordsCompleted = <T>({
|
||||
});
|
||||
|
||||
if (isDefined(data?.[objectMetadataItem.namePlural])) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
cursorFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.endCursor ?? '',
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.hasNextPage ?? false,
|
||||
);
|
||||
}
|
||||
},
|
||||
[objectMetadataItem.namePlural, onCompleted, queryIdentifier],
|
||||
[objectMetadataItem.namePlural, onCompleted, queryIdentifier, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+7
-5
@@ -29,8 +29,8 @@ import {
|
||||
import { DEFAULT_SEARCH_REQUEST_LIMIT } from '@/object-record/constants/DefaultSearchRequestLimit';
|
||||
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
|
||||
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { capitalize, isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export type UseFindManyRecordsParams<T> = ObjectMetadataItemIdentifier &
|
||||
RecordGqlOperationVariables & {
|
||||
@@ -77,6 +77,7 @@ export const useLazyFetchMoreRecordsWithPagination = <
|
||||
fetchMore,
|
||||
objectMetadataItem,
|
||||
}: UseFindManyRecordsStateParams<T>) => {
|
||||
const store = useStore();
|
||||
const queryIdentifier = getQueryIdentifier({
|
||||
objectNameSingular,
|
||||
filter,
|
||||
@@ -92,11 +93,11 @@ export const useLazyFetchMoreRecordsWithPagination = <
|
||||
// This function is equivalent to merge function + read function in field policy
|
||||
const fetchMoreRecordsLazy = useCallback(
|
||||
async (limit = DEFAULT_SEARCH_REQUEST_LIMIT) => {
|
||||
const hasNextPageLocal = jotaiStore.get(
|
||||
const hasNextPageLocal = store.get(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
);
|
||||
|
||||
const lastCursorLocal = jotaiStore.get(
|
||||
const lastCursorLocal = store.get(
|
||||
cursorFamilyState.atomFamily(queryIdentifier),
|
||||
);
|
||||
|
||||
@@ -135,11 +136,11 @@ export const useLazyFetchMoreRecordsWithPagination = <
|
||||
fetchMoreResult?.[objectMetadataItem.namePlural]?.pageInfo;
|
||||
|
||||
if (isDefined(pageInfo)) {
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
cursorFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.endCursor ?? '',
|
||||
);
|
||||
jotaiStore.set(
|
||||
store.set(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
pageInfo.hasNextPage ?? false,
|
||||
);
|
||||
@@ -188,6 +189,7 @@ export const useLazyFetchMoreRecordsWithPagination = <
|
||||
filter,
|
||||
orderBy,
|
||||
handleFindManyRecordsError,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPe
|
||||
import { cursorFamilyState } from '@/object-record/states/cursorFamilyState';
|
||||
import { hasNextPageFamilyState } from '@/object-record/states/hasNextPageFamilyState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { getQueryIdentifier } from '@/object-record/utils/getQueryIdentifier';
|
||||
import { QUERY_DEFAULT_LIMIT_RECORDS } from 'twenty-shared/constants';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
type UseLazyFindManyRecordsParams<T> = Omit<
|
||||
UseFindManyRecordsParams<T>,
|
||||
@@ -31,6 +31,7 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
||||
recordGqlFields,
|
||||
fetchPolicy = 'cache-first',
|
||||
}: UseLazyFindManyRecordsParams<T>) => {
|
||||
const store = useStore();
|
||||
const { objectMetadataItem } = useObjectMetadataItem({
|
||||
objectNameSingular,
|
||||
});
|
||||
@@ -83,8 +84,8 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
||||
|
||||
const findManyRecordsLazy = useCallback(async () => {
|
||||
if (!hasReadPermission) {
|
||||
jotaiStore.set(hasNextPageFamilyState.atomFamily(queryIdentifier), false);
|
||||
jotaiStore.set(cursorFamilyState.atomFamily(queryIdentifier), '');
|
||||
store.set(hasNextPageFamilyState.atomFamily(queryIdentifier), false);
|
||||
store.set(cursorFamilyState.atomFamily(queryIdentifier), '');
|
||||
|
||||
return {
|
||||
data: null,
|
||||
@@ -107,11 +108,8 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
||||
const lastCursor =
|
||||
result?.data?.[objectMetadataItem.namePlural]?.pageInfo.endCursor ?? '';
|
||||
|
||||
jotaiStore.set(
|
||||
hasNextPageFamilyState.atomFamily(queryIdentifier),
|
||||
hasNextPage,
|
||||
);
|
||||
jotaiStore.set(cursorFamilyState.atomFamily(queryIdentifier), lastCursor);
|
||||
store.set(hasNextPageFamilyState.atomFamily(queryIdentifier), hasNextPage);
|
||||
store.set(cursorFamilyState.atomFamily(queryIdentifier), lastCursor);
|
||||
|
||||
const records = getRecordsFromRecordConnection({
|
||||
recordConnection: {
|
||||
@@ -141,6 +139,7 @@ export const useLazyFindManyRecords = <T extends ObjectRecord = ObjectRecord>({
|
||||
objectMetadataItem.namePlural,
|
||||
queryIdentifier,
|
||||
handleFindManyRecordsError,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
+2
-2
@@ -18,12 +18,12 @@ import {
|
||||
type RelativeDateFilter,
|
||||
resolveDateFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { formatDateString } from '~/utils/string/formatDateString';
|
||||
|
||||
export const ObjectFilterDropdownDateInput = () => {
|
||||
const { dateFormat, timeZone } = useContext(UserContext);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleStateV2);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleState);
|
||||
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
|
||||
+2
-2
@@ -21,12 +21,12 @@ import {
|
||||
import { useUserTimezone } from '@/ui/input/components/internal/date/hooks/useUserTimezone';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { Temporal } from 'temporal-polyfill';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { formatDateTimeString } from '~/utils/string/formatDateTimeString';
|
||||
|
||||
export const ObjectFilterDropdownDateTimeInput = () => {
|
||||
const { dateFormat, timeFormat, timeZone } = useContext(UserContext);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleStateV2);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleState);
|
||||
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
|
||||
|
||||
const { userTimezone } = useUserTimezone();
|
||||
|
||||
+14
-12
@@ -5,18 +5,19 @@ import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-recor
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { useCreateRecordFilterFromObjectFilterDropdownCurrentStates } from '@/object-record/record-filter/hooks/useCreateRecordFilterFromObjectFilterDropdownCurrentStates';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentSelectorCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentSelectorCallbackStateV2';
|
||||
import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
const objectFilterDropdownCurrentRecordFilterAtom =
|
||||
const store = useStore();
|
||||
const objectFilterDropdownCurrentRecordFilter =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const fieldMetadataItemUsedInDropdownAtom =
|
||||
const fieldMetadataItemUsedInDropdown =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
@@ -29,20 +30,20 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
|
||||
const applyObjectFilterDropdownFilterValue = useCallback(
|
||||
(newFilterValue: string, newDisplayValue?: string) => {
|
||||
const objectFilterDropdownCurrentRecordFilter = jotaiStore.get(
|
||||
objectFilterDropdownCurrentRecordFilterAtom,
|
||||
const existingObjectFilterDropdownCurrentRecordFilter = store.get(
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
) as RecordFilter | undefined | null;
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = jotaiStore.get(
|
||||
fieldMetadataItemUsedInDropdownAtom,
|
||||
const currentFieldMetadataItemUsedInDropdown = store.get(
|
||||
fieldMetadataItemUsedInDropdown,
|
||||
);
|
||||
|
||||
const objectFilterDropdownFilterNotYetCreated = !isDefined(
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
existingObjectFilterDropdownCurrentRecordFilter,
|
||||
);
|
||||
|
||||
if (objectFilterDropdownFilterNotYetCreated) {
|
||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||
if (!isDefined(currentFieldMetadataItemUsedInDropdown)) {
|
||||
throw new Error(
|
||||
`Field metadata item is not defined in object filter dropdown when setting a filter value to create it, this should not happen.`,
|
||||
);
|
||||
@@ -60,7 +61,7 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter);
|
||||
} else {
|
||||
const newCurrentRecordFilter = {
|
||||
...objectFilterDropdownCurrentRecordFilter,
|
||||
...existingObjectFilterDropdownCurrentRecordFilter,
|
||||
value: newFilterValue,
|
||||
displayValue: newDisplayValue ?? newFilterValue,
|
||||
} satisfies RecordFilter;
|
||||
@@ -69,10 +70,11 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
}
|
||||
},
|
||||
[
|
||||
objectFilterDropdownCurrentRecordFilterAtom,
|
||||
fieldMetadataItemUsedInDropdownAtom,
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
fieldMetadataItemUsedInDropdown,
|
||||
createRecordFilterFromObjectFilterDropdownCurrentStates,
|
||||
upsertObjectFilterDropdownCurrentFilter,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
+9
-7
@@ -2,28 +2,30 @@ import { useCallback } from 'react';
|
||||
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useEmptyRecordFilter = (componentInstanceId?: string) => {
|
||||
const objectFilterDropdownSearchInputAtom =
|
||||
const store = useStore();
|
||||
const objectFilterDropdownSearchInput =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const objectFilterDropdownCurrentRecordFilterAtom =
|
||||
const objectFilterDropdownCurrentRecordFilter =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const emptyRecordFilter = useCallback(() => {
|
||||
jotaiStore.set(objectFilterDropdownSearchInputAtom, '');
|
||||
jotaiStore.set(objectFilterDropdownCurrentRecordFilterAtom, undefined);
|
||||
store.set(objectFilterDropdownSearchInput, '');
|
||||
store.set(objectFilterDropdownCurrentRecordFilter, undefined);
|
||||
}, [
|
||||
objectFilterDropdownSearchInputAtom,
|
||||
objectFilterDropdownCurrentRecordFilterAtom,
|
||||
objectFilterDropdownSearchInput,
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
+24
-22
@@ -7,67 +7,69 @@ import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-rec
|
||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useResetFilterDropdown = (componentInstanceId?: string) => {
|
||||
const objectFilterDropdownSearchInputAtom =
|
||||
const store = useStore();
|
||||
const objectFilterDropdownSearchInput =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const fieldMetadataItemIdUsedInDropdownAtom =
|
||||
const fieldMetadataItemIdUsedInDropdown =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdownAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const selectedOperandInDropdown = useRecoilComponentStateCallbackStateV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const objectFilterDropdownFilterIsSelectedAtom =
|
||||
const objectFilterDropdownFilterIsSelected =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownFilterIsSelectedComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const objectFilterDropdownAnyFieldSearchIsSelectedAtom =
|
||||
const objectFilterDropdownAnyFieldSearchIsSelected =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownAnyFieldSearchIsSelectedComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const objectFilterDropdownIsSelectingCompositeFieldAtom =
|
||||
const objectFilterDropdownIsSelectingCompositeField =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const objectFilterDropdownCurrentRecordFilterAtom =
|
||||
const objectFilterDropdownCurrentRecordFilter =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const resetFilterDropdown = useCallback(() => {
|
||||
jotaiStore.set(objectFilterDropdownSearchInputAtom, '');
|
||||
jotaiStore.set(selectedOperandInDropdownAtom, null);
|
||||
jotaiStore.set(objectFilterDropdownFilterIsSelectedAtom, false);
|
||||
jotaiStore.set(objectFilterDropdownIsSelectingCompositeFieldAtom, false);
|
||||
jotaiStore.set(fieldMetadataItemIdUsedInDropdownAtom, null);
|
||||
jotaiStore.set(objectFilterDropdownCurrentRecordFilterAtom, null);
|
||||
jotaiStore.set(objectFilterDropdownAnyFieldSearchIsSelectedAtom, false);
|
||||
store.set(objectFilterDropdownSearchInput, '');
|
||||
store.set(selectedOperandInDropdown, null);
|
||||
store.set(objectFilterDropdownFilterIsSelected, false);
|
||||
store.set(objectFilterDropdownIsSelectingCompositeField, false);
|
||||
store.set(fieldMetadataItemIdUsedInDropdown, null);
|
||||
store.set(objectFilterDropdownCurrentRecordFilter, null);
|
||||
store.set(objectFilterDropdownAnyFieldSearchIsSelected, false);
|
||||
}, [
|
||||
objectFilterDropdownSearchInputAtom,
|
||||
selectedOperandInDropdownAtom,
|
||||
objectFilterDropdownFilterIsSelectedAtom,
|
||||
objectFilterDropdownIsSelectingCompositeFieldAtom,
|
||||
fieldMetadataItemIdUsedInDropdownAtom,
|
||||
objectFilterDropdownCurrentRecordFilterAtom,
|
||||
objectFilterDropdownAnyFieldSearchIsSelectedAtom,
|
||||
objectFilterDropdownSearchInput,
|
||||
selectedOperandInDropdown,
|
||||
objectFilterDropdownFilterIsSelected,
|
||||
objectFilterDropdownIsSelectingCompositeField,
|
||||
fieldMetadataItemIdUsedInDropdown,
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
objectFilterDropdownAnyFieldSearchIsSelected,
|
||||
store,
|
||||
]);
|
||||
|
||||
return {
|
||||
|
||||
+5
-7
@@ -3,11 +3,12 @@ import { useCallback } from 'react';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useRecoilComponentStateCallbackStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilComponentStateCallbackStateV2';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
export const useUpsertObjectFilterDropdownCurrentFilter = () => {
|
||||
const objectFilterDropdownCurrentRecordFilterAtom =
|
||||
const store = useStore();
|
||||
const objectFilterDropdownCurrentRecordFilter =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
@@ -18,12 +19,9 @@ export const useUpsertObjectFilterDropdownCurrentFilter = () => {
|
||||
(recordFilterToUpsert: RecordFilter) => {
|
||||
upsertRecordFilter(recordFilterToUpsert);
|
||||
|
||||
jotaiStore.set(
|
||||
objectFilterDropdownCurrentRecordFilterAtom,
|
||||
recordFilterToUpsert,
|
||||
);
|
||||
store.set(objectFilterDropdownCurrentRecordFilter, recordFilterToUpsert);
|
||||
},
|
||||
[objectFilterDropdownCurrentRecordFilterAtom, upsertRecordFilter],
|
||||
[objectFilterDropdownCurrentRecordFilter, upsertRecordFilter, store],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+25
-9
@@ -1,24 +1,40 @@
|
||||
import { useSearchRecordGroupField } from '@/object-record/object-options-dropdown/hooks/useSearchRecordGroupField';
|
||||
import { objectOptionsDropdownSearchInputComponentState } from '@/object-record/object-options-dropdown/states/objectOptionsDropdownSearchInputComponentState';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { act } from 'react';
|
||||
import { RecoilRoot } from 'recoil';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
const INSTANCE_ID = 'myViewInstanceId';
|
||||
|
||||
describe('useSearchRecordGroupField', () => {
|
||||
beforeEach(() => {
|
||||
jotaiStore.set(
|
||||
objectOptionsDropdownSearchInputComponentState.atomFamily({
|
||||
instanceId: INSTANCE_ID,
|
||||
}),
|
||||
'',
|
||||
);
|
||||
});
|
||||
|
||||
const renderWithContext = (contextValue: any) =>
|
||||
renderHook(() => useSearchRecordGroupField(), {
|
||||
wrapper: ({ children }) => (
|
||||
<RecoilRoot>
|
||||
<RecordIndexContextProvider value={contextValue}>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'myViewInstanceId' }}
|
||||
>
|
||||
{children}
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
</RecoilRoot>
|
||||
<JotaiProvider store={jotaiStore}>
|
||||
<RecoilRoot>
|
||||
<RecordIndexContextProvider value={contextValue}>
|
||||
<ViewComponentInstanceContext.Provider
|
||||
value={{ instanceId: INSTANCE_ID }}
|
||||
>
|
||||
{children}
|
||||
</ViewComponentInstanceContext.Provider>
|
||||
</RecordIndexContextProvider>
|
||||
</RecoilRoot>
|
||||
</JotaiProvider>
|
||||
),
|
||||
});
|
||||
|
||||
|
||||
+4
-5
@@ -4,7 +4,6 @@ import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type GraphQLView } from '@/views/types/GraphQLView';
|
||||
@@ -40,7 +39,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const existingCoreViews = jotaiStore.get(coreViewsState.atom);
|
||||
const existingCoreViews = store.get(coreViewsState.atom);
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
throw new Error('No view id found');
|
||||
@@ -75,7 +74,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
jotaiStore.set(coreViewsState.atom, [
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
@@ -96,7 +95,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
updateCurrentViewParams.mainGroupByFieldMetadataId = null;
|
||||
await updateCurrentView(updateCurrentViewParams);
|
||||
setRecordIndexViewType(viewType);
|
||||
jotaiStore.set(coreViewsState.atom, [
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
@@ -116,7 +115,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
const calendarFieldMetadataId = availableFieldsForCalendar[0].id;
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
jotaiStore.set(coreViewsState.atom, [
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
|
||||
+6
-6
@@ -28,7 +28,7 @@ export const RecordBoardDataChangedEffect = () => {
|
||||
useRecoilComponentFamilySelectorCallbackStateV2(
|
||||
recordGroupFromGroupValueComponentFamilySelector,
|
||||
);
|
||||
const recordIndexGroupFieldMetadataItemAtom =
|
||||
const recordIndexGroupFieldMetadataItem =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
recordIndexGroupFieldMetadataItemComponentState,
|
||||
);
|
||||
@@ -73,17 +73,17 @@ export const RecordBoardDataChangedEffect = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordIndexGroupFieldMetadataItem = store.get(
|
||||
recordIndexGroupFieldMetadataItemAtom,
|
||||
const currentRecordIndexGroupFieldMetadataItem = store.get(
|
||||
recordIndexGroupFieldMetadataItem,
|
||||
);
|
||||
|
||||
if (!isDefined(recordIndexGroupFieldMetadataItem)) {
|
||||
if (!isDefined(currentRecordIndexGroupFieldMetadataItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordGroupValue =
|
||||
objectRecordOperation.createdRecord[
|
||||
recordIndexGroupFieldMetadataItem.name
|
||||
currentRecordIndexGroupFieldMetadataItem.name
|
||||
];
|
||||
|
||||
const recordGroupDefinitionFromGroupValue = store.get(
|
||||
@@ -157,7 +157,7 @@ export const RecordBoardDataChangedEffect = () => {
|
||||
store,
|
||||
triggerRecordBoardInitialQuery,
|
||||
getShouldInitializeRecordBoardForUpdateInputs,
|
||||
recordIndexGroupFieldMetadataItemAtom,
|
||||
recordIndexGroupFieldMetadataItem,
|
||||
recordGroupFromGroupValueCallbackState,
|
||||
recordIndexRecordIdsByGroupCallbackState,
|
||||
removeRecordsFromBoard,
|
||||
|
||||
+10
-14
@@ -23,12 +23,12 @@ export const RecordBoardDragDropContext = ({
|
||||
}: React.PropsWithChildren) => {
|
||||
const { recordBoardId } = useContext(RecordBoardContext);
|
||||
|
||||
const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const currentRecordSorts = useRecoilComponentStateCallbackStateV2(
|
||||
currentRecordSortsComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordBoardSelectedRecordIdsAtom =
|
||||
const recordBoardSelectedRecordIds =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardId,
|
||||
@@ -36,7 +36,7 @@ export const RecordBoardDragDropContext = ({
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const originalDragSelection = useRecoilComponentStateCallbackStateV2(
|
||||
originalDragSelectionComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
@@ -50,13 +50,11 @@ export const RecordBoardDragDropContext = ({
|
||||
|
||||
const handleDragStart = useCallback(
|
||||
(start: DragStart) => {
|
||||
const currentSelectedRecordIds = store.get(
|
||||
recordBoardSelectedRecordIdsAtom,
|
||||
);
|
||||
const currentSelectedRecordIds = store.get(recordBoardSelectedRecordIds);
|
||||
|
||||
startRecordDrag(start, currentSelectedRecordIds);
|
||||
},
|
||||
[recordBoardSelectedRecordIdsAtom, startRecordDrag, store],
|
||||
[recordBoardSelectedRecordIds, startRecordDrag, store],
|
||||
);
|
||||
|
||||
const handleDragEnd: OnDragEndResponder = useCallback(
|
||||
@@ -65,24 +63,22 @@ export const RecordBoardDragDropContext = ({
|
||||
|
||||
if (!result.destination) return;
|
||||
|
||||
const currentRecordSorts = store.get(currentRecordSortsAtom);
|
||||
const existingRecordSorts = store.get(currentRecordSorts);
|
||||
|
||||
if (currentRecordSorts.length > 0) {
|
||||
if (existingRecordSorts.length > 0) {
|
||||
openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
const originalSelection = store.get(
|
||||
originalDragSelectionAtom,
|
||||
) as string[];
|
||||
const originalSelection = store.get(originalDragSelection) as string[];
|
||||
|
||||
processBoardCardDrop(result, originalSelection);
|
||||
},
|
||||
[
|
||||
processBoardCardDrop,
|
||||
originalDragSelectionAtom,
|
||||
originalDragSelection,
|
||||
endRecordDrag,
|
||||
currentRecordSortsAtom,
|
||||
currentRecordSorts,
|
||||
openModal,
|
||||
store,
|
||||
],
|
||||
|
||||
+2
-8
@@ -22,10 +22,7 @@ export const useActiveRecordBoardCard = (recordBoardId?: string) => {
|
||||
const store = useStore();
|
||||
|
||||
const deactivateBoardCard = useCallback(() => {
|
||||
const activeBoardCardIndexes = store.get(activeBoardCardIndexesState) as
|
||||
| BoardCardIndexes
|
||||
| null
|
||||
| undefined;
|
||||
const activeBoardCardIndexes = store.get(activeBoardCardIndexesState);
|
||||
|
||||
if (!isDefined(activeBoardCardIndexes)) {
|
||||
return;
|
||||
@@ -37,10 +34,7 @@ export const useActiveRecordBoardCard = (recordBoardId?: string) => {
|
||||
|
||||
const activateBoardCard = useCallback(
|
||||
(boardCardIndexes: BoardCardIndexes) => {
|
||||
const activeBoardCardIndexes = store.get(activeBoardCardIndexesState) as
|
||||
| BoardCardIndexes
|
||||
| null
|
||||
| undefined;
|
||||
const activeBoardCardIndexes = store.get(activeBoardCardIndexesState);
|
||||
|
||||
if (
|
||||
activeBoardCardIndexes?.rowIndex === boardCardIndexes.rowIndex &&
|
||||
|
||||
+26
-30
@@ -14,17 +14,17 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
||||
const store = useStore();
|
||||
const isCardFocusedAtom = useRecoilComponentFamilyStateCallbackStateV2(
|
||||
const isCardFocused = useRecoilComponentFamilyStateCallbackStateV2(
|
||||
isRecordBoardCardFocusedComponentFamilyState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const focusedBoardCardIndexesAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const focusedBoardCardIndexes = useRecoilComponentStateCallbackStateV2(
|
||||
focusedRecordBoardCardIndexesComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const isCardFocusActiveAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const isCardFocusActive = useRecoilComponentStateCallbackStateV2(
|
||||
isRecordBoardCardFocusActiveComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
@@ -34,53 +34,49 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
||||
useRemoveFocusItemFromFocusStackById();
|
||||
|
||||
const unfocusBoardCard = useCallback(() => {
|
||||
const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as
|
||||
| BoardCardIndexes
|
||||
| null
|
||||
| undefined;
|
||||
const currentFocusedBoardCardIndexes = store.get(focusedBoardCardIndexes);
|
||||
|
||||
if (!isDefined(focusedBoardCardIndexes)) {
|
||||
if (!isDefined(currentFocusedBoardCardIndexes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const focusId = getRecordBoardCardFocusId({
|
||||
recordBoardId: recordBoardId || '',
|
||||
cardIndexes: focusedBoardCardIndexes,
|
||||
cardIndexes: currentFocusedBoardCardIndexes,
|
||||
});
|
||||
|
||||
removeFocusItemFromFocusStackById({
|
||||
focusId,
|
||||
});
|
||||
|
||||
store.set(focusedBoardCardIndexesAtom, null);
|
||||
store.set(isCardFocusedAtom(focusedBoardCardIndexes), false);
|
||||
store.set(isCardFocusActiveAtom, false);
|
||||
store.set(focusedBoardCardIndexes, null);
|
||||
store.set(isCardFocused(currentFocusedBoardCardIndexes), false);
|
||||
store.set(isCardFocusActive, false);
|
||||
}, [
|
||||
store,
|
||||
focusedBoardCardIndexesAtom,
|
||||
isCardFocusedAtom,
|
||||
isCardFocusActiveAtom,
|
||||
focusedBoardCardIndexes,
|
||||
isCardFocused,
|
||||
isCardFocusActive,
|
||||
recordBoardId,
|
||||
removeFocusItemFromFocusStackById,
|
||||
]);
|
||||
|
||||
const focusBoardCard = useCallback(
|
||||
(boardCardIndexes: BoardCardIndexes) => {
|
||||
const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as
|
||||
| BoardCardIndexes
|
||||
| null
|
||||
| undefined;
|
||||
const currentFocusedBoardCardIndexes = store.get(focusedBoardCardIndexes);
|
||||
|
||||
if (
|
||||
isDefined(focusedBoardCardIndexes) &&
|
||||
(focusedBoardCardIndexes.rowIndex !== boardCardIndexes.rowIndex ||
|
||||
focusedBoardCardIndexes.columnIndex !== boardCardIndexes.columnIndex)
|
||||
isDefined(currentFocusedBoardCardIndexes) &&
|
||||
(currentFocusedBoardCardIndexes.rowIndex !==
|
||||
boardCardIndexes.rowIndex ||
|
||||
currentFocusedBoardCardIndexes.columnIndex !==
|
||||
boardCardIndexes.columnIndex)
|
||||
) {
|
||||
store.set(isCardFocusedAtom(focusedBoardCardIndexes), false);
|
||||
store.set(isCardFocused(currentFocusedBoardCardIndexes), false);
|
||||
|
||||
const currentFocusId = getRecordBoardCardFocusId({
|
||||
recordBoardId: recordBoardId || '',
|
||||
cardIndexes: focusedBoardCardIndexes,
|
||||
cardIndexes: currentFocusedBoardCardIndexes,
|
||||
});
|
||||
|
||||
removeFocusItemFromFocusStackById({
|
||||
@@ -101,15 +97,15 @@ export const useFocusedRecordBoardCard = (recordBoardId?: string) => {
|
||||
},
|
||||
});
|
||||
|
||||
store.set(focusedBoardCardIndexesAtom, boardCardIndexes);
|
||||
store.set(isCardFocusedAtom(boardCardIndexes), true);
|
||||
store.set(isCardFocusActiveAtom, true);
|
||||
store.set(focusedBoardCardIndexes, boardCardIndexes);
|
||||
store.set(isCardFocused(boardCardIndexes), true);
|
||||
store.set(isCardFocusActive, true);
|
||||
},
|
||||
[
|
||||
store,
|
||||
focusedBoardCardIndexesAtom,
|
||||
isCardFocusedAtom,
|
||||
isCardFocusActiveAtom,
|
||||
focusedBoardCardIndexes,
|
||||
isCardFocused,
|
||||
isCardFocusActive,
|
||||
recordBoardId,
|
||||
pushFocusItemToFocusStack,
|
||||
removeFocusItemFromFocusStackById,
|
||||
|
||||
+20
-32
@@ -17,7 +17,7 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
const store = useStore();
|
||||
const { focusBoardCard } = useFocusedRecordBoardCard(recordBoardId);
|
||||
|
||||
const focusedBoardCardIndexesAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const focusedBoardCardIndexes = useRecoilComponentStateCallbackStateV2(
|
||||
focusedRecordBoardCardIndexesComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
@@ -38,9 +38,7 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
|
||||
const firstColumnWithRecords = visibleRecordGroupIds.findIndex(
|
||||
(groupId) => {
|
||||
const recordIdsInGroup = store.get(
|
||||
recordIdsByGroupState(groupId),
|
||||
) as string[];
|
||||
const recordIdsInGroup = store.get(recordIdsByGroupState(groupId));
|
||||
return Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0;
|
||||
},
|
||||
);
|
||||
@@ -55,12 +53,9 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
|
||||
const moveHorizontally = useCallback(
|
||||
(direction: 'left' | 'right') => {
|
||||
const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as
|
||||
| { rowIndex: number; columnIndex: number }
|
||||
| null
|
||||
| undefined;
|
||||
const currentFocusedBoardCardIndexes = store.get(focusedBoardCardIndexes);
|
||||
|
||||
if (!isDefined(focusedBoardCardIndexes)) {
|
||||
if (!isDefined(currentFocusedBoardCardIndexes)) {
|
||||
focusFirstAvailableRecord();
|
||||
return;
|
||||
}
|
||||
@@ -71,8 +66,8 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
|
||||
let newColumnIndex =
|
||||
direction === 'right'
|
||||
? focusedBoardCardIndexes.columnIndex + 1
|
||||
: focusedBoardCardIndexes.columnIndex - 1;
|
||||
? currentFocusedBoardCardIndexes.columnIndex + 1
|
||||
: currentFocusedBoardCardIndexes.columnIndex - 1;
|
||||
|
||||
if (newColumnIndex < 0) {
|
||||
newColumnIndex = 0;
|
||||
@@ -80,7 +75,7 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
newColumnIndex = visibleRecordGroupIds.length - 1;
|
||||
}
|
||||
|
||||
if (newColumnIndex === focusedBoardCardIndexes.columnIndex) {
|
||||
if (newColumnIndex === currentFocusedBoardCardIndexes.columnIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -91,7 +86,7 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
const currentGroupId = visibleRecordGroupIds[newColumnIndex];
|
||||
const recordIdsInGroup = store.get(
|
||||
recordIdsByGroupState(currentGroupId),
|
||||
) as string[];
|
||||
);
|
||||
|
||||
if (Array.isArray(recordIdsInGroup) && recordIdsInGroup.length > 0) {
|
||||
foundColumnWithRecords = true;
|
||||
@@ -117,11 +112,9 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
}
|
||||
|
||||
const currentGroupId = visibleRecordGroupIds[newColumnIndex];
|
||||
const recordIdsInGroup = store.get(
|
||||
recordIdsByGroupState(currentGroupId),
|
||||
) as string[];
|
||||
const recordIdsInGroup = store.get(recordIdsByGroupState(currentGroupId));
|
||||
|
||||
let newRowIndex = focusedBoardCardIndexes.rowIndex;
|
||||
let newRowIndex = currentFocusedBoardCardIndexes.rowIndex;
|
||||
if (newRowIndex >= recordIdsInGroup.length) {
|
||||
newRowIndex = recordIdsInGroup.length - 1;
|
||||
}
|
||||
@@ -133,7 +126,7 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
},
|
||||
[
|
||||
store,
|
||||
focusedBoardCardIndexesAtom,
|
||||
focusedBoardCardIndexes,
|
||||
visibleRecordGroupIds,
|
||||
recordIdsByGroupState,
|
||||
focusBoardCard,
|
||||
@@ -143,12 +136,9 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
|
||||
const moveVertically = useCallback(
|
||||
(direction: 'up' | 'down') => {
|
||||
const focusedBoardCardIndexes = store.get(focusedBoardCardIndexesAtom) as
|
||||
| { rowIndex: number; columnIndex: number }
|
||||
| null
|
||||
| undefined;
|
||||
const currentFocusedBoardCardIndexes = store.get(focusedBoardCardIndexes);
|
||||
|
||||
if (!isDefined(focusedBoardCardIndexes)) {
|
||||
if (!isDefined(currentFocusedBoardCardIndexes)) {
|
||||
focusFirstAvailableRecord();
|
||||
return;
|
||||
}
|
||||
@@ -156,10 +146,8 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
if (visibleRecordGroupIds.length === 0) return;
|
||||
|
||||
const currentGroupId =
|
||||
visibleRecordGroupIds[focusedBoardCardIndexes.columnIndex];
|
||||
const recordIdsInGroup = store.get(
|
||||
recordIdsByGroupState(currentGroupId),
|
||||
) as string[];
|
||||
visibleRecordGroupIds[currentFocusedBoardCardIndexes.columnIndex];
|
||||
const recordIdsInGroup = store.get(recordIdsByGroupState(currentGroupId));
|
||||
|
||||
if (!Array.isArray(recordIdsInGroup) || recordIdsInGroup.length === 0) {
|
||||
focusFirstAvailableRecord();
|
||||
@@ -168,8 +156,8 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
|
||||
let newRowIndex =
|
||||
direction === 'down'
|
||||
? focusedBoardCardIndexes.rowIndex + 1
|
||||
: focusedBoardCardIndexes.rowIndex - 1;
|
||||
? currentFocusedBoardCardIndexes.rowIndex + 1
|
||||
: currentFocusedBoardCardIndexes.rowIndex - 1;
|
||||
|
||||
if (newRowIndex < 0) {
|
||||
newRowIndex = 0;
|
||||
@@ -177,18 +165,18 @@ export const useRecordBoardCardNavigation = (recordBoardId?: string) => {
|
||||
newRowIndex = recordIdsInGroup.length - 1;
|
||||
}
|
||||
|
||||
if (newRowIndex === focusedBoardCardIndexes.rowIndex) {
|
||||
if (newRowIndex === currentFocusedBoardCardIndexes.rowIndex) {
|
||||
return;
|
||||
}
|
||||
|
||||
focusBoardCard({
|
||||
columnIndex: focusedBoardCardIndexes.columnIndex,
|
||||
columnIndex: currentFocusedBoardCardIndexes.columnIndex,
|
||||
rowIndex: newRowIndex,
|
||||
});
|
||||
},
|
||||
[
|
||||
store,
|
||||
focusedBoardCardIndexesAtom,
|
||||
focusedBoardCardIndexes,
|
||||
visibleRecordGroupIds,
|
||||
recordIdsByGroupState,
|
||||
focusBoardCard,
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ export const useRecordBoardSelection = (recordBoardId?: string) => {
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordBoardSelectedRecordIdsAtom =
|
||||
const recordBoardSelectedRecordIds =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardId,
|
||||
@@ -50,12 +50,12 @@ export const useRecordBoardSelection = (recordBoardId?: string) => {
|
||||
);
|
||||
|
||||
const checkIfLastUnselectAndCloseDropdown = useCallback(() => {
|
||||
const recordIds = store.get(recordBoardSelectedRecordIdsAtom);
|
||||
const recordIds = store.get(recordBoardSelectedRecordIds);
|
||||
|
||||
if (recordIds.length === 0) {
|
||||
closeDropdown(dropdownId);
|
||||
}
|
||||
}, [recordBoardSelectedRecordIdsAtom, store, closeDropdown, dropdownId]);
|
||||
}, [recordBoardSelectedRecordIds, store, closeDropdown, dropdownId]);
|
||||
|
||||
return {
|
||||
setRecordAsSelected,
|
||||
|
||||
+9
-10
@@ -1,4 +1,3 @@
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { recordGroupFromGroupValueComponentFamilySelector } from '@/object-record/record-group/states/selectors/recordGroupFromGroupValueComponentFamilySelector';
|
||||
import { recordIndexGroupFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupFieldMetadataComponentState';
|
||||
import { recordIndexRecordIdsByGroupComponentFamilyState } from '@/object-record/record-index/states/recordIndexRecordIdsByGroupComponentFamilyState';
|
||||
@@ -13,7 +12,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useRemoveRecordsFromBoard = () => {
|
||||
const store = useStore();
|
||||
const recordIndexGroupFieldMetadataItemAtom =
|
||||
const recordIndexGroupFieldMetadataItem =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
recordIndexGroupFieldMetadataItemComponentState,
|
||||
);
|
||||
@@ -35,22 +34,22 @@ export const useRemoveRecordsFromBoard = () => {
|
||||
for (const recordIdToRemove of recordIdsToRemove) {
|
||||
const recordToRemove = store.get(
|
||||
recordStoreFamilyState.atomFamily(recordIdToRemove),
|
||||
) as Record<string, unknown> | null | undefined;
|
||||
);
|
||||
|
||||
if (!isDefined(recordToRemove)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const recordIndexGroupFieldMetadataItem = store.get(
|
||||
recordIndexGroupFieldMetadataItemAtom,
|
||||
) as FieldMetadataItem | undefined;
|
||||
const currentRecordIndexGroupFieldMetadataItem = store.get(
|
||||
recordIndexGroupFieldMetadataItem,
|
||||
);
|
||||
|
||||
if (!isDefined(recordIndexGroupFieldMetadataItem)) {
|
||||
if (!isDefined(currentRecordIndexGroupFieldMetadataItem)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const recordGroupValue = recordToRemove[
|
||||
recordIndexGroupFieldMetadataItem.name
|
||||
currentRecordIndexGroupFieldMetadataItem.name
|
||||
] as string | undefined;
|
||||
|
||||
const recordGroupDefinitionFromGroupValue = store.get(
|
||||
@@ -76,7 +75,7 @@ export const useRemoveRecordsFromBoard = () => {
|
||||
] of recordIdsToRemoveByGroup) {
|
||||
const currentRecordIdsForGroup = store.get(
|
||||
recordIndexRecordIdsByGroupFamilyCallbackState(groupId),
|
||||
) as string[];
|
||||
);
|
||||
|
||||
const recordIdsWithoutRemovedRecords = currentRecordIdsForGroup.filter(
|
||||
(recordId) => !recordIdsToRemoveInGroup.includes(recordId),
|
||||
@@ -90,7 +89,7 @@ export const useRemoveRecordsFromBoard = () => {
|
||||
},
|
||||
[
|
||||
store,
|
||||
recordIndexGroupFieldMetadataItemAtom,
|
||||
recordIndexGroupFieldMetadataItem,
|
||||
recordGroupFromGroupValueFamilyCallbackState,
|
||||
recordIndexRecordIdsByGroupFamilyCallbackState,
|
||||
],
|
||||
|
||||
+4
-3
@@ -29,9 +29,10 @@ export const useRemoveSelectedRecordsFromRecordBoard = (
|
||||
const recordIndexRecordIdsByGroupCallbackState =
|
||||
useRecoilComponentFamilyStateCallbackStateV2(
|
||||
recordIndexRecordIdsByGroupComponentFamilyState,
|
||||
recordBoardIndexId,
|
||||
);
|
||||
|
||||
const recordBoardSelectedRecordIdsAtom =
|
||||
const recordBoardSelectedRecordIds =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardIndexId,
|
||||
@@ -42,7 +43,7 @@ export const useRemoveSelectedRecordsFromRecordBoard = (
|
||||
|
||||
const removeSelectedRecordsFromRecordBoard = useCallback(() => {
|
||||
const deletedRecordIds = store.get(
|
||||
recordBoardSelectedRecordIdsAtom,
|
||||
recordBoardSelectedRecordIds,
|
||||
) as string[];
|
||||
|
||||
if (
|
||||
@@ -89,7 +90,7 @@ export const useRemoveSelectedRecordsFromRecordBoard = (
|
||||
groupByFieldMetadataItem,
|
||||
recordIndexRecordIdsByGroupCallbackState,
|
||||
recordGroupDefinitions,
|
||||
recordBoardSelectedRecordIdsAtom,
|
||||
recordBoardSelectedRecordIds,
|
||||
resetRecordBoardSelection,
|
||||
]);
|
||||
|
||||
|
||||
+3
-3
@@ -22,7 +22,7 @@ export const useResetRecordBoardSelection = (recordBoardId?: string) => {
|
||||
recordBoardId,
|
||||
);
|
||||
|
||||
const recordBoardSelectedRecordIdsAtom =
|
||||
const recordBoardSelectedRecordIds =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
recordBoardSelectedRecordIdsComponentSelector,
|
||||
recordBoardId,
|
||||
@@ -38,7 +38,7 @@ export const useResetRecordBoardSelection = (recordBoardId?: string) => {
|
||||
const resetRecordBoardSelection = useCallback(() => {
|
||||
closeDropdown(dropdownId);
|
||||
|
||||
const recordIds = store.get(recordBoardSelectedRecordIdsAtom);
|
||||
const recordIds = store.get(recordBoardSelectedRecordIds);
|
||||
|
||||
for (const recordId of recordIds) {
|
||||
store.set(isRecordBoardCardSelectedFamilyState(recordId), false);
|
||||
@@ -46,7 +46,7 @@ export const useResetRecordBoardSelection = (recordBoardId?: string) => {
|
||||
}, [
|
||||
closeDropdown,
|
||||
dropdownId,
|
||||
recordBoardSelectedRecordIdsAtom,
|
||||
recordBoardSelectedRecordIds,
|
||||
isRecordBoardCardSelectedFamilyState,
|
||||
store,
|
||||
]);
|
||||
|
||||
+9
-8
@@ -8,7 +8,7 @@ import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useSelectAllCards = (recordBoardId?: string) => {
|
||||
const allCardsSelectedStatusAtom = useRecoilComponentSelectorCallbackStateV2(
|
||||
const allCardsSelectedStatus = useRecoilComponentSelectorCallbackStateV2(
|
||||
allCardsSelectedStatusComponentSelector,
|
||||
recordBoardId,
|
||||
);
|
||||
@@ -17,7 +17,7 @@ export const useSelectAllCards = (recordBoardId?: string) => {
|
||||
isRecordBoardCardSelectedComponentFamilyState,
|
||||
recordBoardId,
|
||||
);
|
||||
const allRecordIdsOfAllRecordGroupsAtom =
|
||||
const allRecordIdsOfAllRecordGroups =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
allRecordIdsOfAllRecordGroupsComponentSelector,
|
||||
recordBoardId,
|
||||
@@ -29,22 +29,23 @@ export const useSelectAllCards = (recordBoardId?: string) => {
|
||||
const store = useStore();
|
||||
|
||||
const selectAllCards = useCallback(() => {
|
||||
const allCardsSelectedStatus = store.get(allCardsSelectedStatusAtom);
|
||||
const allRecordIds = store.get(allRecordIdsOfAllRecordGroupsAtom);
|
||||
const currentAllCardsSelectedStatus = store.get(allCardsSelectedStatus);
|
||||
const allRecordIds = store.get(allRecordIdsOfAllRecordGroups);
|
||||
|
||||
if (allCardsSelectedStatus === 'all') {
|
||||
if (currentAllCardsSelectedStatus === 'all') {
|
||||
resetRecordBoardSelection();
|
||||
}
|
||||
|
||||
for (const recordId of allRecordIds) {
|
||||
const isSelected =
|
||||
allCardsSelectedStatus === 'none' || allCardsSelectedStatus === 'some';
|
||||
currentAllCardsSelectedStatus === 'none' ||
|
||||
currentAllCardsSelectedStatus === 'some';
|
||||
|
||||
store.set(isRecordBoardCardSelectedFamilyState(recordId), isSelected);
|
||||
}
|
||||
}, [
|
||||
allCardsSelectedStatusAtom,
|
||||
allRecordIdsOfAllRecordGroupsAtom,
|
||||
allCardsSelectedStatus,
|
||||
allRecordIdsOfAllRecordGroups,
|
||||
resetRecordBoardSelection,
|
||||
isRecordBoardCardSelectedFamilyState,
|
||||
store,
|
||||
|
||||
+7
-5
@@ -14,7 +14,7 @@ import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
const store = useStore();
|
||||
|
||||
const recordGroupFieldMetadataAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const recordGroupFieldMetadata = useRecoilComponentStateCallbackStateV2(
|
||||
recordIndexGroupFieldMetadataItemComponentState,
|
||||
recordBoardId,
|
||||
);
|
||||
@@ -40,16 +40,18 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
recordIndexRecordIdsByGroupFamilyState(currentRecordGroupId),
|
||||
);
|
||||
|
||||
const recordGroupFieldMetadata = store.get(recordGroupFieldMetadataAtom);
|
||||
const currentRecordGroupFieldMetadata = store.get(
|
||||
recordGroupFieldMetadata,
|
||||
);
|
||||
|
||||
if (!isDefined(recordGroupFieldMetadata)) {
|
||||
if (!isDefined(currentRecordGroupFieldMetadata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const recordGroupRowIds = records
|
||||
.filter(
|
||||
(record) =>
|
||||
record[recordGroupFieldMetadata.name] === recordGroup?.value,
|
||||
record[currentRecordGroupFieldMetadata.name] === recordGroup?.value,
|
||||
)
|
||||
.map((record) => record.id);
|
||||
|
||||
@@ -75,7 +77,7 @@ export const useSetRecordIdsForColumn = (recordBoardId?: string) => {
|
||||
},
|
||||
[
|
||||
recordIndexRecordIdsByGroupFamilyState,
|
||||
recordGroupFieldMetadataAtom,
|
||||
recordGroupFieldMetadata,
|
||||
emptyRecordGroupByIdCallbackState,
|
||||
store,
|
||||
],
|
||||
|
||||
+5
-5
@@ -62,22 +62,22 @@ export const useTriggerRecordBoardFetchMore = () => {
|
||||
recordIndexRecordIdsByGroupComponentFamilyState,
|
||||
);
|
||||
|
||||
const recordBoardIsFetchingMoreAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const recordBoardIsFetchingMore = useRecoilComponentStateCallbackStateV2(
|
||||
recordBoardIsFetchingMoreComponentState,
|
||||
);
|
||||
|
||||
const triggerRecordBoardFetchMore = useCallback(async () => {
|
||||
const isAlreadyFetchingMore = store.get(recordBoardIsFetchingMoreAtom);
|
||||
const isAlreadyFetchingMore = store.get(recordBoardIsFetchingMore);
|
||||
|
||||
const cleanStateBeforeExit = () => {
|
||||
store.set(recordBoardIsFetchingMoreAtom, false);
|
||||
store.set(recordBoardIsFetchingMore, false);
|
||||
};
|
||||
|
||||
if (isAlreadyFetchingMore) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.set(recordBoardIsFetchingMoreAtom, true);
|
||||
store.set(recordBoardIsFetchingMore, true);
|
||||
|
||||
const currentOffset = store.get(
|
||||
recordBoardCurrentGroupByQueryOffsetCallbackState,
|
||||
@@ -214,7 +214,7 @@ export const useTriggerRecordBoardFetchMore = () => {
|
||||
upsertRecordsInStore,
|
||||
executeRecordIndexGroupsRecordsLazyGroupBy,
|
||||
recordIndexRecordIdsByGroupCallbackState,
|
||||
recordBoardIsFetchingMoreAtom,
|
||||
recordBoardIsFetchingMore,
|
||||
recordBoardCurrentGroupByQueryOffsetCallbackState,
|
||||
recordBoardShouldFetchMoreInColumnFamilyCallbackState,
|
||||
combinedFilters,
|
||||
|
||||
+4
-4
@@ -44,7 +44,7 @@ export const useTriggerRecordBoardInitialQuery = () => {
|
||||
recordBoardShouldFetchMoreInColumnComponentFamilyState,
|
||||
);
|
||||
|
||||
const recordIndexRecordGroupsAreInInitialLoadingAtom =
|
||||
const recordIndexRecordGroupsAreInInitialLoading =
|
||||
useRecoilComponentStateCallbackStateV2(
|
||||
recordIndexRecordGroupsAreInInitialLoadingComponentState,
|
||||
);
|
||||
@@ -76,10 +76,10 @@ export const useTriggerRecordBoardInitialQuery = () => {
|
||||
});
|
||||
|
||||
const triggerRecordBoardInitialQuery = useCallback(async () => {
|
||||
store.set(recordIndexRecordGroupsAreInInitialLoadingAtom, true);
|
||||
store.set(recordIndexRecordGroupsAreInInitialLoading, true);
|
||||
|
||||
const cleanStateBeforeExit = () => {
|
||||
store.set(recordIndexRecordGroupsAreInInitialLoadingAtom, false);
|
||||
store.set(recordIndexRecordGroupsAreInInitialLoading, false);
|
||||
|
||||
setLastRecordBoardQueryIdentifier(queryIdentifier);
|
||||
|
||||
@@ -165,7 +165,7 @@ export const useTriggerRecordBoardInitialQuery = () => {
|
||||
|
||||
cleanStateBeforeExit();
|
||||
}, [
|
||||
recordIndexRecordGroupsAreInInitialLoadingAtom,
|
||||
recordIndexRecordGroupsAreInInitialLoading,
|
||||
store,
|
||||
executeRecordIndexGroupsRecordsLazyGroupBy,
|
||||
objectMetadataItem,
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ import {
|
||||
turnJSDateToPlainDate,
|
||||
turnPlainDateToShiftedDateInSystemTimeZone,
|
||||
} from 'twenty-shared/utils';
|
||||
import { dateLocaleStateV2 } from '~/localization/states/dateLocaleStateV2';
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
|
||||
// TODO: we could refactor this to use Temporal.PlainDate directly
|
||||
// But it would require recoding the utils here, not really worth it for now
|
||||
@@ -24,7 +24,7 @@ export const useRecordCalendarMonthDaysRange = (
|
||||
selectedDate: Temporal.PlainDate,
|
||||
) => {
|
||||
const currentWorkspaceMember = useRecoilValueV2(currentWorkspaceMemberState);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleStateV2);
|
||||
const dateLocale = useRecoilValueV2(dateLocaleState);
|
||||
|
||||
if (!currentWorkspaceMember) {
|
||||
throw new Error('Current workspace member not found');
|
||||
|
||||
+3
-3
@@ -23,7 +23,7 @@ export const useRecordCalendarSelection = (recordCalendarId?: string) => {
|
||||
recordCalendarId,
|
||||
);
|
||||
|
||||
const recordCalendarSelectedRecordIdsAtom =
|
||||
const recordCalendarSelectedRecordIds =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
recordCalendarSelectedRecordIdsComponentSelector,
|
||||
recordCalendarId,
|
||||
@@ -39,7 +39,7 @@ export const useRecordCalendarSelection = (recordCalendarId?: string) => {
|
||||
const resetRecordSelection = useCallback(() => {
|
||||
closeDropdown(dropdownId);
|
||||
|
||||
const recordIds = store.get(recordCalendarSelectedRecordIdsAtom);
|
||||
const recordIds = store.get(recordCalendarSelectedRecordIds);
|
||||
|
||||
for (const recordId of recordIds) {
|
||||
store.set(isRecordCalendarCardSelectedFamilyState(recordId), false);
|
||||
@@ -47,7 +47,7 @@ export const useRecordCalendarSelection = (recordCalendarId?: string) => {
|
||||
}, [
|
||||
closeDropdown,
|
||||
dropdownId,
|
||||
recordCalendarSelectedRecordIdsAtom,
|
||||
recordCalendarSelectedRecordIds,
|
||||
isRecordCalendarCardSelectedFamilyState,
|
||||
store,
|
||||
]);
|
||||
|
||||
+6
-6
@@ -32,7 +32,7 @@ export const useEndRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const originalSelectionAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const originalSelection = useRecoilComponentStateCallbackStateV2(
|
||||
originalDragSelectionComponentState,
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
@@ -49,13 +49,13 @@ export const useEndRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const isDraggingRecord = useRecoilComponentStateCallbackStateV2(
|
||||
isDraggingRecordComponentState,
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const endRecordDrag = useCallback(() => {
|
||||
store.set(isDraggingRecordAtom, false);
|
||||
store.set(isDraggingRecord, false);
|
||||
|
||||
const currentlyDraggedRecordIds = store.get(draggedRecordIdsCallbackState);
|
||||
|
||||
@@ -90,16 +90,16 @@ export const useEndRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
store.set(isMultiDragActiveCallbackState, false);
|
||||
store.set(draggedRecordIdsCallbackState, []);
|
||||
store.set(primaryDraggedRecordIdCallbackState, null);
|
||||
store.set(originalSelectionAtom, []);
|
||||
store.set(originalSelection, []);
|
||||
}, [
|
||||
store,
|
||||
isMultiDragActiveCallbackState,
|
||||
draggedRecordIdsCallbackState,
|
||||
primaryDraggedRecordIdCallbackState,
|
||||
originalSelectionAtom,
|
||||
originalSelection,
|
||||
isRecordIdPrimaryDragMultipleCallbackState,
|
||||
isRecordIdSecondaryDragMultipleCallbackState,
|
||||
isDraggingRecordAtom,
|
||||
isDraggingRecord,
|
||||
]);
|
||||
|
||||
return { endRecordDrag };
|
||||
|
||||
+2
-5
@@ -43,10 +43,7 @@ export const useProcessCalendarCardDrop = () => {
|
||||
|
||||
const destinationPlainDate = Temporal.PlainDate.from(destinationDate);
|
||||
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId)) as
|
||||
| Record<string, unknown>
|
||||
| null
|
||||
| undefined;
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
|
||||
if (!record) return;
|
||||
|
||||
@@ -61,7 +58,7 @@ export const useProcessCalendarCardDrop = () => {
|
||||
day: destinationPlainDate,
|
||||
timeZone: userTimezone,
|
||||
}),
|
||||
) as string[];
|
||||
);
|
||||
|
||||
const targetDayIsEmpty = destinationRecordIds.length === 0;
|
||||
|
||||
|
||||
+15
-17
@@ -36,22 +36,22 @@ export const useProcessTableWithGroupRecordDrop = () => {
|
||||
recordIndexRecordIdsByGroupComponentFamilyState,
|
||||
);
|
||||
|
||||
const currentRecordSortsAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const currentRecordSorts = useRecoilComponentStateCallbackStateV2(
|
||||
currentRecordSortsComponentState,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2(
|
||||
const selectedRowIds = useRecoilComponentSelectorCallbackStateV2(
|
||||
selectedRowIdsComponentSelector,
|
||||
recordTableId,
|
||||
);
|
||||
|
||||
const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const isDraggingRecord = useRecoilComponentStateCallbackStateV2(
|
||||
isDraggingRecordComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
|
||||
const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const originalDragSelection = useRecoilComponentStateCallbackStateV2(
|
||||
originalDragSelectionComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
@@ -81,19 +81,17 @@ export const useProcessTableWithGroupRecordDrop = () => {
|
||||
throw new Error('Field metadata is not defined');
|
||||
}
|
||||
|
||||
const originalDragSelection = store.get(
|
||||
originalDragSelectionAtom,
|
||||
) as string[];
|
||||
const existingOriginalDragSelection = store.get(originalDragSelection);
|
||||
|
||||
const isDraggingRecord = store.get(isDraggingRecordAtom);
|
||||
const isCurrentlyDraggingRecord = store.get(isDraggingRecord);
|
||||
|
||||
const selectedRecordIds = isDraggingRecord
|
||||
? originalDragSelection
|
||||
: (store.get(selectedRowIdsAtom) as string[]);
|
||||
const selectedRecordIds = isCurrentlyDraggingRecord
|
||||
? existingOriginalDragSelection
|
||||
: store.get(selectedRowIds);
|
||||
|
||||
const currentRecordSorts = store.get(currentRecordSortsAtom);
|
||||
const existingRecordSorts = store.get(currentRecordSorts);
|
||||
|
||||
if (currentRecordSorts.length > 0) {
|
||||
if (existingRecordSorts.length > 0) {
|
||||
openModal(RECORD_INDEX_REMOVE_SORTING_MODAL_ID);
|
||||
return;
|
||||
}
|
||||
@@ -116,13 +114,13 @@ export const useProcessTableWithGroupRecordDrop = () => {
|
||||
});
|
||||
},
|
||||
[
|
||||
currentRecordSortsAtom,
|
||||
currentRecordSorts,
|
||||
store,
|
||||
objectNameSingular,
|
||||
objectMetadataItem.fields,
|
||||
originalDragSelectionAtom,
|
||||
isDraggingRecordAtom,
|
||||
selectedRowIdsAtom,
|
||||
originalDragSelection,
|
||||
isDraggingRecord,
|
||||
selectedRowIds,
|
||||
recordIdsByGroupFamilyState,
|
||||
groupFieldMetadata?.id,
|
||||
openModal,
|
||||
|
||||
+13
-20
@@ -31,16 +31,15 @@ export const useProcessTableWithoutGroupRecordDrop = () => {
|
||||
|
||||
const { updateOneRecord } = useUpdateOneRecord();
|
||||
|
||||
const allRecordIdsWithoutGroupAtom =
|
||||
useRecoilComponentSelectorCallbackStateV2(
|
||||
allRecordIdsWithoutGroupsComponentSelector,
|
||||
);
|
||||
const allRecordIdsWithoutGroup = useRecoilComponentSelectorCallbackStateV2(
|
||||
allRecordIdsWithoutGroupsComponentSelector,
|
||||
);
|
||||
|
||||
const selectedRowIdsAtom = useRecoilComponentSelectorCallbackStateV2(
|
||||
const selectedRowIds = useRecoilComponentSelectorCallbackStateV2(
|
||||
selectedRowIdsComponentSelector,
|
||||
);
|
||||
|
||||
const originalDragSelectionAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const originalDragSelection = useRecoilComponentStateCallbackStateV2(
|
||||
originalDragSelectionComponentState,
|
||||
recordIndexId,
|
||||
);
|
||||
@@ -63,12 +62,10 @@ export const useProcessTableWithoutGroupRecordDrop = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const allSparseRecordIds = store.get(
|
||||
allRecordIdsWithoutGroupAtom,
|
||||
) as string[];
|
||||
const allSparseRecordIds = store.get(allRecordIdsWithoutGroup);
|
||||
|
||||
const draggedRecordId = tableRecordDropResult.draggableId;
|
||||
const selectedRecordIds = store.get(selectedRowIdsAtom) as string[];
|
||||
const selectedRecordIds = store.get(selectedRowIds);
|
||||
|
||||
const isDroppedAfterList =
|
||||
tableRecordDropResult.destination.index + 1 >=
|
||||
@@ -77,9 +74,7 @@ export const useProcessTableWithoutGroupRecordDrop = () => {
|
||||
const recordsWithPosition: RecordWithPosition[] = allSparseRecordIds
|
||||
.filter((recordId): recordId is string => isDefined(recordId))
|
||||
.map((recordId: string) => {
|
||||
const record = store.get(
|
||||
recordStoreFamilyState.atomFamily(recordId),
|
||||
) as { position?: number } | null | undefined;
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
return {
|
||||
id: recordId,
|
||||
position: record?.position ?? 0,
|
||||
@@ -136,14 +131,12 @@ export const useProcessTableWithoutGroupRecordDrop = () => {
|
||||
);
|
||||
}
|
||||
|
||||
const originalDragSelection = store.get(
|
||||
originalDragSelectionAtom,
|
||||
) as string[];
|
||||
const existingOriginalDragSelection = store.get(originalDragSelection);
|
||||
|
||||
const multiDragResult = processMultiDrag({
|
||||
draggedRecordId,
|
||||
targetRecordId: targetRecordId ?? '',
|
||||
selectedRecordIds: originalDragSelection,
|
||||
selectedRecordIds: existingOriginalDragSelection,
|
||||
recordsWithPosition: contiguousRecordsWithPosition,
|
||||
isDroppedAfterList,
|
||||
});
|
||||
@@ -165,13 +158,13 @@ export const useProcessTableWithoutGroupRecordDrop = () => {
|
||||
},
|
||||
[
|
||||
objectNameSingular,
|
||||
selectedRowIdsAtom,
|
||||
selectedRowIds,
|
||||
store,
|
||||
updateOneRecord,
|
||||
openModal,
|
||||
currentRecordSorts,
|
||||
originalDragSelectionAtom,
|
||||
allRecordIdsWithoutGroupAtom,
|
||||
originalDragSelection,
|
||||
allRecordIdsWithoutGroup,
|
||||
triggerTableWithoutGroupDragAndDropOptimisticUpdate,
|
||||
],
|
||||
);
|
||||
|
||||
+7
-7
@@ -44,19 +44,19 @@ export const useStartRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const originalSelectionAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const originalSelection = useRecoilComponentStateCallbackStateV2(
|
||||
originalDragSelectionComponentState,
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const isDraggingRecordAtom = useRecoilComponentStateCallbackStateV2(
|
||||
const isDraggingRecord = useRecoilComponentStateCallbackStateV2(
|
||||
isDraggingRecordComponentState,
|
||||
contextStoreInstanceId,
|
||||
);
|
||||
|
||||
const startRecordDrag = useCallback(
|
||||
(start: DragStart, selectedRecordIds: string[]) => {
|
||||
store.set(isDraggingRecordAtom, true);
|
||||
store.set(isDraggingRecord, true);
|
||||
|
||||
const draggedRecordId = start.draggableId;
|
||||
|
||||
@@ -69,7 +69,7 @@ export const useStartRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
store.set(isMultiDragActiveCallbackState, true);
|
||||
store.set(draggedRecordIdsCallbackState, selectedRecordIds);
|
||||
store.set(primaryDraggedRecordIdCallbackState, draggedRecordId);
|
||||
store.set(originalSelectionAtom, selectedRecordIds);
|
||||
store.set(originalSelection, selectedRecordIds);
|
||||
|
||||
store.set(
|
||||
isRecordIdPrimaryDragMultipleCallbackState({
|
||||
@@ -94,7 +94,7 @@ export const useStartRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
store.set(isMultiDragActiveCallbackState, true);
|
||||
store.set(draggedRecordIdsCallbackState, [draggedRecordId]);
|
||||
store.set(primaryDraggedRecordIdCallbackState, draggedRecordId);
|
||||
store.set(originalSelectionAtom, [draggedRecordId]);
|
||||
store.set(originalSelection, [draggedRecordId]);
|
||||
}
|
||||
},
|
||||
[
|
||||
@@ -102,8 +102,8 @@ export const useStartRecordDrag = (contextStoreInstanceId?: string) => {
|
||||
isMultiDragActiveCallbackState,
|
||||
draggedRecordIdsCallbackState,
|
||||
primaryDraggedRecordIdCallbackState,
|
||||
originalSelectionAtom,
|
||||
isDraggingRecordAtom,
|
||||
originalSelection,
|
||||
isDraggingRecord,
|
||||
isRecordIdSecondaryDragMultipleCallbackState,
|
||||
isRecordIdPrimaryDragMultipleCallbackState,
|
||||
],
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ export const useTriggerTableWithoutGroupDragAndDropOptimisticUpdate = () => {
|
||||
|
||||
const correspondingRecordInStore = store.get(
|
||||
recordStoreFamilyState.atomFamily(recordIdAtRealIndex),
|
||||
) as { id: string; position?: number } | null | undefined;
|
||||
);
|
||||
|
||||
if (
|
||||
isDefined(correspondingRecordInStore) &&
|
||||
|
||||
+1
-4
@@ -8,10 +8,7 @@ export const extractRecordPositions = (
|
||||
store: Store,
|
||||
): RecordWithPosition[] => {
|
||||
return recordIds.map((recordId) => {
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId)) as
|
||||
| { position?: number }
|
||||
| null
|
||||
| undefined;
|
||||
const record = store.get(recordStoreFamilyState.atomFamily(recordId));
|
||||
|
||||
return {
|
||||
id: recordId,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user