Migrate more to Jotai (#17903)

Here we go again
This commit is contained in:
Charles Bochet
2026-02-12 18:13:31 +01:00
committed by GitHub
parent 3075707bf8
commit d5a8cc2085
48 changed files with 134 additions and 105 deletions
@@ -10,6 +10,7 @@ import { type Task } from '@/activities/types/Task';
import { type CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
import { isDefined } from 'twenty-shared/utils';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export const useUpsertActivity = ({
activityObjectNameSingular,
@@ -18,7 +19,9 @@ export const useUpsertActivity = ({
| CoreObjectNameSingular.Task
| CoreObjectNameSingular.Note;
}) => {
const [isActivityInCreateMode] = useRecoilState(isActivityInCreateModeState);
const [isActivityInCreateMode] = useRecoilStateV2(
isActivityInCreateModeState,
);
const { updateOneRecord: updateOneActivity } = useUpdateOneRecord();
@@ -1,5 +1,5 @@
import { createState } from '@/ui/utilities/state/utils/createState';
export const isActivityInCreateModeState = createState<boolean>({
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const isActivityInCreateModeState = createStateV2<boolean>({
key: 'isActivityInCreateModeState',
defaultValue: false,
});
@@ -1,14 +1,14 @@
import { aiModelsState } from '@/client-config/states/aiModelsState';
import { useRecoilValue } from 'recoil';
import { type SelectOption } from 'twenty-ui/input';
import { DEFAULT_FAST_MODEL } from '@/ai/constants/DefaultFastModel';
import { DEFAULT_SMART_MODEL } from '@/ai/constants/DefaultSmartModel';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
export const useAiModelOptions = (
includeDeprecated = false,
): SelectOption<string>[] => {
const aiModels = useRecoilValue(aiModelsState);
const aiModels = useRecoilValueV2(aiModelsState);
return aiModels
.filter((model) => includeDeprecated || !model.deprecated)
@@ -24,7 +24,7 @@ export const useAiModelOptions = (
};
export const useAiModelLabel = (modelId: string | undefined): string => {
const aiModels = useRecoilValue(aiModelsState);
const aiModels = useRecoilValueV2(aiModelsState);
if (!modelId) {
return '';
@@ -1,7 +1,7 @@
import { InMemoryCache, type NormalizedCacheObject } from '@apollo/client';
import { useMemo, useRef } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
@@ -18,6 +18,8 @@ import { appVersionState } from '@/client-config/states/appVersionState';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { AppPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
// eslint-disable-next-line twenty/no-state-useref
@@ -28,14 +30,14 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
currentWorkspaceState,
);
const appVersion = useRecoilValue(appVersionState);
const appVersion = useRecoilValueV2(appVersionState);
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
currentWorkspaceMemberState,
);
const setCurrentUser = useSetRecoilState(currentUserState);
const setCurrentUserWorkspace = useSetRecoilState(currentUserWorkspaceState);
const setPreviousUrl = useSetRecoilState(previousUrlState);
const setPreviousUrl = useSetRecoilStateV2(previousUrlState);
const location = useLocation();
const { enqueueErrorSnackBar } = useSnackBar();
@@ -5,10 +5,12 @@ import { useCurrentUserWorkspaceTwoFactorAuthentication } from '@/settings/two-f
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useLingui } from '@lingui/react/macro';
import { useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilValue } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { AppPath } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
export const TwoFactorAuthenticationSetupEffect = () => {
const { initiateCurrentUserWorkspaceOtpProvisioning } =
@@ -18,8 +20,8 @@ export const TwoFactorAuthenticationSetupEffect = () => {
const navigate = useNavigateApp();
const { origin } = useOrigin();
const loginToken = useRecoilValue(loginTokenState);
const qrCode = useRecoilValue(qrCodeState);
const setQrCodeState = useSetRecoilState(qrCodeState);
const qrCode = useRecoilValueV2(qrCodeState);
const setQrCodeState = useSetRecoilStateV2(qrCodeState);
const { t } = useLingui();
@@ -29,6 +29,7 @@ import {
} from 'twenty-ui/display';
import { type AvailableWorkspace } from '~/generated-metadata/graphql';
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledContentContainer = styled(motion.div)`
margin-bottom: ${({ theme }) => theme.spacing(8)};
@@ -124,7 +125,7 @@ const StyledActionLinkContainer = styled.div`
`;
export const SignInUpGlobalScopeForm = () => {
const authProviders = useRecoilValue(authProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const signInUpStep = useRecoilValue(signInUpStepState);
const { buildWorkspaceUrl } = useBuildWorkspaceUrl();
const { signOut } = useAuth();
@@ -10,10 +10,11 @@ import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Trans, useLingui } from '@lingui/react/macro';
import QRCode from 'react-qr-code';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useSetRecoilState } from 'recoil';
import { IconCopy } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
import { MainButton } from 'twenty-ui/input';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledMainContentContainer = styled.div`
margin-bottom: ${({ theme }) => theme.spacing(8)};
@@ -69,7 +70,7 @@ export const SignInUpTwoFactorAuthenticationProvision = () => {
const { t } = useLingui();
const theme = useTheme();
const { enqueueSuccessSnackBar } = useSnackBar();
const qrCode = useRecoilValue(qrCodeState);
const qrCode = useRecoilValueV2(qrCodeState);
const setSignInUpStep = useSetRecoilState(signInUpStepState);
const handleClick = () => {
@@ -24,13 +24,14 @@ import { isDefined } from 'twenty-shared/utils';
import { buildAppPathWithQueryParams } from '~/utils/buildAppPathWithQueryParams';
import { isMatchingLocation } from '~/utils/isMatchingLocation';
import { useAuth } from '@/auth/hooks/useAuth';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export const useSignInUp = (form: UseFormReturn<Form>) => {
const { enqueueErrorSnackBar } = useSnackBar();
const { t } = useLingui();
const [signInUpStep, setSignInUpStep] = useRecoilState(signInUpStepState);
const [signInUpMode, setSignInUpMode] = useRecoilState(signInUpModeState);
const [signInUpMode, setSignInUpMode] = useRecoilStateV2(signInUpModeState);
const { isOnAWorkspace } = useIsCurrentLocationOnAWorkspace();
const { isCaptchaReady } = useCaptcha();
const setLastAuthenticatedMethod = useSetRecoilState(
@@ -1,5 +1,5 @@
import { createState } from '@/ui/utilities/state/utils/createState';
export const previousUrlState = createState<string>({
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const previousUrlState = createStateV2<string>({
key: 'previousUrlState',
defaultValue: '',
});
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const qrCodeState = createState<string | null>({
export const qrCodeState = createStateV2<string | null>({
key: 'qrCodeState',
defaultValue: null,
});
@@ -1,7 +1,7 @@
import { SignInUpMode } from '@/auth/types/signInUpMode';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const signInUpModeState = createState<SignInUpMode>({
export const signInUpModeState = createStateV2<SignInUpMode>({
key: 'signInUpModeState',
defaultValue: SignInUpMode.SignIn,
});
@@ -1,17 +1,18 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useSetRecoilState } from 'recoil';
import { tokenPairState } from '@/auth/states/tokenPairState';
import { isLoadingTokensFromExtensionState } from '@/chrome-extension-sidecar/states/isLoadingTokensFromExtensionState';
import { chromeExtensionIdState } from '@/client-config/states/chromeExtensionIdState';
import { isInFrame } from '~/utils/isInIframe';
import { isDefined } from 'twenty-shared/utils';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
export const ChromeExtensionSidecarEffect = () => {
const navigate = useNavigate();
const setTokenPair = useSetRecoilState(tokenPairState);
const chromeExtensionId = useRecoilValue(chromeExtensionIdState);
const chromeExtensionId = useRecoilValueV2(chromeExtensionIdState);
const setIsLoadingTokensFromExtension = useSetRecoilState(
isLoadingTokensFromExtensionState,
);
@@ -33,6 +33,7 @@ import { isAttachmentPreviewEnabledStateV2 } from '@/client-config/states/isAtta
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
import { getClientConfig } from '@/client-config/utils/getClientConfig';
import { allowRequestsToTwentyIconsState } from '@/client-config/states/allowRequestsToTwentyIcons';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
type UseClientConfigResult = {
data: { clientConfig: ClientConfig } | undefined;
@@ -43,10 +44,10 @@ type UseClientConfigResult = {
};
export const useClientConfig = (): UseClientConfigResult => {
const setIsAnalyticsEnabled = useSetRecoilState(isAnalyticsEnabledState);
const setIsAnalyticsEnabled = useSetRecoilStateV2(isAnalyticsEnabledState);
const setDomainConfiguration = useSetRecoilState(domainConfigurationState);
const setAuthProviders = useSetRecoilState(authProvidersState);
const setAiModels = useSetRecoilState(aiModelsState);
const setAuthProviders = useSetRecoilStateV2(authProvidersState);
const setAiModels = useSetRecoilStateV2(aiModelsState);
const setIsDeveloperDefaultSignInPrefilled = useSetRecoilState(
isDeveloperDefaultSignInPrefilledState,
@@ -68,7 +69,7 @@ export const useClientConfig = (): UseClientConfigResult => {
const setCaptcha = useSetRecoilState(captchaState);
const setChromeExtensionId = useSetRecoilState(chromeExtensionIdState);
const setChromeExtensionId = useSetRecoilStateV2(chromeExtensionIdState);
const setApiConfig = useSetRecoilState(apiConfigState);
@@ -127,7 +128,7 @@ export const useClientConfig = (): UseClientConfigResult => {
isClickHouseConfiguredState,
);
const setAppVersion = useSetRecoilState(appVersionState);
const setAppVersion = useSetRecoilStateV2(appVersionState);
const fetchClientConfig = useCallback(async () => {
setClientConfigApiStatus((prev) => ({
@@ -1,7 +1,7 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { type ClientAiModelConfig } from '~/generated-metadata/graphql';
export const aiModelsState = createState<ClientAiModelConfig[]>({
export const aiModelsState = createStateV2<ClientAiModelConfig[]>({
key: 'aiModelsState',
defaultValue: [],
});
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const appVersionState = createState<string | undefined>({
export const appVersionState = createStateV2<string | undefined>({
key: 'appVersion',
defaultValue: undefined,
});
@@ -1,7 +1,7 @@
import { type AuthProviders } from '~/generated-metadata/graphql';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const authProvidersState = createState<AuthProviders>({
export const authProvidersState = createStateV2<AuthProviders>({
key: 'authProvidersState',
defaultValue: {
google: true,
@@ -1,5 +1,5 @@
import { createState } from '@/ui/utilities/state/utils/createState';
export const chromeExtensionIdState = createState<string | null | undefined>({
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const chromeExtensionIdState = createStateV2<string | null | undefined>({
key: 'chromeExtensionIdState',
defaultValue: null,
});
@@ -1,5 +1,5 @@
import { createState } from '@/ui/utilities/state/utils/createState';
export const isAnalyticsEnabledState = createState<boolean>({
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const isAnalyticsEnabledState = createStateV2<boolean>({
key: 'isAnalyticsEnabled',
defaultValue: false,
});
@@ -1,5 +1,4 @@
import { useLingui } from '@lingui/react/macro';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { useMergeManyRecords } from '@/object-record/hooks/useMergeManyRecords';
@@ -9,6 +8,8 @@ import { AppPath } from 'twenty-shared/types';
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { isMergeInProgressState } from '@/object-record/record-merge/states/mergeInProgressState';
import { mergeSettingsState } from '@/object-record/record-merge/states/mergeSettingsState';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
type UseMergeRecordsActionsProps = {
objectNameSingular: string;
@@ -17,7 +18,7 @@ type UseMergeRecordsActionsProps = {
export const useMergeRecordsActions = ({
objectNameSingular,
}: UseMergeRecordsActionsProps) => {
const mergeSettings = useRecoilValue(mergeSettingsState);
const mergeSettings = useRecoilValueV2(mergeSettingsState);
const { selectedRecords } = useMergeRecordsSelectedRecords();
@@ -25,7 +26,7 @@ export const useMergeRecordsActions = ({
objectNameSingular,
});
const setMergeInProgress = useSetRecoilState(isMergeInProgressState);
const setMergeInProgress = useSetRecoilStateV2(isMergeInProgressState);
const { t } = useLingui();
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
@@ -1,10 +1,10 @@
import { useRecoilState } from 'recoil';
import { type MergeManySettings } from '@/object-record/hooks/useMergeManyRecords';
import { mergeSettingsState } from '@/object-record/record-merge/states/mergeSettingsState';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export const useMergeRecordsSettings = () => {
const [mergeSettings, setMergeSettings] = useRecoilState(mergeSettingsState);
const [mergeSettings, setMergeSettings] =
useRecoilStateV2(mergeSettingsState);
const updateMergeSettings = (settings: MergeManySettings) => {
setMergeSettings(settings);
@@ -4,9 +4,9 @@ import { useMergeRecordsSelectedRecords } from '@/object-record/record-merge/hoo
import { useUpsertRecordsInStore } from '@/object-record/record-store/hooks/useUpsertRecordsInStore';
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
import { useEffect, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { isMergeInProgressState } from '@/object-record/record-merge/states/mergeInProgressState';
import { mergeSettingsState } from '@/object-record/record-merge/states/mergeSettingsState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
type UseMergePreviewProps = {
objectNameSingular: string;
@@ -20,8 +20,8 @@ export const usePerformMergePreview = ({
const [isGeneratingPreview, setIsGeneratingPreview] = useState(false);
const [isInitialized, setIsInitialized] = useState(false);
const mergeSettings = useRecoilValue(mergeSettingsState);
const isMergeInProgress = useRecoilValue(isMergeInProgressState);
const mergeSettings = useRecoilValueV2(mergeSettingsState);
const isMergeInProgress = useRecoilValueV2(isMergeInProgressState);
const { mergeManyRecords } = useMergeManyRecords({
objectNameSingular,
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const isMergeInProgressState = createState<boolean>({
export const isMergeInProgressState = createStateV2<boolean>({
key: 'isMergeInProgress',
defaultValue: false,
});
@@ -1,7 +1,7 @@
import { type MergeManySettings } from '@/object-record/hooks/useMergeManyRecords';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const mergeSettingsState = createState<MergeManySettings>({
export const mergeSettingsState = createStateV2<MergeManySettings>({
key: 'mergeSettingsState',
defaultValue: {
conflictPriorityIndex: 0,
@@ -9,7 +9,6 @@ import { showHiddenGroupVariablesState } from '@/settings/admin-panel/config-var
import styled from '@emotion/styled';
import { t } from '@lingui/core/macro';
import { useMemo, useState } from 'react';
import { useRecoilState } from 'recoil';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import {
@@ -18,6 +17,7 @@ import {
} from '~/generated-metadata/graphql';
import { normalizeSearchText } from '~/utils/normalizeSearchText';
import { ConfigVariableSearchInput } from './ConfigVariableSearchInput';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
const StyledControlsContainer = styled.div`
display: flex;
@@ -37,11 +37,11 @@ export const SettingsAdminConfigVariables = () => {
const [search, setSearch] = useState('');
const [showHiddenGroupVariables, setShowHiddenGroupVariables] =
useRecoilState(showHiddenGroupVariablesState);
useRecoilStateV2(showHiddenGroupVariablesState);
const [configVariableSourceFilter, setConfigVariableSourceFilter] =
useRecoilState(configVariableSourceFilterState);
useRecoilStateV2(configVariableSourceFilterState);
const [configVariableGroupFilter, setConfigVariableGroupFilter] =
useRecoilState(configVariableGroupFilterState);
useRecoilStateV2(configVariableGroupFilterState);
const allGroups = useMemo(
() => configVariables?.getConfigVariablesGrouped.groups ?? [],
@@ -1,8 +1,8 @@
import { type ConfigVariableGroupFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableGroupFilter';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const configVariableGroupFilterState =
createState<ConfigVariableGroupFilter>({
createStateV2<ConfigVariableGroupFilter>({
key: 'configVariableGroupFilterState',
defaultValue: 'all',
});
@@ -1,8 +1,8 @@
import { type ConfigVariableSourceFilter } from '@/settings/admin-panel/config-variables/types/ConfigVariableSourceFilter';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const configVariableSourceFilterState =
createState<ConfigVariableSourceFilter>({
createStateV2<ConfigVariableSourceFilter>({
key: 'configVariableSourceFilterState',
defaultValue: 'all',
});
@@ -1,6 +1,6 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const showHiddenGroupVariablesState = createState<boolean>({
export const showHiddenGroupVariablesState = createStateV2<boolean>({
key: 'showHiddenGroupVariablesState',
defaultValue: false,
});
@@ -1,8 +1,8 @@
import { useRecoilState } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { publicDomainRecordsState } from '@/settings/domains/states/publicDomainRecordsState';
import { useCheckPublicDomainValidRecordsMutation } from '~/generated-metadata/graphql';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export const useCheckPublicDomainValidRecords = () => {
const [checkPublicDomainValidRecords] =
@@ -10,7 +10,7 @@ export const useCheckPublicDomainValidRecords = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const [{ isLoading, publicDomainRecords }, setPublicDomainRecords] =
useRecoilState(publicDomainRecordsState);
useRecoilStateV2(publicDomainRecordsState);
const checkPublicDomainRecords = (domain: string) => {
if (isLoading) {
@@ -1,7 +1,7 @@
import { type DomainValidRecords } from '~/generated-metadata/graphql';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const publicDomainRecordsState = createState<{
export const publicDomainRecordsState = createStateV2<{
publicDomainRecords: DomainValidRecords | null;
isLoading: boolean;
}>({
@@ -5,7 +5,7 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ApolloError } from '@apollo/client';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilState } from 'recoil';
import { capitalize } from 'twenty-shared/utils';
import { IconGoogle, IconMicrosoft, IconPassword } from 'twenty-ui/display';
import { Card } from 'twenty-ui/layout';
@@ -13,6 +13,7 @@ import {
type AuthProviders,
useUpdateWorkspaceMutation,
} from '~/generated-metadata/graphql';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledSettingsSecurityOptionsList = styled.div`
display: flex;
@@ -24,7 +25,7 @@ export const SettingsSecurityAuthBypassOptionsList = () => {
const { t } = useLingui();
const { enqueueErrorSnackBar } = useSnackBar();
const authProviders = useRecoilValue(authProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
currentWorkspaceState,
@@ -22,6 +22,7 @@ import {
} from '~/generated-metadata/graphql';
import { Toggle2FA } from './Toggle2FA';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledSettingsSecurityOptionsList = styled.div`
display: flex;
@@ -34,7 +35,7 @@ export const SettingsSecurityAuthProvidersOptionsList = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState);
const authProviders = useRecoilValue(authProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
currentWorkspaceState,
@@ -4,8 +4,9 @@ import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { gql, useMutation } from '@apollo/client';
import { useLingui } from '@lingui/react/macro';
import { useEffect } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
const INITIATE_OTP_PROVISIONING_FOR_AUTHENTICATED_USER = gql`
mutation initiateOTPProvisioningForAuthenticatedUser {
@@ -17,7 +18,7 @@ const INITIATE_OTP_PROVISIONING_FOR_AUTHENTICATED_USER = gql`
export const TwoFactorAuthenticationSetupForSettingsEffect = () => {
const { enqueueErrorSnackBar } = useSnackBar();
const [qrCode, setQrCode] = useRecoilState(qrCodeState);
const [qrCode, setQrCode] = useRecoilStateV2(qrCodeState);
const currentUser = useRecoilValue(currentUserState);
const { t } = useLingui();
@@ -1,9 +1,8 @@
import { useRecoilState } from 'recoil';
import { iconPickerState } from '@/ui/input/states/iconPickerState';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export const useIconPicker = () => {
const [iconPicker, setIconPicker] = useRecoilState(iconPickerState);
const [iconPicker, setIconPicker] = useRecoilStateV2(iconPickerState);
return {
Icon: iconPicker.Icon,
@@ -1,4 +1,4 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
import { IconApps, type IconComponent } from 'twenty-ui/display';
type IconPickerState = {
@@ -6,7 +6,7 @@ type IconPickerState = {
iconKey: string;
};
export const iconPickerState = createState<IconPickerState>({
export const iconPickerState = createStateV2<IconPickerState>({
key: 'iconPickerState',
defaultValue: { Icon: IconApps, iconKey: 'IconApps' },
});
@@ -1,5 +1,6 @@
import { act, renderHook } from '@testing-library/react';
import { RecoilRoot, useRecoilValue } from 'recoil';
import { Provider } from 'jotai';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
import { stepBarInternalState } from '@/ui/navigation/step-bar/states/stepBarInternalState';
import { useStepBar } from '@/ui/navigation/step-bar/hooks/useStepBar';
@@ -10,7 +11,7 @@ const renderHooks = (initialStep: number) => {
const { nextStep, prevStep, reset, setStep } = useStepBar({
initialStep,
});
const stepBarInternal = useRecoilValue(stepBarInternalState);
const stepBarInternal = useRecoilValueV2(stepBarInternalState);
return {
nextStep,
@@ -21,7 +22,7 @@ const renderHooks = (initialStep: number) => {
};
},
{
wrapper: RecoilRoot,
wrapper: Provider,
},
);
@@ -1,7 +1,7 @@
import { useCallback, useEffect } from 'react';
import { useRecoilState } from 'recoil';
import { stepBarInternalState } from '@/ui/navigation/step-bar/states/stepBarInternalState';
import { useRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilStateV2';
export type StepsOptions = {
initialStep: number;
@@ -9,7 +9,7 @@ export type StepsOptions = {
export const useStepBar = ({ initialStep }: StepsOptions) => {
const [stepBarInternal, setStepBarInternal] =
useRecoilState(stepBarInternalState);
useRecoilStateV2(stepBarInternalState);
const nextStep = () => {
setStepBarInternal((prevState) => ({
@@ -1,9 +1,9 @@
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export type StepsState = {
activeStep: number;
};
export const stepBarInternalState = createState<StepsState>({
export const stepBarInternalState = createStateV2<StepsState>({
key: 'step-bar/internal-state',
defaultValue: {
activeStep: -1,
@@ -11,7 +11,7 @@ import { useInitializeFormatPreferences } from '@/localization/hooks/useInitiali
import { coreViewsState } from '@/views/states/coreViewState';
import { workspaceAuthBypassProvidersState } from '@/workspace/states/workspaceAuthBypassProvidersState';
import { useCallback } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useSetRecoilState } from 'recoil';
import { SOURCE_LOCALE, type APP_LOCALES } from 'twenty-shared/translations';
import { type ObjectPermissions } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -22,6 +22,7 @@ import {
} from '~/generated-metadata/graphql';
import { getWorkspaceUrl } from '~/utils/getWorkspaceUrl';
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
export const useLoadCurrentUser = () => {
const setCurrentUser = useSetRecoilState(currentUserState);
@@ -41,7 +42,7 @@ export const useLoadCurrentUser = () => {
const setWorkspaceAuthBypassProviders = useSetRecoilState(
workspaceAuthBypassProvidersState,
);
const authProviders = useRecoilValue(authProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const { isOnAWorkspace } = useIsCurrentLocationOnAWorkspace();
@@ -1,14 +1,16 @@
import { useSetRecoilState } from 'recoil';
import {
type SendInvitationsMutationVariables,
useSendInvitationsMutation,
} from '~/generated-metadata/graphql';
import { workspaceInvitationsState } from '@/workspace-invitation/states/workspaceInvitationsStates';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
export const useCreateWorkspaceInvitation = () => {
const [sendInvitationsMutation] = useSendInvitationsMutation();
const setWorkspaceInvitations = useSetRecoilState(workspaceInvitationsState);
const setWorkspaceInvitations = useSetRecoilStateV2(
workspaceInvitationsState,
);
const sendInvitation = async (emails: SendInvitationsMutationVariables) => {
return await sendInvitationsMutation({
@@ -1,15 +1,17 @@
import { useSetRecoilState } from 'recoil';
import {
type DeleteWorkspaceInvitationMutationVariables,
useDeleteWorkspaceInvitationMutation,
} from '~/generated-metadata/graphql';
import { workspaceInvitationsState } from '@/workspace-invitation/states/workspaceInvitationsStates';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
export const useDeleteWorkspaceInvitation = () => {
const [deleteWorkspaceInvitationMutation] =
useDeleteWorkspaceInvitationMutation();
const setWorkspaceInvitations = useSetRecoilState(workspaceInvitationsState);
const setWorkspaceInvitations = useSetRecoilStateV2(
workspaceInvitationsState,
);
const deleteWorkspaceInvitation = async ({
appTokenId,
@@ -1,15 +1,17 @@
import { useSetRecoilState } from 'recoil';
import {
type ResendWorkspaceInvitationMutationVariables,
useResendWorkspaceInvitationMutation,
} from '~/generated-metadata/graphql';
import { workspaceInvitationsState } from '@/workspace-invitation/states/workspaceInvitationsStates';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
export const useResendWorkspaceInvitation = () => {
const [resendWorkspaceInvitationMutation] =
useResendWorkspaceInvitationMutation();
const setWorkspaceInvitations = useSetRecoilState(workspaceInvitationsState);
const setWorkspaceInvitations = useSetRecoilStateV2(
workspaceInvitationsState,
);
const resendInvitation = async ({
appTokenId,
@@ -1,7 +1,7 @@
import { type WorkspaceInvitation } from '@/workspace-member/types/WorkspaceMember';
import { createState } from '@/ui/utilities/state/utils/createState';
import { createStateV2 } from '@/ui/utilities/state/jotai/utils/createStateV2';
export const workspaceInvitationsState = createState<
export const workspaceInvitationsState = createStateV2<
Omit<WorkspaceInvitation, '__typename'>[]
>({
key: 'workspaceInvitationsState',
@@ -2,7 +2,6 @@ import styled from '@emotion/styled';
import { Trans, useLingui } from '@lingui/react/macro';
import { FormProvider } from 'react-hook-form';
import QRCode from 'react-qr-code';
import { useRecoilValue } from 'recoil';
import { qrCodeState } from '@/auth/states/qrCode';
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
@@ -21,6 +20,7 @@ import { getSettingsPath } from 'twenty-shared/utils';
import { H2Title, IconCopy } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
import { Section } from 'twenty-ui/layout';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledQRCodeContainer = styled.div`
margin: ${({ theme }) => theme.spacing(4)} 0;
@@ -81,7 +81,7 @@ export const SettingsTwoFactorAuthenticationMethod = () => {
const { t } = useLingui();
const theme = useTheme();
const { enqueueSuccessSnackBar } = useSnackBar();
const qrCode = useRecoilValue(qrCodeState);
const qrCode = useRecoilValueV2(qrCodeState);
const { currentUserWorkspaceTwoFactorAuthenticationMethods } =
useCurrentUserWorkspaceTwoFactorAuthentication();
@@ -1,5 +1,5 @@
import styled from '@emotion/styled';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useRecoilState } from 'recoil';
import { DEFAULT_FAST_MODEL } from '@/ai/constants/DefaultFastModel';
import { DEFAULT_SMART_MODEL } from '@/ai/constants/DefaultSmartModel';
@@ -22,6 +22,7 @@ import { t } from '@lingui/core/macro';
import { H2Title, IconBolt, IconBrain } from 'twenty-ui/display';
import { Card, Section } from 'twenty-ui/layout';
import { useUpdateWorkspaceMutation } from '~/generated-metadata/graphql';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledSelectContainer = styled.div`
justify-content: flex-end;
@@ -42,7 +43,7 @@ export const SettingsAIRouterSettings = () => {
);
const [updateWorkspace] = useUpdateWorkspaceMutation();
const aiModels = useRecoilValue(aiModelsState);
const aiModels = useRecoilValueV2(aiModelsState);
const activeModelOptions = useAiModelOptions();
const fastModelLabel = useAiModelLabel(currentWorkspace?.fastModel);
const smartModelLabel = useAiModelLabel(currentWorkspace?.smartModel);
@@ -1,6 +1,5 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { aiModelsState } from '@/client-config/states/aiModelsState';
import { InputLabel } from '@/ui/input/components/InputLabel';
@@ -9,6 +8,7 @@ import { isDefined } from 'twenty-shared/utils';
import { IconBrandX, IconWorld } from 'twenty-ui/display';
import { Checkbox } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledCheckboxContainer = styled.div<{ disabled: boolean }>`
display: flex;
@@ -57,7 +57,7 @@ export const SettingsAgentModelCapabilities = ({
disabled = false,
}: SettingsAgentModelCapabilitiesProps) => {
const theme = useTheme();
const aiModels = useRecoilValue(aiModelsState);
const aiModels = useRecoilValueV2(aiModelsState);
const selectedModel = aiModels.find((m) => m.modelId === selectedModelId);
const nativeCapabilities = selectedModel?.nativeCapabilities;
@@ -11,7 +11,6 @@ import { Select } from '@/ui/input/components/Select';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { TextArea } from '@/ui/input/components/TextArea';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-shared/utils';
import { H2Title, IconTrash } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
@@ -22,6 +21,7 @@ import { SettingsAgentResponseFormat } from '~/pages/settings/ai/components/Sett
import { computeMetadataNameFromLabel } from '~/pages/settings/data-model/utils/computeMetadataNameFromLabel';
import { SettingsAgentModelCapabilities } from '~/pages/settings/ai/components/SettingsAgentModelCapabilities';
import { type SettingsAIAgentFormValues } from '~/pages/settings/ai/hooks/useSettingsAgentFormState';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledFormContainer = styled.div`
display: flex;
@@ -66,7 +66,7 @@ export const SettingsAgentSettingsTab = ({
const { t } = useLingui();
const { openModal } = useModal();
const aiModels = useRecoilValue(aiModelsState);
const aiModels = useRecoilValueV2(aiModelsState);
const activeModelOptions = useAiModelOptions();
const currentModelLabel = useAiModelLabel(formValues.modelId);
@@ -4,7 +4,8 @@ import { Trans, useLingui } from '@lingui/react/macro';
import { isNonEmptyArray } from '@sniptt/guards';
import { useMemo, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { useRecoilValue } from 'recoil';
import { useSetRecoilStateV2 } from '@/ui/utilities/state/jotai/hooks/useSetRecoilStateV2';
import { useDebounce } from 'use-debounce';
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
@@ -51,6 +52,7 @@ import { TableRow } from '@/ui/layout/table/components/TableRow';
import { useDeleteWorkspaceInvitation } from '@/workspace-invitation/hooks/useDeleteWorkspaceInvitation';
import { useResendWorkspaceInvitation } from '@/workspace-invitation/hooks/useResendWorkspaceInvitation';
import { workspaceInvitationsState } from '@/workspace-invitation/states/workspaceInvitationsStates';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledButtonContainer = styled.div`
align-items: center;
@@ -152,8 +154,10 @@ export const SettingsWorkspaceMembers = () => {
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const workspaceInvitations = useRecoilValue(workspaceInvitationsState);
const setWorkspaceInvitations = useSetRecoilState(workspaceInvitationsState);
const workspaceInvitations = useRecoilValueV2(workspaceInvitationsState);
const setWorkspaceInvitations = useSetRecoilStateV2(
workspaceInvitationsState,
);
const handleSearchChange = (text: string) => {
setSearchFilter(text);
@@ -34,6 +34,7 @@ import {
import { Button } from 'twenty-ui/input';
import { Card, Section } from 'twenty-ui/layout';
import { useUpdateWorkspaceMutation } from '~/generated-metadata/graphql';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
const StyledContainer = styled.div`
width: 100%;
@@ -63,7 +64,7 @@ export const SettingsSecurity = () => {
const isMultiWorkspaceEnabled = useRecoilValue(isMultiWorkspaceEnabledState);
const isClickHouseConfigured = useRecoilValue(isClickHouseConfiguredState);
const authProviders = useRecoilValue(authProvidersState);
const authProviders = useRecoilValueV2(authProvidersState);
const SSOIdentitiesProviders = useRecoilValue(SSOIdentitiesProvidersState);
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
currentWorkspaceState,