fix(client-config): set isLoaded to false on API status update (#12371)
Attempt at #12289 (edit Félix: removed fix keyword since I don't think it fixes it) --------- Co-authored-by: Félix Malfait <felix.malfait@gmail.com> Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -11,4 +11,5 @@ VITE_DISABLE_ESLINT_CHECKER=true
|
|||||||
# VITE_ENABLE_SSL=false
|
# VITE_ENABLE_SSL=false
|
||||||
# VITE_HOST=localhost.com
|
# VITE_HOST=localhost.com
|
||||||
# SSL_KEY_PATH="./certs/your-cert.key"
|
# SSL_KEY_PATH="./certs/your-cert.key"
|
||||||
# SSL_CERT_PATH="./certs/your-cert.crt"
|
# SSL_CERT_PATH="./certs/your-cert.crt"
|
||||||
|
# IS_DEBUG_MODE=false
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import { InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
import { InMemoryCache, NormalizedCacheObject } from '@apollo/client';
|
||||||
import { useMemo, useRef } from 'react';
|
import { useMemo, useRef } from 'react';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
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 { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
@ -9,7 +9,6 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
|||||||
import { previousUrlState } from '@/auth/states/previousUrlState';
|
import { previousUrlState } from '@/auth/states/previousUrlState';
|
||||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||||
import { workspacesState } from '@/auth/states/workspaces';
|
import { workspacesState } from '@/auth/states/workspaces';
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||||
import { useUpdateEffect } from '~/hooks/useUpdateEffect';
|
import { useUpdateEffect } from '~/hooks/useUpdateEffect';
|
||||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||||
@ -22,18 +21,16 @@ import { ApolloFactory, Options } from '../services/apollo.factory';
|
|||||||
export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
||||||
// eslint-disable-next-line @nx/workspace-no-state-useref
|
// eslint-disable-next-line @nx/workspace-no-state-useref
|
||||||
const apolloRef = useRef<ApolloFactory<NormalizedCacheObject> | null>(null);
|
const apolloRef = useRef<ApolloFactory<NormalizedCacheObject> | null>(null);
|
||||||
const [isDebugMode] = useRecoilState(isDebugModeState);
|
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const setTokenPair = useSetRecoilState(tokenPairState);
|
const setTokenPair = useSetRecoilState(tokenPairState);
|
||||||
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
|
const [currentWorkspace, setCurrentWorkspace] = useRecoilState(
|
||||||
currentWorkspaceState,
|
currentWorkspaceState,
|
||||||
);
|
);
|
||||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
const [currentWorkspaceMember, setCurrentWorkspaceMember] = useRecoilState(
|
||||||
const setCurrentUser = useSetRecoilState(currentUserState);
|
|
||||||
const setCurrentWorkspaceMember = useSetRecoilState(
|
|
||||||
currentWorkspaceMemberState,
|
currentWorkspaceMemberState,
|
||||||
);
|
);
|
||||||
|
const setCurrentUser = useSetRecoilState(currentUserState);
|
||||||
const setCurrentUserWorkspace = useSetRecoilState(currentUserWorkspaceState);
|
const setCurrentUserWorkspace = useSetRecoilState(currentUserWorkspaceState);
|
||||||
|
|
||||||
const setWorkspaces = useSetRecoilState(workspacesState);
|
const setWorkspaces = useSetRecoilState(workspacesState);
|
||||||
@ -50,18 +47,15 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
headers: {
|
|
||||||
...(currentWorkspace?.metadataVersion && {
|
|
||||||
'X-Schema-Version': `${currentWorkspace.metadataVersion}`,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
defaultOptions: {
|
defaultOptions: {
|
||||||
watchQuery: {
|
watchQuery: {
|
||||||
fetchPolicy: 'cache-and-network',
|
fetchPolicy: 'cache-and-network',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
connectToDevTools: isDebugMode,
|
connectToDevTools: process.env.IS_DEBUG_MODE === 'true',
|
||||||
currentWorkspaceMember: currentWorkspaceMember,
|
currentWorkspaceMember: currentWorkspaceMember,
|
||||||
|
currentWorkspace: currentWorkspace,
|
||||||
onTokenPairChange: (tokenPair) => {
|
onTokenPairChange: (tokenPair) => {
|
||||||
setTokenPair(tokenPair);
|
setTokenPair(tokenPair);
|
||||||
},
|
},
|
||||||
@ -83,7 +77,7 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
extraLinks: [],
|
extraLinks: [],
|
||||||
isDebugMode,
|
isDebugMode: process.env.IS_DEBUG_MODE === 'true',
|
||||||
// Override options
|
// Override options
|
||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
@ -96,8 +90,6 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
|||||||
setCurrentWorkspaceMember,
|
setCurrentWorkspaceMember,
|
||||||
setCurrentWorkspace,
|
setCurrentWorkspace,
|
||||||
setWorkspaces,
|
setWorkspaces,
|
||||||
isDebugMode,
|
|
||||||
currentWorkspace?.metadataVersion,
|
|
||||||
setPreviousUrl,
|
setPreviousUrl,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -107,5 +99,11 @@ export const useApolloFactory = (options: Partial<Options<any>> = {}) => {
|
|||||||
}
|
}
|
||||||
}, [currentWorkspaceMember]);
|
}, [currentWorkspaceMember]);
|
||||||
|
|
||||||
|
useUpdateEffect(() => {
|
||||||
|
if (isDefined(apolloRef.current)) {
|
||||||
|
apolloRef.current.updateCurrentWorkspace(currentWorkspace);
|
||||||
|
}
|
||||||
|
}, [currentWorkspace]);
|
||||||
|
|
||||||
return apolloClient;
|
return apolloClient;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { ApolloError, gql, InMemoryCache } from '@apollo/client';
|
import { ApolloError, gql, InMemoryCache } from '@apollo/client';
|
||||||
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
|
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
|
||||||
|
|
||||||
|
import { WorkspaceActivationStatus } from '~/generated/graphql';
|
||||||
import { ApolloFactory, Options } from '../apollo.factory';
|
import { ApolloFactory, Options } from '../apollo.factory';
|
||||||
|
|
||||||
enableFetchMocks();
|
enableFetchMocks();
|
||||||
@ -31,9 +32,32 @@ const mockWorkspaceMember = {
|
|||||||
colorScheme: 'Light' as const,
|
colorScheme: 'Light' as const,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mockWorkspace = {
|
||||||
|
id: 'workspace-id',
|
||||||
|
metadataVersion: 1,
|
||||||
|
allowImpersonation: false,
|
||||||
|
activationStatus: WorkspaceActivationStatus.ACTIVE,
|
||||||
|
billingSubscriptions: [],
|
||||||
|
currentBillingSubscription: null,
|
||||||
|
workspaceMembersCount: 0,
|
||||||
|
isPublicInviteLinkEnabled: false,
|
||||||
|
isGoogleAuthEnabled: false,
|
||||||
|
isMicrosoftAuthEnabled: false,
|
||||||
|
isPasswordAuthEnabled: false,
|
||||||
|
isCustomDomainEnabled: false,
|
||||||
|
hasValidEnterpriseKey: false,
|
||||||
|
subdomain: 'test',
|
||||||
|
customDomain: 'test.com',
|
||||||
|
workspaceUrls: {
|
||||||
|
subdomainUrl: 'test.com',
|
||||||
|
customUrl: 'test.com',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const createMockOptions = (): Options<any> => ({
|
const createMockOptions = (): Options<any> => ({
|
||||||
uri: 'http://localhost:3000',
|
uri: 'http://localhost:3000',
|
||||||
currentWorkspaceMember: mockWorkspaceMember,
|
currentWorkspaceMember: mockWorkspaceMember,
|
||||||
|
currentWorkspace: mockWorkspace,
|
||||||
cache: new InMemoryCache(),
|
cache: new InMemoryCache(),
|
||||||
isDebugMode: true,
|
isDebugMode: true,
|
||||||
onError: mockOnError,
|
onError: mockOnError,
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import { createUploadLink } from 'apollo-upload-client';
|
|||||||
|
|
||||||
import { renewToken } from '@/auth/services/AuthService';
|
import { renewToken } from '@/auth/services/AuthService';
|
||||||
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
import { CurrentWorkspaceMember } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
|
import { CurrentWorkspace } from '@/auth/states/currentWorkspaceState';
|
||||||
import { AuthTokenPair } from '~/generated/graphql';
|
import { AuthTokenPair } from '~/generated/graphql';
|
||||||
import { logDebug } from '~/utils/logDebug';
|
import { logDebug } from '~/utils/logDebug';
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ export interface Options<TCacheShape> extends ApolloClientOptions<TCacheShape> {
|
|||||||
onTokenPairChange?: (tokenPair: AuthTokenPair) => void;
|
onTokenPairChange?: (tokenPair: AuthTokenPair) => void;
|
||||||
onUnauthenticatedError?: () => void;
|
onUnauthenticatedError?: () => void;
|
||||||
currentWorkspaceMember: CurrentWorkspaceMember | null;
|
currentWorkspaceMember: CurrentWorkspaceMember | null;
|
||||||
|
currentWorkspace: CurrentWorkspace | null;
|
||||||
extraLinks?: ApolloLink[];
|
extraLinks?: ApolloLink[];
|
||||||
isDebugMode?: boolean;
|
isDebugMode?: boolean;
|
||||||
}
|
}
|
||||||
@ -41,6 +43,7 @@ export interface Options<TCacheShape> extends ApolloClientOptions<TCacheShape> {
|
|||||||
export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
||||||
private client: ApolloClient<TCacheShape>;
|
private client: ApolloClient<TCacheShape>;
|
||||||
private currentWorkspaceMember: CurrentWorkspaceMember | null = null;
|
private currentWorkspaceMember: CurrentWorkspaceMember | null = null;
|
||||||
|
private currentWorkspace: CurrentWorkspace | null = null;
|
||||||
|
|
||||||
constructor(opts: Options<TCacheShape>) {
|
constructor(opts: Options<TCacheShape>) {
|
||||||
const {
|
const {
|
||||||
@ -50,12 +53,14 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
|||||||
onTokenPairChange,
|
onTokenPairChange,
|
||||||
onUnauthenticatedError,
|
onUnauthenticatedError,
|
||||||
currentWorkspaceMember,
|
currentWorkspaceMember,
|
||||||
|
currentWorkspace,
|
||||||
extraLinks,
|
extraLinks,
|
||||||
isDebugMode,
|
isDebugMode,
|
||||||
...options
|
...options
|
||||||
} = opts;
|
} = opts;
|
||||||
|
|
||||||
this.currentWorkspaceMember = currentWorkspaceMember;
|
this.currentWorkspaceMember = currentWorkspaceMember;
|
||||||
|
this.currentWorkspace = currentWorkspace;
|
||||||
|
|
||||||
const buildApolloLink = (): ApolloLink => {
|
const buildApolloLink = (): ApolloLink => {
|
||||||
const httpLink = createUploadLink({
|
const httpLink = createUploadLink({
|
||||||
@ -84,6 +89,9 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
|||||||
...(this.currentWorkspaceMember?.locale
|
...(this.currentWorkspaceMember?.locale
|
||||||
? { 'x-locale': this.currentWorkspaceMember.locale }
|
? { 'x-locale': this.currentWorkspaceMember.locale }
|
||||||
: { 'x-locale': i18n.locale }),
|
: { 'x-locale': i18n.locale }),
|
||||||
|
...(this.currentWorkspace?.metadataVersion && {
|
||||||
|
'X-Schema-Version': `${this.currentWorkspace.metadataVersion}`,
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -188,6 +196,10 @@ export class ApolloFactory<TCacheShape> implements ApolloManager<TCacheShape> {
|
|||||||
this.currentWorkspaceMember = workspaceMember;
|
this.currentWorkspaceMember = workspaceMember;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateCurrentWorkspace(workspace: CurrentWorkspace | null) {
|
||||||
|
this.currentWorkspace = workspace;
|
||||||
|
}
|
||||||
|
|
||||||
getClient() {
|
getClient() {
|
||||||
return this.client;
|
return this.client;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,7 @@
|
|||||||
|
import { getTokenPair } from '@/apollo/utils/getTokenPair';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
export const hasTokenPair = () => {
|
||||||
|
const tokenPair = getTokenPair();
|
||||||
|
return isDefined(tokenPair) && isDefined(tokenPair.accessToken?.token);
|
||||||
|
};
|
||||||
@ -33,15 +33,15 @@ export const AppRouterProviders = () => {
|
|||||||
const pageTitle = getPageTitleFromPath(pathname);
|
const pageTitle = getPageTitleFromPath(pathname);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CaptchaProvider>
|
<ApolloProvider>
|
||||||
<ApolloProvider>
|
<BaseThemeProvider>
|
||||||
<BaseThemeProvider>
|
<ClientConfigProviderEffect />
|
||||||
<ClientConfigProviderEffect />
|
<UserProviderEffect />
|
||||||
<ClientConfigProvider>
|
<WorkspaceProviderEffect />
|
||||||
|
<ClientConfigProvider>
|
||||||
|
<CaptchaProvider>
|
||||||
<ChromeExtensionSidecarEffect />
|
<ChromeExtensionSidecarEffect />
|
||||||
<ChromeExtensionSidecarProvider>
|
<ChromeExtensionSidecarProvider>
|
||||||
<UserProviderEffect />
|
|
||||||
<WorkspaceProviderEffect />
|
|
||||||
<UserProvider>
|
<UserProvider>
|
||||||
<AuthProvider>
|
<AuthProvider>
|
||||||
<ApolloMetadataClientProvider>
|
<ApolloMetadataClientProvider>
|
||||||
@ -71,9 +71,9 @@ export const AppRouterProviders = () => {
|
|||||||
</AuthProvider>
|
</AuthProvider>
|
||||||
</UserProvider>
|
</UserProvider>
|
||||||
</ChromeExtensionSidecarProvider>
|
</ChromeExtensionSidecarProvider>
|
||||||
</ClientConfigProvider>
|
</CaptchaProvider>
|
||||||
</BaseThemeProvider>
|
</ClientConfigProvider>
|
||||||
</ApolloProvider>
|
</BaseThemeProvider>
|
||||||
</CaptchaProvider>
|
</ApolloProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export const VerifyLoginTokenEffect = () => {
|
|||||||
const navigate = useNavigateApp();
|
const navigate = useNavigateApp();
|
||||||
const { verifyLoginToken } = useVerifyLogin();
|
const { verifyLoginToken } = useVerifyLogin();
|
||||||
|
|
||||||
const { isLoaded: clientConfigLoaded } = useRecoilValue(
|
const { isSaved: clientConfigLoaded } = useRecoilValue(
|
||||||
clientConfigApiStatusState,
|
clientConfigApiStatusState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { useAuth } from '@/auth/hooks/useAuth';
|
import { useAuth } from '@/auth/hooks/useAuth';
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
import { billingState } from '@/client-config/states/billingState';
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
|
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
|
||||||
import { supportChatState } from '@/client-config/states/supportChatState';
|
import { supportChatState } from '@/client-config/states/supportChatState';
|
||||||
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
|
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
|
||||||
@ -118,7 +117,6 @@ describe('useAuth', () => {
|
|||||||
isDeveloperDefaultSignInPrefilledState,
|
isDeveloperDefaultSignInPrefilledState,
|
||||||
);
|
);
|
||||||
const supportChat = useRecoilValue(supportChatState);
|
const supportChat = useRecoilValue(supportChatState);
|
||||||
const isDebugMode = useRecoilValue(isDebugModeState);
|
|
||||||
const isMultiWorkspaceEnabled = useRecoilValue(
|
const isMultiWorkspaceEnabled = useRecoilValue(
|
||||||
isMultiWorkspaceEnabledState,
|
isMultiWorkspaceEnabledState,
|
||||||
);
|
);
|
||||||
@ -131,7 +129,6 @@ describe('useAuth', () => {
|
|||||||
billing,
|
billing,
|
||||||
isDeveloperDefaultSignInPrefilled,
|
isDeveloperDefaultSignInPrefilled,
|
||||||
supportChat,
|
supportChat,
|
||||||
isDebugMode,
|
|
||||||
isMultiWorkspaceEnabled,
|
isMultiWorkspaceEnabled,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -160,7 +157,6 @@ describe('useAuth', () => {
|
|||||||
supportDriver: 'none',
|
supportDriver: 'none',
|
||||||
supportFrontChatId: null,
|
supportFrontChatId: null,
|
||||||
});
|
});
|
||||||
expect(state.isDebugMode).toBe(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle credential sign-up', async () => {
|
it('should handle credential sign-up', async () => {
|
||||||
|
|||||||
@ -11,11 +11,9 @@ import {
|
|||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
|
||||||
import { workspacesState } from '@/auth/states/workspaces';
|
import { workspacesState } from '@/auth/states/workspaces';
|
||||||
import { billingState } from '@/client-config/states/billingState';
|
import { billingState } from '@/client-config/states/billingState';
|
||||||
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
|
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
import { supportChatState } from '@/client-config/states/supportChatState';
|
import { supportChatState } from '@/client-config/states/supportChatState';
|
||||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||||
@ -42,25 +40,27 @@ import { currentUserState } from '../states/currentUserState';
|
|||||||
import { tokenPairState } from '../states/tokenPairState';
|
import { tokenPairState } from '../states/tokenPairState';
|
||||||
|
|
||||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||||
|
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||||
import {
|
import {
|
||||||
SignInUpStep,
|
SignInUpStep,
|
||||||
signInUpStepState,
|
signInUpStepState,
|
||||||
} from '@/auth/states/signInUpStepState';
|
} from '@/auth/states/signInUpStepState';
|
||||||
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
|
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
|
||||||
import { BillingCheckoutSession } from '@/auth/types/billingCheckoutSession.type';
|
import { BillingCheckoutSession } from '@/auth/types/billingCheckoutSession.type';
|
||||||
|
import { apiConfigState } from '@/client-config/states/apiConfigState';
|
||||||
import { captchaState } from '@/client-config/states/captchaState';
|
import { captchaState } from '@/client-config/states/captchaState';
|
||||||
import { isEmailVerificationRequiredState } from '@/client-config/states/isEmailVerificationRequiredState';
|
import { isEmailVerificationRequiredState } from '@/client-config/states/isEmailVerificationRequiredState';
|
||||||
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
|
import { isMultiWorkspaceEnabledState } from '@/client-config/states/isMultiWorkspaceEnabledState';
|
||||||
|
import { sentryConfigState } from '@/client-config/states/sentryConfigState';
|
||||||
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
|
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
|
||||||
import { useLastAuthenticatedWorkspaceDomain } from '@/domain-manager/hooks/useLastAuthenticatedWorkspaceDomain';
|
import { useLastAuthenticatedWorkspaceDomain } from '@/domain-manager/hooks/useLastAuthenticatedWorkspaceDomain';
|
||||||
import { useOrigin } from '@/domain-manager/hooks/useOrigin';
|
import { useOrigin } from '@/domain-manager/hooks/useOrigin';
|
||||||
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
import { useRedirect } from '@/domain-manager/hooks/useRedirect';
|
||||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||||
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
|
import { domainConfigurationState } from '@/domain-manager/states/domainConfigurationState';
|
||||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItem';
|
|
||||||
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
|
import { workspaceAuthProvidersState } from '@/workspace/states/workspaceAuthProvidersState';
|
||||||
import { i18n } from '@lingui/core';
|
import { i18n } from '@lingui/core';
|
||||||
import { useSearchParams } from 'react-router-dom';
|
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||||
import { APP_LOCALES } from 'twenty-shared/translations';
|
import { APP_LOCALES } from 'twenty-shared/translations';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { iconsState } from 'twenty-ui/display';
|
import { iconsState } from 'twenty-ui/display';
|
||||||
@ -85,8 +85,6 @@ export const useAuth = () => {
|
|||||||
isEmailVerificationRequiredState,
|
isEmailVerificationRequiredState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems();
|
|
||||||
|
|
||||||
const setSignInUpStep = useSetRecoilState(signInUpStepState);
|
const setSignInUpStep = useSetRecoilState(signInUpStepState);
|
||||||
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
const setCurrentWorkspace = useSetRecoilState(currentWorkspaceState);
|
||||||
const setWorkspaces = useSetRecoilState(workspacesState);
|
const setWorkspaces = useSetRecoilState(workspacesState);
|
||||||
@ -119,10 +117,13 @@ export const useAuth = () => {
|
|||||||
|
|
||||||
const [, setSearchParams] = useSearchParams();
|
const [, setSearchParams] = useSearchParams();
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const clearSession = useRecoilCallback(
|
const clearSession = useRecoilCallback(
|
||||||
({ snapshot }) =>
|
({ snapshot }) =>
|
||||||
async () => {
|
async () => {
|
||||||
const emptySnapshot = snapshot_UNSTABLE();
|
const emptySnapshot = snapshot_UNSTABLE();
|
||||||
|
|
||||||
const iconsValue = snapshot.getLoadable(iconsState).getValue();
|
const iconsValue = snapshot.getLoadable(iconsState).getValue();
|
||||||
const authProvidersValue = snapshot
|
const authProvidersValue = snapshot
|
||||||
.getLoadable(workspaceAuthProvidersState)
|
.getLoadable(workspaceAuthProvidersState)
|
||||||
@ -132,7 +133,6 @@ export const useAuth = () => {
|
|||||||
.getLoadable(isDeveloperDefaultSignInPrefilledState)
|
.getLoadable(isDeveloperDefaultSignInPrefilledState)
|
||||||
.getValue();
|
.getValue();
|
||||||
const supportChat = snapshot.getLoadable(supportChatState).getValue();
|
const supportChat = snapshot.getLoadable(supportChatState).getValue();
|
||||||
const isDebugMode = snapshot.getLoadable(isDebugModeState).getValue();
|
|
||||||
const captcha = snapshot.getLoadable(captchaState).getValue();
|
const captcha = snapshot.getLoadable(captchaState).getValue();
|
||||||
const clientConfigApiStatus = snapshot
|
const clientConfigApiStatus = snapshot
|
||||||
.getLoadable(clientConfigApiStatusState)
|
.getLoadable(clientConfigApiStatusState)
|
||||||
@ -146,6 +146,12 @@ export const useAuth = () => {
|
|||||||
const domainConfiguration = snapshot
|
const domainConfiguration = snapshot
|
||||||
.getLoadable(domainConfigurationState)
|
.getLoadable(domainConfigurationState)
|
||||||
.getValue();
|
.getValue();
|
||||||
|
const apiConfig = snapshot.getLoadable(apiConfigState).getValue();
|
||||||
|
const sentryConfig = snapshot.getLoadable(sentryConfigState).getValue();
|
||||||
|
const workspacePublicData = snapshot
|
||||||
|
.getLoadable(workspacePublicDataState)
|
||||||
|
.getValue();
|
||||||
|
|
||||||
const initialSnapshot = emptySnapshot.map(({ set }) => {
|
const initialSnapshot = emptySnapshot.map(({ set }) => {
|
||||||
set(iconsState, iconsValue);
|
set(iconsState, iconsValue);
|
||||||
set(workspaceAuthProvidersState, authProvidersValue);
|
set(workspaceAuthProvidersState, authProvidersValue);
|
||||||
@ -155,22 +161,27 @@ export const useAuth = () => {
|
|||||||
isDeveloperDefaultSignInPrefilled,
|
isDeveloperDefaultSignInPrefilled,
|
||||||
);
|
);
|
||||||
set(supportChatState, supportChat);
|
set(supportChatState, supportChat);
|
||||||
set(isDebugModeState, isDebugMode);
|
|
||||||
set(captchaState, captcha);
|
set(captchaState, captcha);
|
||||||
|
set(apiConfigState, apiConfig);
|
||||||
|
set(sentryConfigState, sentryConfig);
|
||||||
|
set(workspacePublicDataState, workspacePublicData);
|
||||||
set(clientConfigApiStatusState, clientConfigApiStatus);
|
set(clientConfigApiStatusState, clientConfigApiStatus);
|
||||||
set(isCurrentUserLoadedState, isCurrentUserLoaded);
|
set(isCurrentUserLoadedState, isCurrentUserLoaded);
|
||||||
set(isMultiWorkspaceEnabledState, isMultiWorkspaceEnabled);
|
set(isMultiWorkspaceEnabledState, isMultiWorkspaceEnabled);
|
||||||
set(domainConfigurationState, domainConfiguration);
|
set(domainConfigurationState, domainConfiguration);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
goToRecoilSnapshot(initialSnapshot);
|
goToRecoilSnapshot(initialSnapshot);
|
||||||
await client.clearStore();
|
|
||||||
sessionStorage.clear();
|
sessionStorage.clear();
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
|
await client.clearStore();
|
||||||
// We need to explicitly clear the state to trigger the cookie deletion which include the parent domain
|
// We need to explicitly clear the state to trigger the cookie deletion which include the parent domain
|
||||||
setLastAuthenticateWorkspaceDomain(null);
|
setLastAuthenticateWorkspaceDomain(null);
|
||||||
|
navigate(AppPath.SignInUp);
|
||||||
},
|
},
|
||||||
[client, goToRecoilSnapshot, setLastAuthenticateWorkspaceDomain],
|
[navigate, client, goToRecoilSnapshot, setLastAuthenticateWorkspaceDomain],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleGetLoginTokenFromCredentials = useCallback(
|
const handleGetLoginTokenFromCredentials = useCallback(
|
||||||
@ -368,16 +379,9 @@ export const useAuth = () => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
await refreshObjectMetadataItems();
|
|
||||||
await loadCurrentUser();
|
await loadCurrentUser();
|
||||||
},
|
},
|
||||||
[
|
[getAuthTokensFromLoginToken, setTokenPair, loadCurrentUser, origin],
|
||||||
getAuthTokensFromLoginToken,
|
|
||||||
setTokenPair,
|
|
||||||
refreshObjectMetadataItems,
|
|
||||||
loadCurrentUser,
|
|
||||||
origin,
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCredentialsSignIn = useCallback(
|
const handleCredentialsSignIn = useCallback(
|
||||||
|
|||||||
@ -1,21 +1,30 @@
|
|||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
|
|
||||||
import { CaptchaProviderScriptLoaderEffect } from '@/captcha/components/CaptchaProviderScriptLoaderEffect';
|
import { CaptchaProviderScriptLoaderEffect } from '@/captcha/components/CaptchaProviderScriptLoaderEffect';
|
||||||
import { isCaptchaRequiredForPath } from '@/captcha/utils/isCaptchaRequiredForPath';
|
import { isCaptchaRequiredForPath } from '@/captcha/utils/isCaptchaRequiredForPath';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
export const CaptchaProvider = ({ children }: React.PropsWithChildren) => {
|
export const CaptchaProvider = React.memo(
|
||||||
const location = useLocation();
|
({ children }: React.PropsWithChildren) => {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
if (!isCaptchaRequiredForPath(location.pathname)) {
|
const isCaptchaRequired = useMemo(
|
||||||
return <>{children}</>;
|
() => isCaptchaRequiredForPath(location.pathname),
|
||||||
}
|
[location.pathname],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div id="captcha-widget" data-size="invisible"></div>
|
{isCaptchaRequired && (
|
||||||
<CaptchaProviderScriptLoaderEffect />
|
<>
|
||||||
{children}
|
<div id="captcha-widget" data-size="invisible"></div>
|
||||||
</>
|
<CaptchaProviderScriptLoaderEffect />
|
||||||
);
|
</>
|
||||||
};
|
)}
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
CaptchaProvider.displayName = 'CaptchaProvider';
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import { clientConfigApiStatusState } from '@/client-config/states/clientConfigA
|
|||||||
import { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
|
import { isAnalyticsEnabledState } from '@/client-config/states/isAnalyticsEnabledState';
|
||||||
import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState';
|
import { isAttachmentPreviewEnabledState } from '@/client-config/states/isAttachmentPreviewEnabledState';
|
||||||
import { isConfigVariablesInDbEnabledState } from '@/client-config/states/isConfigVariablesInDbEnabledState';
|
import { isConfigVariablesInDbEnabledState } from '@/client-config/states/isConfigVariablesInDbEnabledState';
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
|
import { isDeveloperDefaultSignInPrefilledState } from '@/client-config/states/isDeveloperDefaultSignInPrefilledState';
|
||||||
import { isEmailVerificationRequiredState } from '@/client-config/states/isEmailVerificationRequiredState';
|
import { isEmailVerificationRequiredState } from '@/client-config/states/isEmailVerificationRequiredState';
|
||||||
import { isGoogleCalendarEnabledState } from '@/client-config/states/isGoogleCalendarEnabledState';
|
import { isGoogleCalendarEnabledState } from '@/client-config/states/isGoogleCalendarEnabledState';
|
||||||
@ -26,7 +25,6 @@ import { useRecoilState, useSetRecoilState } from 'recoil';
|
|||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
export const ClientConfigProviderEffect = () => {
|
export const ClientConfigProviderEffect = () => {
|
||||||
const setIsDebugMode = useSetRecoilState(isDebugModeState);
|
|
||||||
const setIsAnalyticsEnabled = useSetRecoilState(isAnalyticsEnabledState);
|
const setIsAnalyticsEnabled = useSetRecoilState(isAnalyticsEnabledState);
|
||||||
const setDomainConfiguration = useSetRecoilState(domainConfigurationState);
|
const setDomainConfiguration = useSetRecoilState(domainConfigurationState);
|
||||||
const setAuthProviders = useSetRecoilState(authProvidersState);
|
const setAuthProviders = useSetRecoilState(authProvidersState);
|
||||||
@ -90,10 +88,17 @@ export const ClientConfigProviderEffect = () => {
|
|||||||
const { data, loading, error, fetchClientConfig } = useClientConfig();
|
const { data, loading, error, fetchClientConfig } = useClientConfig();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!clientConfigApiStatus.isLoaded) {
|
if (
|
||||||
|
!clientConfigApiStatus.isLoadedOnce &&
|
||||||
|
!clientConfigApiStatus.isLoading
|
||||||
|
) {
|
||||||
fetchClientConfig();
|
fetchClientConfig();
|
||||||
}
|
}
|
||||||
}, [clientConfigApiStatus.isLoaded, fetchClientConfig]);
|
}, [
|
||||||
|
clientConfigApiStatus.isLoadedOnce,
|
||||||
|
clientConfigApiStatus.isLoading,
|
||||||
|
fetchClientConfig,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
@ -124,7 +129,6 @@ export const ClientConfigProviderEffect = () => {
|
|||||||
magicLink: false,
|
magicLink: false,
|
||||||
sso: data?.clientConfig.authProviders.sso,
|
sso: data?.clientConfig.authProviders.sso,
|
||||||
});
|
});
|
||||||
setIsDebugMode(data?.clientConfig.debugMode);
|
|
||||||
setIsAnalyticsEnabled(data?.clientConfig.analyticsEnabled);
|
setIsAnalyticsEnabled(data?.clientConfig.analyticsEnabled);
|
||||||
setIsDeveloperDefaultSignInPrefilled(data?.clientConfig.signInPrefilled);
|
setIsDeveloperDefaultSignInPrefilled(data?.clientConfig.signInPrefilled);
|
||||||
setIsMultiWorkspaceEnabled(data?.clientConfig.isMultiWorkspaceEnabled);
|
setIsMultiWorkspaceEnabled(data?.clientConfig.isMultiWorkspaceEnabled);
|
||||||
@ -167,24 +171,23 @@ export const ClientConfigProviderEffect = () => {
|
|||||||
);
|
);
|
||||||
setClientConfigApiStatus((currentStatus) => ({
|
setClientConfigApiStatus((currentStatus) => ({
|
||||||
...currentStatus,
|
...currentStatus,
|
||||||
isLoaded: true,
|
isSaved: true,
|
||||||
}));
|
}));
|
||||||
}, [
|
}, [
|
||||||
data,
|
data,
|
||||||
setIsDebugMode,
|
loading,
|
||||||
|
error,
|
||||||
setIsDeveloperDefaultSignInPrefilled,
|
setIsDeveloperDefaultSignInPrefilled,
|
||||||
setIsMultiWorkspaceEnabled,
|
setIsMultiWorkspaceEnabled,
|
||||||
setIsEmailVerificationRequired,
|
setIsEmailVerificationRequired,
|
||||||
setSupportChat,
|
setSupportChat,
|
||||||
setBilling,
|
setBilling,
|
||||||
setSentryConfig,
|
setSentryConfig,
|
||||||
loading,
|
|
||||||
setClientConfigApiStatus,
|
setClientConfigApiStatus,
|
||||||
setCaptcha,
|
setCaptcha,
|
||||||
setChromeExtensionId,
|
setChromeExtensionId,
|
||||||
setApiConfig,
|
setApiConfig,
|
||||||
setIsAnalyticsEnabled,
|
setIsAnalyticsEnabled,
|
||||||
error,
|
|
||||||
setDomainConfiguration,
|
setDomainConfiguration,
|
||||||
setAuthProviders,
|
setAuthProviders,
|
||||||
setCanManageFeatureFlags,
|
setCanManageFeatureFlags,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useRecoilCallback, useRecoilValue } from 'recoil';
|
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||||
import { ClientConfig } from '~/generated/graphql';
|
import { ClientConfig } from '~/generated/graphql';
|
||||||
import { clientConfigApiStatusState } from '../states/clientConfigApiStatusState';
|
import { clientConfigApiStatusState } from '../states/clientConfigApiStatusState';
|
||||||
import { getClientConfig } from '../utils/getClientConfig';
|
import { getClientConfig } from '../utils/getClientConfig';
|
||||||
@ -13,41 +13,38 @@ type UseClientConfigResult = {
|
|||||||
|
|
||||||
export const useClientConfig = (): UseClientConfigResult => {
|
export const useClientConfig = (): UseClientConfigResult => {
|
||||||
const clientConfigApiStatus = useRecoilValue(clientConfigApiStatusState);
|
const clientConfigApiStatus = useRecoilValue(clientConfigApiStatusState);
|
||||||
|
const setClientConfigApiStatus = useSetRecoilState(
|
||||||
const fetchClientConfig = useRecoilCallback(
|
clientConfigApiStatusState,
|
||||||
({ set }) =>
|
|
||||||
async () => {
|
|
||||||
set(clientConfigApiStatusState, (prev) => ({
|
|
||||||
...prev,
|
|
||||||
isLoading: true,
|
|
||||||
isErrored: false,
|
|
||||||
error: undefined,
|
|
||||||
}));
|
|
||||||
|
|
||||||
try {
|
|
||||||
const clientConfig = await getClientConfig();
|
|
||||||
set(clientConfigApiStatusState, (prev) => ({
|
|
||||||
...prev,
|
|
||||||
isLoading: false,
|
|
||||||
isLoaded: true,
|
|
||||||
data: { clientConfig },
|
|
||||||
}));
|
|
||||||
} catch (err) {
|
|
||||||
const error =
|
|
||||||
err instanceof Error
|
|
||||||
? err
|
|
||||||
: new Error('Failed to fetch client config');
|
|
||||||
set(clientConfigApiStatusState, (prev) => ({
|
|
||||||
...prev,
|
|
||||||
isLoading: false,
|
|
||||||
isErrored: true,
|
|
||||||
error,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const fetchClientConfig = async () => {
|
||||||
|
setClientConfigApiStatus((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isLoading: true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const clientConfig = await getClientConfig();
|
||||||
|
setClientConfigApiStatus((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isLoading: false,
|
||||||
|
isLoadedOnce: true,
|
||||||
|
isErrored: false,
|
||||||
|
error: undefined,
|
||||||
|
data: { clientConfig },
|
||||||
|
}));
|
||||||
|
} catch (err) {
|
||||||
|
const error =
|
||||||
|
err instanceof Error ? err : new Error('Failed to fetch client config');
|
||||||
|
setClientConfigApiStatus((prev) => ({
|
||||||
|
...prev,
|
||||||
|
isLoading: false,
|
||||||
|
isErrored: true,
|
||||||
|
error,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: clientConfigApiStatus.data,
|
data: clientConfigApiStatus.data,
|
||||||
loading: clientConfigApiStatus.isLoading || false,
|
loading: clientConfigApiStatus.isLoading || false,
|
||||||
|
|||||||
@ -2,9 +2,10 @@ import { createState } from 'twenty-ui/utilities';
|
|||||||
import { ClientConfig } from '~/generated/graphql';
|
import { ClientConfig } from '~/generated/graphql';
|
||||||
|
|
||||||
type ClientConfigApiStatus = {
|
type ClientConfigApiStatus = {
|
||||||
isLoaded: boolean;
|
isLoadedOnce: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
isErrored: boolean;
|
isErrored: boolean;
|
||||||
|
isSaved: boolean;
|
||||||
error?: Error;
|
error?: Error;
|
||||||
data?: { clientConfig: ClientConfig };
|
data?: { clientConfig: ClientConfig };
|
||||||
};
|
};
|
||||||
@ -12,9 +13,10 @@ type ClientConfigApiStatus = {
|
|||||||
export const clientConfigApiStatusState = createState<ClientConfigApiStatus>({
|
export const clientConfigApiStatusState = createState<ClientConfigApiStatus>({
|
||||||
key: 'clientConfigApiStatus',
|
key: 'clientConfigApiStatus',
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
isLoaded: false,
|
isLoadedOnce: false,
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
isErrored: false,
|
isErrored: false,
|
||||||
|
isSaved: false,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
data: undefined,
|
data: undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
import { createState } from 'twenty-ui/utilities';
|
|
||||||
export const isDebugModeState = createState<boolean>({
|
|
||||||
key: 'isDebugModeState',
|
|
||||||
defaultValue: false,
|
|
||||||
});
|
|
||||||
@ -2,14 +2,12 @@ import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainCo
|
|||||||
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState';
|
||||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||||
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
import { contextStoreCurrentViewTypeComponentState } from '@/context-store/states/contextStoreCurrentViewTypeComponentState';
|
||||||
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
import { getViewType } from '@/context-store/utils/getViewType';
|
||||||
import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId';
|
import { useSetLastVisitedObjectMetadataId } from '@/navigation/hooks/useSetLastVisitedObjectMetadataId';
|
||||||
import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural';
|
import { useSetLastVisitedViewForObjectMetadataNamePlural } from '@/navigation/hooks/useSetLastVisitedViewForObjectMetadataNamePlural';
|
||||||
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
import { ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||||
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
import { prefetchViewFromViewIdFamilySelector } from '@/prefetch/states/selector/prefetchViewFromViewIdFamilySelector';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { View } from '@/views/types/View';
|
|
||||||
import { ViewType } from '@/views/types/ViewType';
|
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
@ -124,31 +122,3 @@ export const MainContextStoreProviderEffect = ({
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getViewType = ({
|
|
||||||
isSettingsPage,
|
|
||||||
isRecordShowPage,
|
|
||||||
isRecordIndexPage,
|
|
||||||
view,
|
|
||||||
}: {
|
|
||||||
isSettingsPage: boolean;
|
|
||||||
isRecordShowPage: boolean;
|
|
||||||
isRecordIndexPage: boolean;
|
|
||||||
view?: View;
|
|
||||||
}) => {
|
|
||||||
if (isSettingsPage) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRecordIndexPage) {
|
|
||||||
return view?.type === ViewType.Kanban
|
|
||||||
? ContextStoreViewType.Kanban
|
|
||||||
: ContextStoreViewType.Table;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isRecordShowPage) {
|
|
||||||
return ContextStoreViewType.ShowPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
import { ContextStoreViewType } from '@/context-store/types/ContextStoreViewType';
|
||||||
|
import { View } from '@/views/types/View';
|
||||||
|
import { ViewType } from '@/views/types/ViewType';
|
||||||
|
|
||||||
|
export const getViewType = ({
|
||||||
|
isSettingsPage,
|
||||||
|
isRecordShowPage,
|
||||||
|
isRecordIndexPage,
|
||||||
|
view,
|
||||||
|
}: {
|
||||||
|
isSettingsPage: boolean;
|
||||||
|
isRecordShowPage: boolean;
|
||||||
|
isRecordIndexPage: boolean;
|
||||||
|
view?: View;
|
||||||
|
}) => {
|
||||||
|
if (isSettingsPage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRecordIndexPage) {
|
||||||
|
return view?.type === ViewType.Kanban
|
||||||
|
? ContextStoreViewType.Kanban
|
||||||
|
: ContextStoreViewType.Table;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRecordShowPage) {
|
||||||
|
return ContextStoreViewType.ShowPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
@ -1,11 +1,8 @@
|
|||||||
import { loadDevMessages, loadErrorMessages } from '@apollo/client/dev';
|
import { loadDevMessages, loadErrorMessages } from '@apollo/client/dev';
|
||||||
import { useEffect } from 'react';
|
import { useEffect } from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
|
|
||||||
export const ApolloDevLogEffect = () => {
|
export const ApolloDevLogEffect = () => {
|
||||||
const isDebugMode = useRecoilValue(isDebugModeState);
|
const isDebugMode = process.env.IS_DEBUG_MODE === 'true';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isDebugMode) {
|
if (isDebugMode) {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
import { useRecoilTransactionObserver_UNSTABLE } from 'recoil';
|
||||||
import { useRecoilTransactionObserver_UNSTABLE, useRecoilValue } from 'recoil';
|
|
||||||
|
|
||||||
import { logDebug } from '~/utils/logDebug';
|
import { logDebug } from '~/utils/logDebug';
|
||||||
|
|
||||||
@ -15,7 +14,7 @@ const formatTitle = (stateName: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RecoilDebugObserverEffect = () => {
|
export const RecoilDebugObserverEffect = () => {
|
||||||
const isDebugMode = useRecoilValue(isDebugModeState);
|
const isDebugMode = process.env.IS_DEBUG_MODE === 'true';
|
||||||
|
|
||||||
useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
|
useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
|
||||||
if (!isDebugMode) {
|
if (!isDebugMode) {
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const useGetPublicWorkspaceDataByDomain = () => {
|
|||||||
origin,
|
origin,
|
||||||
},
|
},
|
||||||
skip:
|
skip:
|
||||||
!clientConfigApiStatus.isLoaded ||
|
!clientConfigApiStatus.isSaved ||
|
||||||
(isMultiWorkspaceEnabled && isDefaultDomain) ||
|
(isMultiWorkspaceEnabled && isDefaultDomain) ||
|
||||||
isDefined(workspacePublicData),
|
isDefined(workspacePublicData),
|
||||||
onCompleted: (data) => {
|
onCompleted: (data) => {
|
||||||
@ -38,9 +38,17 @@ export const useGetPublicWorkspaceDataByDomain = () => {
|
|||||||
setWorkspacePublicDataState(data.getPublicWorkspaceDataByDomain);
|
setWorkspacePublicDataState(data.getPublicWorkspaceDataByDomain);
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
// eslint-disable-next-line no-console
|
// Only redirect to default domain if it's a workspace not found error
|
||||||
console.error(error);
|
const isWorkspaceNotFoundError = error.graphQLErrors?.some(
|
||||||
redirectToDefaultDomain();
|
(graphQLError) => graphQLError.extensions?.code === 'NOT_FOUND',
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isWorkspaceNotFoundError) {
|
||||||
|
redirectToDefaultDomain();
|
||||||
|
} else {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import { currentUserState } from '@/auth/states/currentUserState';
|
|||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { useLoadMockedObjectMetadataItems } from '@/object-metadata/hooks/useLoadMockedObjectMetadataItems';
|
import { useLoadMockedObjectMetadataItems } from '@/object-metadata/hooks/useLoadMockedObjectMetadataItems';
|
||||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItem';
|
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItem';
|
||||||
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
|
||||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||||
|
import { isUndefinedOrNull } from '~/utils/isUndefinedOrNull';
|
||||||
|
|
||||||
export const ObjectMetadataItemsLoadEffect = () => {
|
export const ObjectMetadataItemsLoadEffect = () => {
|
||||||
const currentUser = useRecoilValue(currentUserState);
|
const currentUser = useRecoilValue(currentUserState);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
|
|
||||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||||
import { dateTimeFormatState } from '@/localization/states/dateTimeFormatState';
|
import { dateTimeFormatState } from '@/localization/states/dateTimeFormatState';
|
||||||
import { AppPath } from '@/types/AppPath';
|
import { AppPath } from '@/types/AppPath';
|
||||||
import { UserContext } from '@/users/contexts/UserContext';
|
import { UserContext } from '@/users/contexts/UserContext';
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
import { useRecoilCallback, useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
|
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||||
import { currentUserState } from '@/auth/states/currentUserState';
|
import { currentUserState } from '@/auth/states/currentUserState';
|
||||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||||
import { currentWorkspaceDeletedMembersState } from '@/auth/states/currentWorkspaceDeletedMembersStates';
|
import { currentWorkspaceDeletedMembersState } from '@/auth/states/currentWorkspaceDeletedMembersStates';
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersStates';
|
||||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadingState';
|
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||||
import { workspacesState } from '@/auth/states/workspaces';
|
import { workspacesState } from '@/auth/states/workspaces';
|
||||||
import { DateFormat } from '@/localization/constants/DateFormat';
|
import { DateFormat } from '@/localization/constants/DateFormat';
|
||||||
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
import { TimeFormat } from '@/localization/constants/TimeFormat';
|
||||||
@ -21,6 +21,7 @@ import { AppPath } from '@/types/AppPath';
|
|||||||
import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util';
|
import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util';
|
||||||
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
import { ColorScheme } from '@/workspace-member/types/WorkspaceMember';
|
||||||
import { enUS } from 'date-fns/locale';
|
import { enUS } from 'date-fns/locale';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -31,7 +32,6 @@ import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
|||||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||||
|
|
||||||
export const UserProviderEffect = () => {
|
export const UserProviderEffect = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
const [isCurrentUserLoaded, setIsCurrentUserLoaded] = useRecoilState(
|
const [isCurrentUserLoaded, setIsCurrentUserLoaded] = useRecoilState(
|
||||||
@ -42,6 +42,8 @@ export const UserProviderEffect = () => {
|
|||||||
const setCurrentUserWorkspace = useSetRecoilState(currentUserWorkspaceState);
|
const setCurrentUserWorkspace = useSetRecoilState(currentUserWorkspaceState);
|
||||||
const setWorkspaces = useSetRecoilState(workspacesState);
|
const setWorkspaces = useSetRecoilState(workspacesState);
|
||||||
const setDateTimeFormat = useSetRecoilState(dateTimeFormatState);
|
const setDateTimeFormat = useSetRecoilState(dateTimeFormatState);
|
||||||
|
const isLoggedIn = useIsLogged();
|
||||||
|
|
||||||
const updateLocaleCatalog = useRecoilCallback(
|
const updateLocaleCatalog = useRecoilCallback(
|
||||||
({ snapshot, set }) =>
|
({ snapshot, set }) =>
|
||||||
async (newLocale: keyof typeof APP_LOCALES) => {
|
async (newLocale: keyof typeof APP_LOCALES) => {
|
||||||
@ -68,8 +70,9 @@ export const UserProviderEffect = () => {
|
|||||||
currentWorkspaceDeletedMembersState,
|
currentWorkspaceDeletedMembersState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { loading: queryLoading, data: queryData } = useGetCurrentUserQuery({
|
const { data: queryData, loading: queryLoading } = useGetCurrentUserQuery({
|
||||||
skip:
|
skip:
|
||||||
|
!isLoggedIn ||
|
||||||
isCurrentUserLoaded ||
|
isCurrentUserLoaded ||
|
||||||
isMatchingLocation(location, AppPath.Verify) ||
|
isMatchingLocation(location, AppPath.Verify) ||
|
||||||
isMatchingLocation(location, AppPath.VerifyEmail),
|
isMatchingLocation(location, AppPath.VerifyEmail),
|
||||||
@ -77,7 +80,6 @@ export const UserProviderEffect = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!queryLoading) {
|
if (!queryLoading) {
|
||||||
setIsLoading(false);
|
|
||||||
setIsCurrentUserLoaded(true);
|
setIsCurrentUserLoaded(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,15 +161,14 @@ export const UserProviderEffect = () => {
|
|||||||
setWorkspaces(workspaces);
|
setWorkspaces(workspaces);
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
|
queryLoading,
|
||||||
|
queryData?.currentUser,
|
||||||
setCurrentUser,
|
setCurrentUser,
|
||||||
setCurrentUserWorkspace,
|
setCurrentUserWorkspace,
|
||||||
setCurrentWorkspaceMembers,
|
setCurrentWorkspaceMembers,
|
||||||
isLoading,
|
|
||||||
queryLoading,
|
|
||||||
setCurrentWorkspace,
|
setCurrentWorkspace,
|
||||||
setCurrentWorkspaceMember,
|
setCurrentWorkspaceMember,
|
||||||
setWorkspaces,
|
setWorkspaces,
|
||||||
queryData?.currentUser,
|
|
||||||
setIsCurrentUserLoaded,
|
setIsCurrentUserLoaded,
|
||||||
setDateTimeFormat,
|
setDateTimeFormat,
|
||||||
setCurrentWorkspaceMembersWithDeleted,
|
setCurrentWorkspaceMembersWithDeleted,
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
import { useRecoilState, useSetRecoilState } from 'recoil';
|
||||||
|
|
||||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||||
import { isDebugModeState } from '@/client-config/states/isDebugModeState';
|
|
||||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||||
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
import { useUpdateOneRecord } from '@/object-record/hooks/useUpdateOneRecord';
|
||||||
import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util';
|
import { getDateFnsLocale } from '@/ui/field/display/utils/getDateFnsLocale.util';
|
||||||
@ -29,7 +28,6 @@ export const LocalePicker = () => {
|
|||||||
currentWorkspaceMemberState,
|
currentWorkspaceMemberState,
|
||||||
);
|
);
|
||||||
const setDateLocale = useSetRecoilState(dateLocaleState);
|
const setDateLocale = useSetRecoilState(dateLocaleState);
|
||||||
const isDebugMode = useRecoilValue(isDebugModeState);
|
|
||||||
|
|
||||||
const { updateOneRecord } = useUpdateOneRecord({
|
const { updateOneRecord } = useUpdateOneRecord({
|
||||||
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
objectNameSingular: CoreObjectNameSingular.WorkspaceMember,
|
||||||
@ -204,7 +202,7 @@ export const LocalePicker = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (isDebugMode) {
|
if (process.env.NODE_ENV === 'development') {
|
||||||
unsortedLocaleOptions.push({
|
unsortedLocaleOptions.push({
|
||||||
label: t`Pseudo-English`,
|
label: t`Pseudo-English`,
|
||||||
value: APP_LOCALES['pseudo-en'],
|
value: APP_LOCALES['pseudo-en'],
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
SSL_CERT_PATH,
|
SSL_CERT_PATH,
|
||||||
SSL_KEY_PATH,
|
SSL_KEY_PATH,
|
||||||
REACT_APP_PORT,
|
REACT_APP_PORT,
|
||||||
|
IS_DEBUG_MODE,
|
||||||
} = env;
|
} = env;
|
||||||
|
|
||||||
const port = isNonEmptyString(REACT_APP_PORT)
|
const port = isNonEmptyString(REACT_APP_PORT)
|
||||||
@ -191,6 +192,7 @@ export default defineConfig(({ command, mode }) => {
|
|||||||
},
|
},
|
||||||
'process.env': {
|
'process.env': {
|
||||||
REACT_APP_SERVER_BASE_URL,
|
REACT_APP_SERVER_BASE_URL,
|
||||||
|
IS_DEBUG_MODE,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
css: {
|
css: {
|
||||||
|
|||||||
Reference in New Issue
Block a user