refactor: metadata store cleanup, SSE unification, mock metadata loading & login redirect fix (#18651)
## Summary - **SSE unification**: Replaced 11 individual SSE effect components with a single generic `MetadataStoreSSEEffect` - **Metadata store cleanup**: Merged `metadataCollectionHashesState` into `metadataStoreState` (currentCollectionHash / draftCollectionHash per entity), moved `objectMetadataItemsSelector` to `object-metadata` domain, converted `navigationMenuItemsState` to a derived selector - **Naming clarity**: Renamed `isAppMetadataReadyState` → `isMinimalMetadataReadyState`, `MetadataGater` → `MinimalMetadataGater`, `useIsLogged` → `useHasAccessTokenPair`, `patchMetadataStoreFromSSEEvent` now takes named object params - **Mock metadata loading**: Added `generate-navigation-menu-items.ts` script, rewrote `useLoadMockedMinimalMetadata` to load full objects/fields/indexes/views/navItems from generated mock data, enabling proper sign-in background rendering (table columns, view picker, navigation) - **Login/logout transitions**: `MinimalMetadataLoadEffect` manages mocked↔real metadata transitions based on auth state, `MainContextStoreProvider` computes context on auth pages for view picker support - **Login redirect fix**: `handleLoadWorkspaceAfterAuthentication` now re-enables `isAppEffectRedirectEnabled` after `loadCurrentUser()` completes, fixing the blocked post-login navigation - **Dead code removal**: Deleted `useRefreshPageLayouts`, `useApplyPageLayouts`, `useStaleMetadataEntities`, `metadataCollectionHashesState`, and all individual SSE effects ## Test plan - [x] Login from welcome page redirects to companies page - [x] Logout transitions cleanly to mocked metadata on welcome page - [x] Sign-in background shows table columns, view picker, and navigation items - [x] SSE events still update metadata store entries correctly - [x] Navigation menu items persist across page refreshes - [ ] CI: lint, typecheck, tests pass
This commit is contained in:
@@ -1,19 +1,23 @@
|
||||
/* oxlint-disable no-console */
|
||||
import { generateApiKeys } from './mock-data/generate-api-keys.js';
|
||||
import { generateBillingPlans } from './mock-data/generate-billing-plans.js';
|
||||
import { generateMetadata } from './mock-data/generate-metadata.js';
|
||||
import { generateObjectMetadata } from './mock-data/generate-object-metadata.js';
|
||||
import { generateMinimalMetadata } from './mock-data/generate-minimal-metadata.js';
|
||||
import { generateRecordData } from './mock-data/generate-record-data.js';
|
||||
import { generateRoles } from './mock-data/generate-roles.js';
|
||||
import { generateNavigationMenuItems } from './mock-data/generate-navigation-menu-items.js';
|
||||
import { generateViews } from './mock-data/generate-views.js';
|
||||
import { authenticate } from './mock-data/utils.js';
|
||||
|
||||
const main = async () => {
|
||||
const token = await authenticate();
|
||||
|
||||
const metadata = await generateMetadata(token);
|
||||
const metadata = await generateObjectMetadata(token);
|
||||
await generateMinimalMetadata(token);
|
||||
await generateRecordData(token, metadata);
|
||||
await generateRoles(token);
|
||||
await generateViews(token);
|
||||
await generateNavigationMenuItems(token);
|
||||
|
||||
try {
|
||||
await generateBillingPlans(token);
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/* oxlint-disable no-console */
|
||||
import { graphqlRequest, writeGeneratedFile } from './utils.js';
|
||||
|
||||
const MINIMAL_METADATA_QUERY = `
|
||||
query FindMinimalMetadata {
|
||||
minimalMetadata {
|
||||
objectMetadataItems {
|
||||
id
|
||||
nameSingular
|
||||
namePlural
|
||||
labelSingular
|
||||
labelPlural
|
||||
icon
|
||||
isCustom
|
||||
isActive
|
||||
isSystem
|
||||
isRemote
|
||||
}
|
||||
views {
|
||||
id
|
||||
type
|
||||
key
|
||||
objectMetadataId
|
||||
}
|
||||
collectionHashes {
|
||||
collectionName
|
||||
hash
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const generateMinimalMetadata = async (token: string) => {
|
||||
console.log('Fetching minimal metadata from /metadata ...');
|
||||
|
||||
const data = (await graphqlRequest(
|
||||
'/metadata',
|
||||
MINIMAL_METADATA_QUERY,
|
||||
token,
|
||||
)) as {
|
||||
minimalMetadata: Record<string, unknown>;
|
||||
};
|
||||
|
||||
writeGeneratedFile(
|
||||
'metadata/minimal/mock-minimal-metadata.ts',
|
||||
'mockedMinimalMetadata',
|
||||
'MinimalMetadata',
|
||||
"import { type MinimalMetadata } from '@/metadata-store/types/MinimalMetadata';",
|
||||
data.minimalMetadata,
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
/* oxlint-disable no-console, lingui/no-unlocalized-strings */
|
||||
import { graphqlRequest, writeGeneratedFile } from './utils.js';
|
||||
|
||||
const FIND_MANY_NAVIGATION_MENU_ITEMS_QUERY = `
|
||||
query FindManyNavigationMenuItems {
|
||||
navigationMenuItems {
|
||||
id
|
||||
userWorkspaceId
|
||||
targetRecordId
|
||||
targetObjectMetadataId
|
||||
viewId
|
||||
folderId
|
||||
name
|
||||
link
|
||||
icon
|
||||
color
|
||||
position
|
||||
applicationId
|
||||
createdAt
|
||||
updatedAt
|
||||
targetRecordIdentifier {
|
||||
id
|
||||
labelIdentifier
|
||||
imageIdentifier
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const generateNavigationMenuItems = async (token: string) => {
|
||||
console.log('Fetching navigation menu items from /metadata ...');
|
||||
|
||||
const data = (await graphqlRequest(
|
||||
'/metadata',
|
||||
FIND_MANY_NAVIGATION_MENU_ITEMS_QUERY,
|
||||
token,
|
||||
)) as {
|
||||
navigationMenuItems: Record<string, unknown>[];
|
||||
};
|
||||
|
||||
console.log(` Got ${data.navigationMenuItems.length} navigation menu items.`);
|
||||
|
||||
writeGeneratedFile(
|
||||
'metadata/navigation-menu-items/mock-navigation-menu-items-data.ts',
|
||||
'mockedNavigationMenuItems',
|
||||
'NavigationMenuItem[]',
|
||||
"import { type NavigationMenuItem } from '~/generated-metadata/graphql';",
|
||||
data.navigationMenuItems,
|
||||
);
|
||||
};
|
||||
+1
-1
@@ -141,7 +141,7 @@ const METADATA_QUERY = `
|
||||
}
|
||||
`;
|
||||
|
||||
export const generateMetadata = async (token: string) => {
|
||||
export const generateObjectMetadata = async (token: string) => {
|
||||
console.log('Fetching object metadata from /metadata ...');
|
||||
|
||||
const metadata = await graphqlRequest('/metadata', METADATA_QUERY, token);
|
||||
@@ -831,6 +831,12 @@ export type ClientConfig = {
|
||||
support: Support;
|
||||
};
|
||||
|
||||
export type CollectionHash = {
|
||||
__typename?: 'CollectionHash';
|
||||
collectionName: AllMetadataName;
|
||||
hash: Scalars['String'];
|
||||
};
|
||||
|
||||
export type CommandMenuItem = {
|
||||
__typename?: 'CommandMenuItem';
|
||||
applicationId?: Maybe<Scalars['UUID']>;
|
||||
@@ -2422,7 +2428,7 @@ export type MetadataEventWithQueryIds = {
|
||||
|
||||
export type MinimalMetadata = {
|
||||
__typename?: 'MinimalMetadata';
|
||||
collectionHashes: Scalars['JSON'];
|
||||
collectionHashes: Array<CollectionHash>;
|
||||
objectMetadataItems: Array<MinimalObjectMetadata>;
|
||||
views: Array<MinimalView>;
|
||||
};
|
||||
|
||||
+223
-223
@@ -1,4 +1,4 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||
import { useOnboardingStatus } from '@/onboarding/hooks/useOnboardingStatus';
|
||||
import { useIsWorkspaceActivationStatusEqualsTo } from '@/workspace/hooks/useIsWorkspaceActivationStatusEqualsTo';
|
||||
@@ -39,9 +39,9 @@ const setupMockIsMatchingLocation = (pathname: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
jest.mock('@/auth/hooks/useIsLogged');
|
||||
const setupMockIsLogged = (isLogged: boolean) => {
|
||||
jest.mocked(useIsLogged).mockReturnValueOnce(isLogged);
|
||||
jest.mock('@/auth/hooks/useHasAccessTokenPair');
|
||||
const setupMockHasAccessTokenPair = (hasAccessTokenPair: boolean) => {
|
||||
jest.mocked(useHasAccessTokenPair).mockReturnValueOnce(hasAccessTokenPair);
|
||||
};
|
||||
|
||||
const defaultHomePagePath = '/objects/companies';
|
||||
@@ -83,7 +83,7 @@ const setupMockState = (
|
||||
// prettier-ignore
|
||||
const testCases: {
|
||||
loc: AppPath;
|
||||
isLoggedIn: boolean;
|
||||
hasAccessTokenPair: boolean;
|
||||
isWorkspaceSuspended: boolean;
|
||||
onboardingStatus: OnboardingStatus | undefined;
|
||||
res: string | undefined;
|
||||
@@ -93,248 +93,248 @@ const testCases: {
|
||||
verifyEmailRedirectPath?: string;
|
||||
returnToPath?: string;
|
||||
}[] = [
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Verify, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Invite, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Invite, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Invite, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.ResetPassword, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: '/plan-required' },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: '/create/workspace' },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: '/create/profile' },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: '/sync/emails' },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: '/invite-team' },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.ResetPassword, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, verifyEmailRedirectPath: '/nextPath?key=value', res: '/nextPath?key=value' },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, verifyEmailRedirectPath: '/nextPath?key=value', res: undefined },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.VerifyEmail, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, verifyEmailRedirectPath: '/nextPath?key=value', res: '/nextPath?key=value' },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, verifyEmailRedirectPath: '/nextPath?key=value', res: undefined },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: undefined },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.VerifyEmail, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.CreateWorkspace, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.CreateWorkspace, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: undefined },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.CreateProfile, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: undefined },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.CreateProfile, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: undefined },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SyncEmails, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: undefined },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SyncEmails, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: undefined },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.InviteTeam, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: undefined },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.InviteTeam, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined },
|
||||
{ loc: AppPath.BookCallDecision, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined },
|
||||
{ loc: AppPath.BookCall, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: undefined },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: undefined },
|
||||
{ loc: AppPath.BookCall, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.PlanRequired, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.PlanRequired, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.PlanRequiredSuccess, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: undefined },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.PlanRequiredSuccess, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Index, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: defaultHomePagePath },
|
||||
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.TasksPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.TasksPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.OpportunitiesPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.OpportunitiesPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined, objectNamePluralFromParams: 'existing-object', objectNamePluralFromMetadata: 'existing-object' },
|
||||
{ loc: AppPath.RecordIndexPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: AppPath.NotFound, objectNamePluralFromParams: 'non-existing-object', objectNamePluralFromMetadata: 'existing-object' },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined, objectNamePluralFromParams: 'existing-object', objectNamePluralFromMetadata: 'existing-object' },
|
||||
{ loc: AppPath.RecordIndexPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: AppPath.NotFound, objectNamePluralFromParams: 'non-existing-object', objectNamePluralFromMetadata: 'existing-object' },
|
||||
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.RecordShowPage, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.RecordShowPage, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SettingsCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.SettingsCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.DevelopersCatchAll, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.DevelopersCatchAll, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Authorize, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.Authorize, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.NotFoundWildcard, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.NotFoundWildcard, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.NotFound, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PLAN_REQUIRED, res: AppPath.PlanRequired },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: true, onboardingStatus: OnboardingStatus.COMPLETED, res: getSettingsPath(SettingsPath.Billing) },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: false, isWorkspaceSuspended: false, onboardingStatus: undefined, res: AppPath.SignInUp },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.WORKSPACE_ACTIVATION, res: AppPath.CreateWorkspace },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.PROFILE_CREATION, res: AppPath.CreateProfile },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.SYNC_EMAIL, res: AppPath.SyncEmails },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.INVITE_TEAM, res: AppPath.InviteTeam },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.BOOK_ONBOARDING, res: AppPath.BookCallDecision },
|
||||
{ loc: AppPath.NotFound, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, res: undefined },
|
||||
|
||||
// returnToPath: should redirect to saved path instead of defaultHomePagePath
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/authorize?clientId=abc', res: '/authorize?clientId=abc' },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/objects/tasks', res: '/objects/tasks' },
|
||||
{ loc: AppPath.Index, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/settings/api-keys', res: '/settings/api-keys' },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/authorize?clientId=abc', res: '/authorize?clientId=abc' },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/objects/tasks', res: '/objects/tasks' },
|
||||
{ loc: AppPath.Index, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, returnToPath: '/settings/api-keys', res: '/settings/api-keys' },
|
||||
|
||||
// isOnAWorkspace:false — on default domain, don't redirect to returnToPath or defaultHomePagePath from auth pages
|
||||
{ loc: AppPath.Verify, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, isOnAWorkspace: false, res: undefined },
|
||||
{ loc: AppPath.SignInUp, isLoggedIn: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, isOnAWorkspace: false, res: undefined },
|
||||
{ loc: AppPath.Verify, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, isOnAWorkspace: false, res: undefined },
|
||||
{ loc: AppPath.SignInUp, hasAccessTokenPair: true, isWorkspaceSuspended: false, onboardingStatus: OnboardingStatus.COMPLETED, isOnAWorkspace: false, res: undefined },
|
||||
];
|
||||
|
||||
describe('usePageChangeEffectNavigateLocation', () => {
|
||||
@@ -344,7 +344,7 @@ describe('usePageChangeEffectNavigateLocation', () => {
|
||||
loc,
|
||||
onboardingStatus,
|
||||
isWorkspaceSuspended,
|
||||
isLoggedIn,
|
||||
hasAccessTokenPair,
|
||||
isOnAWorkspace,
|
||||
objectNamePluralFromParams,
|
||||
objectNamePluralFromMetadata,
|
||||
@@ -355,7 +355,7 @@ describe('usePageChangeEffectNavigateLocation', () => {
|
||||
setupMockIsMatchingLocation(loc);
|
||||
setupMockOnboardingStatus(onboardingStatus);
|
||||
setupMockIsWorkspaceActivationStatusEqualsTo(isWorkspaceSuspended);
|
||||
setupMockIsLogged(isLoggedIn);
|
||||
setupMockHasAccessTokenPair(hasAccessTokenPair);
|
||||
setupMockIsOnAWorkspace(isOnAWorkspace ?? true);
|
||||
setupMockUseParams(objectNamePluralFromParams);
|
||||
setupMockState(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { verifyEmailRedirectPathState } from '@/app/states/verifyEmailRedirectPathState';
|
||||
import { ONBOARDING_PATHS } from '@/auth/constants/OnboardingPaths';
|
||||
import { ONGOING_USER_CREATION_PATHS } from '@/auth/constants/OngoingUserCreationPaths';
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { returnToPathState } from '@/auth/states/returnToPathState';
|
||||
import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState';
|
||||
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
|
||||
@@ -26,7 +26,7 @@ const readReturnToPathFromUrlSearchParams = (): string | null => {
|
||||
};
|
||||
|
||||
export const usePageChangeEffectNavigateLocation = () => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const { isOnAWorkspace } = useIsCurrentLocationOnAWorkspace();
|
||||
const onboardingStatus = useOnboardingStatus();
|
||||
const isWorkspaceSuspended = useIsWorkspaceActivationStatusEqualsTo(
|
||||
@@ -54,7 +54,7 @@ export const usePageChangeEffectNavigateLocation = () => {
|
||||
: readReturnToPathFromUrlSearchParams();
|
||||
|
||||
if (
|
||||
(!isLoggedIn || (isLoggedIn && !isOnAWorkspace)) &&
|
||||
(!hasAccessTokenPair || (hasAccessTokenPair && !isOnAWorkspace)) &&
|
||||
!someMatchingLocationOf([
|
||||
...ONGOING_USER_CREATION_PATHS,
|
||||
AppPath.ResetPassword,
|
||||
@@ -140,13 +140,13 @@ export const usePageChangeEffectNavigateLocation = () => {
|
||||
...ONGOING_USER_CREATION_PATHS,
|
||||
]) &&
|
||||
!isMatchingLocation(location, AppPath.ResetPassword) &&
|
||||
isLoggedIn &&
|
||||
hasAccessTokenPair &&
|
||||
isOnAWorkspace
|
||||
) {
|
||||
return resolvedReturnToPath ?? defaultHomePagePath;
|
||||
}
|
||||
|
||||
if (isMatchingLocation(location, AppPath.Index) && isLoggedIn) {
|
||||
if (isMatchingLocation(location, AppPath.Index) && hasAccessTokenPair) {
|
||||
return resolvedReturnToPath ?? defaultHomePagePath;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { AgentChatProvider } from '@/ai/components/AgentChatProvider';
|
||||
import { CommandMenuConfirmationModalManager } from '@/command-menu-item/confirmation-modal/components/CommandMenuConfirmationModalManager';
|
||||
import { ApolloProvider } from '@/apollo/components/ApolloProvider';
|
||||
import { MetadataGater } from '@/metadata-store/components/MetadataGater';
|
||||
import { IsAppMetadataReadyEffect } from '@/metadata-store/effect-components/IsAppMetadataReadyEffect';
|
||||
import { MinimalMetadataGater } from '@/metadata-store/components/MinimalMetadataGater';
|
||||
import { IsMinimalMetadataReadyEffect } from '@/metadata-store/effect-components/IsMinimalMetadataReadyEffect';
|
||||
|
||||
import { GotoHotkeysEffectsProvider } from '@/app/effect-components/GotoHotkeysEffectsProvider';
|
||||
import { MinimalMetadataLoadEffect } from '@/metadata-store/effect-components/MinimalMetadataLoadEffect';
|
||||
import { MetadataProviderInitialEffects } from '@/metadata-store/effect-components/MetadataProviderInitialEffects';
|
||||
import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect';
|
||||
import { PageChangeEffect } from '@/app/effect-components/PageChangeEffect';
|
||||
import { AuthProvider } from '@/auth/components/AuthProvider';
|
||||
import { CaptchaProvider } from '@/captcha/components/CaptchaProvider';
|
||||
@@ -31,7 +31,6 @@ import { BaseThemeProvider } from '@/ui/theme/components/BaseThemeProvider';
|
||||
import { UserThemeProviderEffect } from '@/ui/theme/components/UserThemeProviderEffect';
|
||||
import { PageFavicon } from '@/ui/utilities/page-favicon/components/PageFavicon';
|
||||
import { PageTitle } from '@/ui/utilities/page-title/components/PageTitle';
|
||||
import { LazyMetadataLoadEffect } from '@/users/components/LazyMetadataLoadEffect';
|
||||
import { WorkspaceProviderEffect } from '@/workspace/components/WorkspaceProviderEffect';
|
||||
import { StrictMode } from 'react';
|
||||
import { Outlet, useLocation } from 'react-router-dom';
|
||||
@@ -45,16 +44,15 @@ export const AppRouterProviders = () => {
|
||||
<ApolloProvider>
|
||||
<BaseThemeProvider>
|
||||
<ClientConfigProviderEffect />
|
||||
<UserMetadataProviderInitialEffect />
|
||||
<MinimalMetadataLoadEffect />
|
||||
<MetadataProviderInitialEffects />
|
||||
<LazyMetadataLoadEffect />
|
||||
<IsAppMetadataReadyEffect />
|
||||
<IsMinimalMetadataReadyEffect />
|
||||
<WorkspaceProviderEffect />
|
||||
<ClientConfigProvider>
|
||||
<CaptchaProvider>
|
||||
<ChromeExtensionSidecarEffect />
|
||||
<ChromeExtensionSidecarProvider>
|
||||
<MetadataGater>
|
||||
<MinimalMetadataGater>
|
||||
<AuthProvider>
|
||||
<ApolloCoreProvider>
|
||||
<SSEProvider>
|
||||
@@ -88,7 +86,7 @@ export const AppRouterProviders = () => {
|
||||
</SSEProvider>
|
||||
</ApolloCoreProvider>
|
||||
</AuthProvider>
|
||||
</MetadataGater>
|
||||
</MinimalMetadataGater>
|
||||
</ChromeExtensionSidecarProvider>
|
||||
</CaptchaProvider>
|
||||
</ClientConfigProvider>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { useVerifyLogin } from '@/auth/hooks/useVerifyLogin';
|
||||
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
@@ -13,7 +13,7 @@ export const VerifyLoginTokenEffect = () => {
|
||||
const [searchParams] = useSearchParams();
|
||||
const loginToken = searchParams.get('loginToken');
|
||||
|
||||
const isLogged = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const navigate = useNavigateApp();
|
||||
const { verifyLoginToken } = useVerifyLogin();
|
||||
|
||||
@@ -28,7 +28,7 @@ export const VerifyLoginTokenEffect = () => {
|
||||
|
||||
if (isDefined(loginToken)) {
|
||||
verifyLoginToken(loginToken);
|
||||
} else if (!isLogged) {
|
||||
} else if (!hasAccessTokenPair) {
|
||||
navigate(AppPath.SignInUp);
|
||||
}
|
||||
// Verify only needs to run once at mount
|
||||
|
||||
@@ -30,12 +30,6 @@ jest.mock('@/domain-manager/hooks/useRedirect', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('@/object-metadata/hooks/useRefreshObjectMetadataItems', () => ({
|
||||
useRefreshObjectMetadataItems: jest.fn().mockImplementation(() => ({
|
||||
refreshObjectMetadataItems: jest.fn(),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('@/domain-manager/hooks/useOrigin', () => ({
|
||||
useOrigin: jest.fn().mockImplementation(() => ({
|
||||
origin: 'http://localhost',
|
||||
|
||||
+6
-6
@@ -1,27 +1,27 @@
|
||||
import { act, renderHook } from '@testing-library/react';
|
||||
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
|
||||
const renderHooks = () => {
|
||||
const { result } = renderHook(() => {
|
||||
const isLogged = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const setTokenPair = useSetAtomState(tokenPairState);
|
||||
|
||||
return {
|
||||
isLogged,
|
||||
hasAccessTokenPair,
|
||||
setTokenPair,
|
||||
};
|
||||
});
|
||||
return { result };
|
||||
};
|
||||
|
||||
describe('useIsLogged', () => {
|
||||
describe('useHasAccessTokenPair', () => {
|
||||
it('should return correct value', async () => {
|
||||
const { result } = renderHooks();
|
||||
|
||||
expect(result.current.isLogged).toBe(false);
|
||||
expect(result.current.hasAccessTokenPair).toBe(false);
|
||||
|
||||
await act(async () => {
|
||||
result.current.setTokenPair({
|
||||
@@ -36,6 +36,6 @@ describe('useIsLogged', () => {
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.isLogged).toBe(true);
|
||||
expect(result.current.hasAccessTokenPair).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -34,7 +34,7 @@ import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMembe
|
||||
import { currentWorkspaceMembersState } from '@/auth/states/currentWorkspaceMembersState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useSignUpInNewWorkspace } from '@/auth/sign-in-up/hooks/useSignUpInNewWorkspace';
|
||||
import { useReloadWorkspaceMetadata } from '@/metadata-store/hooks/useReloadWorkspaceMetadata';
|
||||
import { useLoadMockedMinimalMetadata } from '@/metadata-store/hooks/useLoadMockedMinimalMetadata';
|
||||
import { lastAuthenticatedMethodState } from '@/auth/states/lastAuthenticatedMethodState';
|
||||
import { loginTokenState } from '@/auth/states/loginTokenState';
|
||||
import {
|
||||
@@ -42,7 +42,6 @@ import {
|
||||
signInUpStepState,
|
||||
} from '@/auth/states/signInUpStepState';
|
||||
import { workspacePublicDataState } from '@/auth/states/workspacePublicDataState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type BillingCheckoutSession } from '@/auth/types/billingCheckoutSession.type';
|
||||
import {
|
||||
countAvailableWorkspaces,
|
||||
@@ -88,8 +87,7 @@ export const useAuth = () => {
|
||||
const { loadCurrentUser } = useLoadCurrentUser();
|
||||
const { clearSseClient } = useClearSseClient();
|
||||
|
||||
const { reloadWorkspaceMetadata, resetToMockedMetadata } =
|
||||
useReloadWorkspaceMetadata();
|
||||
const { loadMockedMinimalMetadata } = useLoadMockedMinimalMetadata();
|
||||
const { createWorkspace } = useSignUpInNewWorkspace();
|
||||
|
||||
const setSignInUpStep = useSetAtomState(signInUpStepState);
|
||||
@@ -163,18 +161,17 @@ export const useAuth = () => {
|
||||
});
|
||||
store.set(loginTokenState.atom, null);
|
||||
store.set(signInUpStepState.atom, SignInUpStep.Init);
|
||||
store.set(coreViewsState.atom, []);
|
||||
|
||||
await client.clearStore();
|
||||
setLastAuthenticateWorkspaceDomain(null);
|
||||
await resetToMockedMetadata();
|
||||
await loadMockedMinimalMetadata();
|
||||
navigate(AppPath.SignInUp);
|
||||
store.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
}, [
|
||||
clearSseClient,
|
||||
client,
|
||||
setLastAuthenticateWorkspaceDomain,
|
||||
resetToMockedMetadata,
|
||||
loadMockedMinimalMetadata,
|
||||
navigate,
|
||||
store,
|
||||
]);
|
||||
@@ -305,14 +302,10 @@ export const useAuth = () => {
|
||||
setIsAppEffectRedirectEnabled(false);
|
||||
|
||||
await loadCurrentUser();
|
||||
await reloadWorkspaceMetadata();
|
||||
|
||||
setIsAppEffectRedirectEnabled(true);
|
||||
},
|
||||
[
|
||||
loadCurrentUser,
|
||||
handleSetAuthTokens,
|
||||
reloadWorkspaceMetadata,
|
||||
setIsAppEffectRedirectEnabled,
|
||||
],
|
||||
[loadCurrentUser, handleSetAuthTokens, setIsAppEffectRedirectEnabled],
|
||||
);
|
||||
|
||||
const handleGetAuthTokensFromLoginToken = useCallback(
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
|
||||
export const useIsLogged = (): boolean => {
|
||||
export const useHasAccessTokenPair = (): boolean => {
|
||||
const [tokenPair] = useAtomState(tokenPairState);
|
||||
return !!tokenPair;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { objectMetadataItemsSelector } from '@/metadata-store/states/objectMetadataItemsSelector';
|
||||
import { flatObjectMetadataItemsSelector } from '@/object-metadata/states/flatObjectMetadataItemsSelector';
|
||||
import { createAtomFamilySelector } from '@/ui/utilities/state/jotai/utils/createAtomFamilySelector';
|
||||
|
||||
export const objectPermissionsFamilySelector = createAtomFamilySelector<
|
||||
@@ -14,7 +14,7 @@ export const objectPermissionsFamilySelector = createAtomFamilySelector<
|
||||
({ objectNameSingular }) =>
|
||||
({ get }) => {
|
||||
const currentUserWorkspace = get(currentUserWorkspaceState);
|
||||
const objectMetadataItems = get(objectMetadataItemsSelector);
|
||||
const objectMetadataItems = get(flatObjectMetadataItemsSelector);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(item) => item.nameSingular === objectNameSingular,
|
||||
|
||||
+14
-7
@@ -6,7 +6,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { useLocation, useParams, useSearchParams } from 'react-router-dom';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -38,6 +38,8 @@ const getViewId = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const SIGN_IN_BACKGROUND_OBJECT_NAME_PLURAL = 'companies';
|
||||
|
||||
export const MainContextStoreProvider = () => {
|
||||
const location = useLocation();
|
||||
const isRecordIndexPage = isMatchingLocation(
|
||||
@@ -46,16 +48,21 @@ export const MainContextStoreProvider = () => {
|
||||
);
|
||||
const isRecordShowPage = isMatchingLocation(location, AppPath.RecordShowPage);
|
||||
const isSettingsPage = useIsSettingsPage();
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const objectNamePlural = useParams().objectNamePlural ?? '';
|
||||
const objectNamePluralFromParams = useParams().objectNamePlural ?? '';
|
||||
const objectNameSingular = useParams().objectNameSingular ?? '';
|
||||
|
||||
const objectNamePlural = showAuthModal
|
||||
? SIGN_IN_BACKGROUND_OBJECT_NAME_PLURAL
|
||||
: objectNamePluralFromParams;
|
||||
|
||||
const [searchParams] = useSearchParams();
|
||||
const viewIdQueryParamRaw = searchParams.get('viewId');
|
||||
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
const metadataStore = useAtomFamilyStateValue(metadataStoreState, 'views');
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
|
||||
const objectMetadataItem = objectMetadataItems.find(
|
||||
(objectMetadataItem) =>
|
||||
@@ -108,11 +115,11 @@ export const MainContextStoreProvider = () => {
|
||||
firstAvailableViewId,
|
||||
);
|
||||
|
||||
const showAuthModal = useShowAuthModal();
|
||||
|
||||
const shouldComputeContextStore =
|
||||
(isRecordIndexPage || isRecordShowPage || isSettingsPage) &&
|
||||
!showAuthModal &&
|
||||
(isRecordIndexPage ||
|
||||
isRecordShowPage ||
|
||||
isSettingsPage ||
|
||||
showAuthModal) &&
|
||||
metadataStore.status === 'up-to-date';
|
||||
|
||||
if (!shouldComputeContextStore) {
|
||||
|
||||
+7
-10
@@ -1,9 +1,7 @@
|
||||
import React from 'react';
|
||||
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { useDateTimeFormat } from '@/localization/hooks/useDateTimeFormat';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { UserContext } from '@/users/contexts/UserContext';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
@@ -11,10 +9,8 @@ import { AppPath } from 'twenty-shared/types';
|
||||
import { UserOrMetadataLoader } from '~/loading/components/UserOrMetadataLoader';
|
||||
import { isMatchingLocation } from '~/utils/isMatchingLocation';
|
||||
|
||||
export const MetadataGater = ({ children }: React.PropsWithChildren) => {
|
||||
const isAppMetadataReady = useAtomStateValue(isAppMetadataReadyState);
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
const isLoggedIn = useIsLogged();
|
||||
export const MinimalMetadataGater = ({ children }: React.PropsWithChildren) => {
|
||||
const isMinimalMetadataReady = useAtomStateValue(isMinimalMetadataReadyState);
|
||||
const location = useLocation();
|
||||
|
||||
const { dateFormat, timeFormat, timeZone } = useDateTimeFormat();
|
||||
@@ -22,11 +18,12 @@ export const MetadataGater = ({ children }: React.PropsWithChildren) => {
|
||||
const isOnExcludedPath =
|
||||
isMatchingLocation(location, AppPath.Verify) ||
|
||||
isMatchingLocation(location, AppPath.VerifyEmail) ||
|
||||
isMatchingLocation(location, AppPath.SignInUp) ||
|
||||
isMatchingLocation(location, AppPath.Invite) ||
|
||||
isMatchingLocation(location, AppPath.ResetPassword) ||
|
||||
isMatchingLocation(location, AppPath.CreateWorkspace);
|
||||
|
||||
const shouldShowLoader =
|
||||
(!isAppMetadataReady && isLoggedIn && !isOnExcludedPath) ||
|
||||
objectMetadataItems.length === 0;
|
||||
const shouldShowLoader = !isMinimalMetadataReady && !isOnExcludedPath;
|
||||
|
||||
if (shouldShowLoader) {
|
||||
return <UserOrMetadataLoader />;
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const FieldMetadataSSEEffect = () => {
|
||||
const queryId = 'field-metadata-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.fieldMetadata,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.fieldMetadata,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'fieldMetadataItems',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
+18
-13
@@ -1,7 +1,7 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
@@ -10,8 +10,8 @@ import { useEffect } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
|
||||
export const IsAppMetadataReadyEffect = () => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
export const IsMinimalMetadataReadyEffect = () => {
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const metadataStore = useAtomFamilyStateValue(
|
||||
@@ -23,7 +23,9 @@ export const IsAppMetadataReadyEffect = () => {
|
||||
metadataStoreState,
|
||||
'views',
|
||||
);
|
||||
const setIsAppMetadataReady = useSetAtomState(isAppMetadataReadyState);
|
||||
const setIsMinimalMetadataReady = useSetAtomState(
|
||||
isMinimalMetadataReadyState,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const hasActiveWorkspace = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
@@ -31,23 +33,26 @@ export const IsAppMetadataReadyEffect = () => {
|
||||
const areObjectsLoaded = metadataStore.status === 'up-to-date';
|
||||
const areViewsLoaded = metadataStoreViews.status === 'up-to-date';
|
||||
|
||||
const isReady = !areObjectsLoaded
|
||||
? false
|
||||
: !hasAccessTokenPair ||
|
||||
(isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded));
|
||||
|
||||
if (!areObjectsLoaded) {
|
||||
setIsAppMetadataReady(false);
|
||||
setIsMinimalMetadataReady(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const isReady =
|
||||
!isLoggedIn ||
|
||||
(isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded));
|
||||
|
||||
setIsAppMetadataReady(isReady);
|
||||
if (isReady) {
|
||||
setIsMinimalMetadataReady(true);
|
||||
}
|
||||
}, [
|
||||
isLoggedIn,
|
||||
hasAccessTokenPair,
|
||||
currentUser,
|
||||
currentWorkspace,
|
||||
metadataStore.status,
|
||||
metadataStoreViews.status,
|
||||
setIsAppMetadataReady,
|
||||
setIsMinimalMetadataReady,
|
||||
]);
|
||||
|
||||
return null;
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import { ObjectMetadataProviderInitialEffect } from '@/metadata-store/effect-components/ObjectMetadataProviderInitialEffect';
|
||||
import { UserMetadataProviderInitialEffect } from '@/metadata-store/effect-components/UserMetadataProviderInitialEffect';
|
||||
import { ViewMetadataProviderInitialEffect } from '@/metadata-store/effect-components/ViewMetadataProviderInitialEffect';
|
||||
|
||||
export const MetadataProviderInitialEffects = () => (
|
||||
<>
|
||||
<UserMetadataProviderInitialEffect />
|
||||
<ObjectMetadataProviderInitialEffect />
|
||||
<ViewMetadataProviderInitialEffect />
|
||||
</>
|
||||
);
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { mapAllMetadataNameToEntityKey } from '@/metadata-store/utils/mapAllMetadataNameToEntityKey';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const MetadataStoreSSEEffect = () => {
|
||||
const store = useStore();
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
const entityKey = mapAllMetadataNameToEntityKey(eventDetail.metadataName);
|
||||
|
||||
if (!isDefined(entityKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
patchMetadataStoreFromSSEEvent({
|
||||
store,
|
||||
entityKey,
|
||||
operation: eventDetail.operation,
|
||||
updatedCollectionHash: eventDetail.updatedCollectionHash,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
+45
-34
@@ -1,62 +1,73 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||
import { useLoadMinimalMetadata } from '@/metadata-store/hooks/useLoadMinimalMetadata';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { useLoadMockedMinimalMetadata } from '@/metadata-store/hooks/useLoadMockedMinimalMetadata';
|
||||
import { useLoadStaleMetadataEntities } from '@/metadata-store/hooks/useLoadStaleMetadataEntities';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useStore } from 'jotai';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
|
||||
type LoadedState = 'none' | 'mocked' | 'real';
|
||||
|
||||
const computeDesiredLoadState = (
|
||||
hasAccessTokenPair: boolean,
|
||||
isActiveWorkspace: boolean,
|
||||
): LoadedState => {
|
||||
if (hasAccessTokenPair && isActiveWorkspace) {
|
||||
return 'real';
|
||||
}
|
||||
|
||||
return 'mocked';
|
||||
};
|
||||
|
||||
export const MinimalMetadataLoadEffect = () => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const isCurrentUserLoaded = useAtomStateValue(isCurrentUserLoadedState);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const store = useStore();
|
||||
const [hasLoaded, setHasLoaded] = useState(false);
|
||||
const [loadedState, setLoadedState] = useState<LoadedState>('none');
|
||||
|
||||
const { loadMinimalMetadata } = useLoadMinimalMetadata();
|
||||
const { loadMockedMinimalMetadata } = useLoadMockedMinimalMetadata();
|
||||
const { loadStaleMetadataEntities } = useLoadStaleMetadataEntities();
|
||||
|
||||
const isActiveWorkspace = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
|
||||
const desiredLoadState = computeDesiredLoadState(
|
||||
hasAccessTokenPair,
|
||||
isActiveWorkspace,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (hasLoaded) {
|
||||
if (!isCurrentUserLoaded || loadedState === desiredLoadState) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentUserLoaded || !isLoggedIn) {
|
||||
return;
|
||||
}
|
||||
setLoadedState(desiredLoadState);
|
||||
|
||||
if (!isWorkspaceActiveOrSuspended(currentWorkspace)) {
|
||||
return;
|
||||
}
|
||||
const performLoad = async () => {
|
||||
if (desiredLoadState === 'mocked') {
|
||||
await loadMockedMinimalMetadata();
|
||||
return;
|
||||
}
|
||||
|
||||
const objectsEntry = store.get(
|
||||
metadataStoreState.atomFamily('objectMetadataItems'),
|
||||
);
|
||||
const viewsEntry = store.get(metadataStoreState.atomFamily('views'));
|
||||
const result = await loadMinimalMetadata();
|
||||
|
||||
const hasObjectsFromStorage = objectsEntry.status === 'up-to-date';
|
||||
const hasViewsFromStorage = viewsEntry.status === 'up-to-date';
|
||||
|
||||
if (hasObjectsFromStorage && hasViewsFromStorage) {
|
||||
setHasLoaded(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const load = async () => {
|
||||
await loadMinimalMetadata();
|
||||
setHasLoaded(true);
|
||||
if (result?.staleEntityKeys && result.staleEntityKeys.length > 0) {
|
||||
await loadStaleMetadataEntities(result.staleEntityKeys);
|
||||
}
|
||||
};
|
||||
|
||||
load();
|
||||
performLoad();
|
||||
}, [
|
||||
hasLoaded,
|
||||
isCurrentUserLoaded,
|
||||
isLoggedIn,
|
||||
currentWorkspace,
|
||||
store,
|
||||
hasAccessTokenPair,
|
||||
isActiveWorkspace,
|
||||
desiredLoadState,
|
||||
loadedState,
|
||||
loadMinimalMetadata,
|
||||
loadMockedMinimalMetadata,
|
||||
loadStaleMetadataEntities,
|
||||
]);
|
||||
|
||||
return null;
|
||||
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { navigationMenuItemsState } from '@/navigation-menu-item/states/navigationMenuItemsState';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import {
|
||||
AllMetadataName,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const NavigationMenuItemSSEEffect = () => {
|
||||
const queryId = 'navigation-menu-item-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
const client = useApolloClient();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.navigationMenuItem,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.navigationMenuItem,
|
||||
onMetadataOperationBrowserEvent: async (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'navigationMenuItems',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const result = await client.query({
|
||||
query: FindManyNavigationMenuItemsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
if (!isDefined(result.data?.navigationMenuItems)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingNavigationMenuItems = store.get(
|
||||
navigationMenuItemsState.atom,
|
||||
);
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
existingNavigationMenuItems,
|
||||
result.data.navigationMenuItems,
|
||||
)
|
||||
) {
|
||||
store.set(
|
||||
navigationMenuItemsState.atom,
|
||||
result.data.navigationMenuItems,
|
||||
);
|
||||
|
||||
updateDraft('navigationMenuItems', result.data.navigationMenuItems);
|
||||
applyChanges();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-61
@@ -1,61 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { navigationMenuItemsState } from '@/navigation-menu-item/states/navigationMenuItemsState';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import {
|
||||
AllMetadataName,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const ObjectMetadataItemSSEEffect = () => {
|
||||
const queryId = 'object-metadata-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
const client = useApolloClient();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.objectMetadata,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.objectMetadata,
|
||||
onMetadataOperationBrowserEvent: async (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'objectMetadataItems',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const navigationMenuItemsResult = await client.query({
|
||||
query: FindManyNavigationMenuItemsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
const existingNavigationMenuItems = store.get(
|
||||
navigationMenuItemsState.atom,
|
||||
);
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
existingNavigationMenuItems,
|
||||
navigationMenuItemsResult.data?.navigationMenuItems,
|
||||
)
|
||||
) {
|
||||
store.set(
|
||||
navigationMenuItemsState.atom,
|
||||
navigationMenuItemsResult.data?.navigationMenuItems ?? [],
|
||||
);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||
import { useLoadMockedObjectMetadataItems } from '@/object-metadata/hooks/useLoadMockedObjectMetadataItems';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
|
||||
export const ObjectMetadataProviderInitialEffect = () => {
|
||||
const isCurrentUserLoaded = useAtomStateValue(isCurrentUserLoadedState);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
|
||||
const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems();
|
||||
const { loadMockedObjectMetadataItems } = useLoadMockedObjectMetadataItems();
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
if (!isCurrentUserLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
const shouldLoadReal = isWorkspaceActiveOrSuspended(currentWorkspace);
|
||||
|
||||
const loadObjectMetadata = async () => {
|
||||
if (shouldLoadReal) {
|
||||
await refreshObjectMetadataItems();
|
||||
} else {
|
||||
await loadMockedObjectMetadataItems();
|
||||
}
|
||||
|
||||
setIsInitialized(true);
|
||||
};
|
||||
|
||||
loadObjectMetadata();
|
||||
}, [
|
||||
isInitialized,
|
||||
isCurrentUserLoaded,
|
||||
currentWorkspace,
|
||||
refreshObjectMetadataItems,
|
||||
loadMockedObjectMetadataItems,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useRefreshPageLayouts } from '@/page-layout/hooks/useRefreshPageLayouts';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const PageLayoutSSEEffect = () => {
|
||||
const queryId = 'page-layout-metadata-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
const { refreshPageLayouts } = useRefreshPageLayouts();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.pageLayout,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.pageLayout,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'pageLayouts',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
refreshPageLayouts();
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useRefreshPageLayouts } from '@/page-layout/hooks/useRefreshPageLayouts';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const PageLayoutTabSSEEffect = () => {
|
||||
const queryId = 'page-layout-tab-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
const { refreshPageLayouts } = useRefreshPageLayouts();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.pageLayoutTab,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.pageLayoutTab,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'pageLayoutTabs',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
refreshPageLayouts();
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useRefreshPageLayouts } from '@/page-layout/hooks/useRefreshPageLayouts';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useStore } from 'jotai';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const PageLayoutWidgetSSEEffect = () => {
|
||||
const queryId = 'page-layout-widget-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
const { refreshPageLayouts } = useRefreshPageLayouts();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.pageLayoutWidget,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.pageLayoutWidget,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'pageLayoutWidgets',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
refreshPageLayouts();
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { availableWorkspacesState } from '@/auth/states/availableWorkspacesState';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
@@ -27,7 +27,7 @@ import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { dynamicActivate } from '~/utils/i18n/dynamicActivate';
|
||||
|
||||
export const UserMetadataProviderInitialEffect = () => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
const store = useStore();
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
@@ -65,7 +65,7 @@ export const UserMetadataProviderInitialEffect = () => {
|
||||
[store],
|
||||
);
|
||||
|
||||
const shouldSkipUserQuery = !isLoggedIn || isDefined(currentUser);
|
||||
const shouldSkipUserQuery = !hasAccessTokenPair || isDefined(currentUser);
|
||||
|
||||
const { data: userQueryData, loading: userQueryLoading } = useQuery(
|
||||
GetCurrentUserDocument,
|
||||
@@ -79,7 +79,7 @@ export const UserMetadataProviderInitialEffect = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn) {
|
||||
if (!hasAccessTokenPair) {
|
||||
setIsCurrentUserLoaded(true);
|
||||
setIsInitialized(true);
|
||||
return;
|
||||
@@ -165,7 +165,7 @@ export const UserMetadataProviderInitialEffect = () => {
|
||||
setIsInitialized(true);
|
||||
}, [
|
||||
isInitialized,
|
||||
isLoggedIn,
|
||||
hasAccessTokenPair,
|
||||
userQueryLoading,
|
||||
userQueryData?.currentUser,
|
||||
setCurrentUser,
|
||||
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
AllMetadataName,
|
||||
type CoreViewField,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
export const ViewFieldSSEEffect = () => {
|
||||
const store = useStore();
|
||||
|
||||
const queryId = 'view-field-metadata-sse-effect';
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewField,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewField,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'viewFields',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const coreViews = store.get(coreViewsState.atom);
|
||||
|
||||
let viewId: string | undefined;
|
||||
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
const createdViewField = eventDetail.operation
|
||||
.createdRecord as unknown as CoreViewField;
|
||||
viewId = createdViewField.viewId;
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
const updatedViewField = eventDetail.operation
|
||||
.updatedRecord as unknown as CoreViewField;
|
||||
viewId = updatedViewField.viewId;
|
||||
break;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedViewFieldId = eventDetail.operation
|
||||
.deletedRecordId as string;
|
||||
|
||||
const view = coreViews.find((coreView) =>
|
||||
coreView.viewFields.some(
|
||||
(viewField) => viewField.id === deletedViewFieldId,
|
||||
),
|
||||
);
|
||||
|
||||
viewId = view?.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = coreViews.find((coreView) => coreView.id === viewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
return;
|
||||
}
|
||||
|
||||
refreshCoreViewsByObjectMetadataId(view.objectMetadataId);
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const ViewFilterGroupSSEEffect = () => {
|
||||
const store = useStore();
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-filter-groups-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewFilterGroup,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewFilterGroup,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'viewFilterGroups',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const coreViews = store.get(coreViewsState.atom);
|
||||
|
||||
let viewId: string | undefined;
|
||||
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
viewId = (eventDetail.operation.createdRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
viewId = (eventDetail.operation.updatedRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedId = eventDetail.operation.deletedRecordId as string;
|
||||
viewId = coreViews.find((view) =>
|
||||
view.viewFilterGroups?.some(
|
||||
(viewFilterGroup) => viewFilterGroup.id === deletedId,
|
||||
),
|
||||
)?.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = coreViews.find((coreView) => coreView.id === viewId);
|
||||
|
||||
if (isDefined(view)) {
|
||||
refreshCoreViewsByObjectMetadataId(view.objectMetadataId);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const ViewFilterSSEEffect = () => {
|
||||
const store = useStore();
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-filters-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewFilter,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewFilter,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'viewFilters',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const coreViews = store.get(coreViewsState.atom);
|
||||
|
||||
let viewId: string | undefined;
|
||||
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
viewId = (eventDetail.operation.createdRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
viewId = (eventDetail.operation.updatedRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedId = eventDetail.operation.deletedRecordId as string;
|
||||
viewId = coreViews.find((view) =>
|
||||
view.viewFilters.some((viewFilter) => viewFilter.id === deletedId),
|
||||
)?.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = coreViews.find((coreView) => coreView.id === viewId);
|
||||
|
||||
if (isDefined(view)) {
|
||||
refreshCoreViewsByObjectMetadataId(view.objectMetadataId);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { isCurrentUserLoadedState } from '@/auth/states/isCurrentUserLoadedState';
|
||||
import { useFetchAndLoadIndexViews } from '@/metadata-store/hooks/useFetchAndLoadIndexViews';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { isWorkspaceActiveOrSuspended } from 'twenty-shared/workspace';
|
||||
|
||||
export const ViewMetadataProviderInitialEffect = () => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
const isCurrentUserLoaded = useAtomStateValue(isCurrentUserLoadedState);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
|
||||
const { fetchAndLoadIndexViews } = useFetchAndLoadIndexViews();
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialized) {
|
||||
return;
|
||||
}
|
||||
if (!isCurrentUserLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLoggedIn || !isWorkspaceActiveOrSuspended(currentWorkspace)) {
|
||||
setIsInitialized(true);
|
||||
return;
|
||||
}
|
||||
|
||||
const initialize = async () => {
|
||||
await fetchAndLoadIndexViews();
|
||||
|
||||
setIsInitialized(true);
|
||||
};
|
||||
|
||||
initialize();
|
||||
}, [
|
||||
isInitialized,
|
||||
isCurrentUserLoaded,
|
||||
isLoggedIn,
|
||||
currentWorkspace,
|
||||
fetchAndLoadIndexViews,
|
||||
]);
|
||||
|
||||
return null;
|
||||
};
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { type MetadataOperationBrowserEventDetail } from '@/browser-event/types/MetadataOperationBrowserEventDetail';
|
||||
import { useGetObjectMetadataItemIdFromViewRelationEventDetail } from '@/metadata-store/hooks/useGetObjectMetadataItemIdFromViewRelationEventDetail';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { type ViewSort } from '@/views/types/ViewSort';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const ViewRelationsSSEEffect = () => {
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { getObjectMetadataItemIdFromViewRelationEventDetail } =
|
||||
useGetObjectMetadataItemIdFromViewRelationEventDetail();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-filters-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewFilter,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-sorts-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewSort,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-fields-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewField,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-filter-groups-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewFilterGroup,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: replace this with detailed SSE optimistic effects
|
||||
const debouncedRefreshCoreViewsByObjectMetadataId = useDebouncedCallback(
|
||||
(objectMetadataId: string) => {
|
||||
refreshCoreViewsByObjectMetadataId(objectMetadataId);
|
||||
},
|
||||
500,
|
||||
{
|
||||
leading: false,
|
||||
trailing: true,
|
||||
},
|
||||
);
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewFilter,
|
||||
onMetadataOperationBrowserEvent: (
|
||||
detail: MetadataOperationBrowserEventDetail<ViewFilter>,
|
||||
) => {
|
||||
const objectMetadataItemId =
|
||||
getObjectMetadataItemIdFromViewRelationEventDetail(detail);
|
||||
|
||||
if (!isDefined(objectMetadataItemId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debouncedRefreshCoreViewsByObjectMetadataId(objectMetadataItemId);
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewSort,
|
||||
onMetadataOperationBrowserEvent: (
|
||||
detail: MetadataOperationBrowserEventDetail<ViewSort>,
|
||||
) => {
|
||||
const objectMetadataItemId =
|
||||
getObjectMetadataItemIdFromViewRelationEventDetail(detail);
|
||||
|
||||
if (!isDefined(objectMetadataItemId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debouncedRefreshCoreViewsByObjectMetadataId(objectMetadataItemId);
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewFilterGroup,
|
||||
onMetadataOperationBrowserEvent: (
|
||||
detail: MetadataOperationBrowserEventDetail<ViewFilterGroup>,
|
||||
) => {
|
||||
const objectMetadataItemId =
|
||||
getObjectMetadataItemIdFromViewRelationEventDetail(detail);
|
||||
|
||||
if (!isDefined(objectMetadataItemId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debouncedRefreshCoreViewsByObjectMetadataId(objectMetadataItemId);
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewField,
|
||||
onMetadataOperationBrowserEvent: (
|
||||
detail: MetadataOperationBrowserEventDetail<ViewField>,
|
||||
) => {
|
||||
const objectMetadataItemId =
|
||||
getObjectMetadataItemIdFromViewRelationEventDetail(detail);
|
||||
|
||||
if (!isDefined(objectMetadataItemId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
debouncedRefreshCoreViewsByObjectMetadataId(objectMetadataItemId);
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -1,93 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithoutRelations } from '@/views/types/CoreViewWithoutRelations';
|
||||
import { useStore } from 'jotai';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
import { sleep } from '~/utils/sleep';
|
||||
|
||||
export const ViewSSEEffect = () => {
|
||||
const queryId = 'views-sse-effect';
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId,
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.view,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.view,
|
||||
onMetadataOperationBrowserEvent: async (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'views',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
const createdView = eventDetail.operation
|
||||
.createdRecord as unknown as CoreViewWithoutRelations;
|
||||
|
||||
store.set(coreViewsState.atom, (prevCoreViews) => [
|
||||
...prevCoreViews,
|
||||
{
|
||||
...createdView,
|
||||
viewFields: [],
|
||||
viewFieldGroups: [],
|
||||
viewFilterGroups: [],
|
||||
viewSorts: [],
|
||||
viewFilters: [],
|
||||
viewGroups: [],
|
||||
},
|
||||
]);
|
||||
|
||||
await sleep(50);
|
||||
|
||||
refreshCoreViewsByObjectMetadataId(createdView.objectMetadataId);
|
||||
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
const updatedView = eventDetail.operation
|
||||
.updatedRecord as unknown as CoreViewWithoutRelations;
|
||||
|
||||
store.set(coreViewsState.atom, (prevCoreViews) =>
|
||||
prevCoreViews.map((coreView) =>
|
||||
coreView.id === updatedView.id
|
||||
? {
|
||||
...coreView,
|
||||
...updatedView,
|
||||
}
|
||||
: coreView,
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedViewId = eventDetail.operation.deletedRecordId as string;
|
||||
|
||||
store.set(coreViewsState.atom, (prevCoreViews) =>
|
||||
prevCoreViews.filter((coreView) => coreView.id !== deletedViewId),
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
-71
@@ -1,71 +0,0 @@
|
||||
import { useListenToMetadataOperationBrowserEvent } from '@/browser-event/hooks/useListenToMetadataOperationBrowserEvent';
|
||||
import { patchMetadataStoreFromSSEEvent } from '@/metadata-store/utils/patchMetadataStoreFromSSEEvent';
|
||||
import { useListenToEventsForQuery } from '@/sse-db-event/hooks/useListenToEventsForQuery';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useStore } from 'jotai';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const ViewSortSSEEffect = () => {
|
||||
const store = useStore();
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
useListenToEventsForQuery({
|
||||
queryId: 'view-sorts-sse-effect',
|
||||
operationSignature: {
|
||||
metadataName: AllMetadataName.viewSort,
|
||||
variables: {},
|
||||
},
|
||||
});
|
||||
|
||||
useListenToMetadataOperationBrowserEvent({
|
||||
metadataName: AllMetadataName.viewSort,
|
||||
onMetadataOperationBrowserEvent: (eventDetail) => {
|
||||
patchMetadataStoreFromSSEEvent(
|
||||
store,
|
||||
'viewSorts',
|
||||
eventDetail.operation,
|
||||
eventDetail.updatedCollectionHash,
|
||||
);
|
||||
|
||||
const coreViews = store.get(coreViewsState.atom);
|
||||
|
||||
let viewId: string | undefined;
|
||||
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
viewId = (eventDetail.operation.createdRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'update': {
|
||||
viewId = (eventDetail.operation.updatedRecord as { viewId?: string })
|
||||
.viewId;
|
||||
break;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedId = eventDetail.operation.deletedRecordId as string;
|
||||
viewId = coreViews.find((view) =>
|
||||
view.viewSorts.some((viewSort) => viewSort.id === deletedId),
|
||||
)?.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const view = coreViews.find((coreView) => coreView.id === viewId);
|
||||
|
||||
if (isDefined(view)) {
|
||||
refreshCoreViewsByObjectMetadataId(view.objectMetadataId);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return null;
|
||||
};
|
||||
+4
-1
@@ -21,7 +21,10 @@ export const FIND_MINIMAL_METADATA = gql`
|
||||
key
|
||||
objectMetadataId
|
||||
}
|
||||
collectionHashes
|
||||
collectionHashes {
|
||||
collectionName
|
||||
hash
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { useSetIndexViews } from '@/metadata-store/hooks/useSetIndexViews';
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import {
|
||||
ViewType,
|
||||
FindAllCoreViewsDocument,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const INDEX_VIEW_TYPES = [ViewType.TABLE, ViewType.KANBAN, ViewType.CALENDAR];
|
||||
|
||||
export const useFetchAndLoadIndexViews = () => {
|
||||
const client = useApolloClient();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
const { setIndexViews } = useSetIndexViews();
|
||||
|
||||
const fetchAndLoadIndexViews = useCallback(async () => {
|
||||
const result = await client.query({
|
||||
query: FindAllCoreViewsDocument,
|
||||
variables: { viewTypes: INDEX_VIEW_TYPES },
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
if (isDefined(result.data?.getCoreViews)) {
|
||||
setIndexViews(result.data.getCoreViews);
|
||||
|
||||
const {
|
||||
flatViews,
|
||||
flatViewFields,
|
||||
flatViewFilters,
|
||||
flatViewSorts,
|
||||
flatViewGroups,
|
||||
flatViewFilterGroups,
|
||||
flatViewFieldGroups,
|
||||
} = splitViewWithRelated(result.data.getCoreViews);
|
||||
|
||||
updateDraft('views', flatViews);
|
||||
updateDraft('viewFields', flatViewFields);
|
||||
updateDraft('viewFilters', flatViewFilters);
|
||||
updateDraft('viewSorts', flatViewSorts);
|
||||
updateDraft('viewGroups', flatViewGroups);
|
||||
updateDraft('viewFilterGroups', flatViewFilterGroups);
|
||||
updateDraft('viewFieldGroups', flatViewFieldGroups);
|
||||
applyChanges();
|
||||
}
|
||||
}, [client, setIndexViews, updateDraft, applyChanges]);
|
||||
|
||||
return { fetchAndLoadIndexViews };
|
||||
};
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
import { type MetadataOperationBrowserEventDetail } from '@/browser-event/types/MetadataOperationBrowserEventDetail';
|
||||
import { useGetViewIdFromViewSSERelationEventDetail } from '@/metadata-store/hooks/useGetViewIdFromViewSSERelationEventDetail';
|
||||
import { useGetViewById } from '@/views/hooks/useGetViewById';
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { type ViewSort } from '@/views/types/ViewSort';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useGetObjectMetadataItemIdFromViewRelationEventDetail = () => {
|
||||
const { getViewIdFromViewSSERelationEventDetail } =
|
||||
useGetViewIdFromViewSSERelationEventDetail();
|
||||
|
||||
const { getViewById } = useGetViewById();
|
||||
|
||||
const getObjectMetadataItemIdFromViewRelationEventDetail = <
|
||||
T extends ViewFilter | ViewFilterGroup | ViewField | ViewSort,
|
||||
>(
|
||||
eventDetail: MetadataOperationBrowserEventDetail<T>,
|
||||
) => {
|
||||
const viewId = getViewIdFromViewSSERelationEventDetail(eventDetail);
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { view } = getViewById(viewId);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return view.objectMetadataId;
|
||||
};
|
||||
|
||||
return {
|
||||
getObjectMetadataItemIdFromViewRelationEventDetail,
|
||||
};
|
||||
};
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
import { type MetadataOperationBrowserEventDetail } from '@/browser-event/types/MetadataOperationBrowserEventDetail';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type ViewField } from '@/views/types/ViewField';
|
||||
import { type ViewFilter } from '@/views/types/ViewFilter';
|
||||
import { type ViewFilterGroup } from '@/views/types/ViewFilterGroup';
|
||||
import { type ViewSort } from '@/views/types/ViewSort';
|
||||
import { type Nullable } from 'twenty-shared/types';
|
||||
import { AllMetadataName } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useGetViewIdFromViewSSERelationEventDetail = () => {
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
|
||||
const getViewIdFromViewSSERelationEventDetail = <
|
||||
T extends ViewFilter | ViewFilterGroup | ViewField | ViewSort,
|
||||
>(
|
||||
eventDetail: MetadataOperationBrowserEventDetail<T>,
|
||||
) => {
|
||||
switch (eventDetail.operation.type) {
|
||||
case 'create': {
|
||||
return eventDetail.operation.createdRecord?.viewId as Nullable<string>;
|
||||
}
|
||||
case 'update': {
|
||||
return eventDetail.operation.updatedRecord?.viewId as Nullable<string>;
|
||||
}
|
||||
case 'delete': {
|
||||
const deletedRecordId = eventDetail.operation.deletedRecordId;
|
||||
|
||||
switch (eventDetail.metadataName) {
|
||||
case AllMetadataName.viewFilter:
|
||||
return coreViews.find((view) =>
|
||||
view.viewFilters.some(
|
||||
(viewFilter) => viewFilter.id === deletedRecordId,
|
||||
),
|
||||
)?.id;
|
||||
case AllMetadataName.viewField:
|
||||
return coreViews.find((view) =>
|
||||
view.viewFields.some(
|
||||
(viewField) => viewField.id === deletedRecordId,
|
||||
),
|
||||
)?.id;
|
||||
case AllMetadataName.viewFilterGroup:
|
||||
return coreViews.find((view) =>
|
||||
view.viewFilterGroups?.some(
|
||||
(viewFilterGroup) => viewFilterGroup.id === deletedRecordId,
|
||||
),
|
||||
)?.id;
|
||||
case AllMetadataName.viewSort:
|
||||
return coreViews.find((view) =>
|
||||
view.viewSorts.some(
|
||||
(viewSort) => viewSort.id === deletedRecordId,
|
||||
),
|
||||
)?.id;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
getViewIdFromViewSSERelationEventDetail,
|
||||
};
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import { FIND_MINIMAL_METADATA } from '@/metadata-store/graphql/queries/findMinimalMetadata';
|
||||
import { metadataCollectionHashesState } from '@/metadata-store/states/metadataCollectionHashesState';
|
||||
import {
|
||||
metadataStoreState,
|
||||
type MetadataEntityKey,
|
||||
@@ -30,51 +29,56 @@ export const useLoadMinimalMetadata = () => {
|
||||
const { objectMetadataItems, views, collectionHashes } =
|
||||
result.data.minimalMetadata;
|
||||
|
||||
const localHashes = store.get(metadataCollectionHashesState.atom);
|
||||
|
||||
const serverHashes: Partial<Record<MetadataEntityKey, string>> = {};
|
||||
const staleEntityKeys: MetadataEntityKey[] = [];
|
||||
|
||||
if (isDefined(collectionHashes)) {
|
||||
for (const [metadataName, hash] of Object.entries(
|
||||
collectionHashes as Record<string, string>,
|
||||
)) {
|
||||
const entityKey = mapAllMetadataNameToEntityKey(metadataName);
|
||||
for (const { collectionName, hash } of collectionHashes) {
|
||||
const entityKey = mapAllMetadataNameToEntityKey(collectionName);
|
||||
|
||||
if (isDefined(entityKey)) {
|
||||
serverHashes[entityKey] = hash;
|
||||
if (!isDefined(entityKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry = store.get(metadataStoreState.atomFamily(entityKey));
|
||||
|
||||
if (entry.currentCollectionHash !== hash) {
|
||||
staleEntityKeys.push(entityKey);
|
||||
}
|
||||
|
||||
store.set(metadataStoreState.atomFamily(entityKey), (prev) => ({
|
||||
...prev,
|
||||
draftCollectionHash: hash,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
store.set(metadataCollectionHashesState.atom, serverHashes);
|
||||
|
||||
const staleEntityKeys: MetadataEntityKey[] = Object.entries(serverHashes)
|
||||
.filter(
|
||||
([entityKey, hash]) =>
|
||||
localHashes[entityKey as MetadataEntityKey] !== hash,
|
||||
)
|
||||
.map(([entityKey]) => entityKey as MetadataEntityKey);
|
||||
|
||||
const objectsEntry = store.get(
|
||||
metadataStoreState.atomFamily('objectMetadataItems'),
|
||||
);
|
||||
|
||||
if (objectsEntry.status === 'empty') {
|
||||
store.set(metadataStoreState.atomFamily('objectMetadataItems'), {
|
||||
current: objectMetadataItems as unknown as FlatObjectMetadataItem[],
|
||||
draft: [],
|
||||
status: 'up-to-date',
|
||||
});
|
||||
store.set(
|
||||
metadataStoreState.atomFamily('objectMetadataItems'),
|
||||
(prev) => ({
|
||||
...prev,
|
||||
current: objectMetadataItems as unknown as FlatObjectMetadataItem[],
|
||||
status: 'up-to-date',
|
||||
currentCollectionHash: prev.draftCollectionHash,
|
||||
draftCollectionHash: undefined,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
const viewsEntry = store.get(metadataStoreState.atomFamily('views'));
|
||||
|
||||
if (viewsEntry.status === 'empty') {
|
||||
store.set(metadataStoreState.atomFamily('views'), {
|
||||
store.set(metadataStoreState.atomFamily('views'), (prev) => ({
|
||||
...prev,
|
||||
current: views as unknown as FlatView[],
|
||||
draft: [],
|
||||
status: 'up-to-date',
|
||||
});
|
||||
currentCollectionHash: prev.draftCollectionHash,
|
||||
draftCollectionHash: undefined,
|
||||
}));
|
||||
}
|
||||
|
||||
return { staleEntityKeys };
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { splitObjectMetadataItemWithRelated } from '@/metadata-store/utils/splitObjectMetadataItemWithRelated';
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const MOCKED_COLLECTION_HASH = 'mocked';
|
||||
|
||||
export const useLoadMockedMinimalMetadata = () => {
|
||||
const { updateDraft, applyChanges, resetMetadataStore } = useMetadataStore();
|
||||
|
||||
const loadMockedMinimalMetadata = useCallback(async () => {
|
||||
resetMetadataStore();
|
||||
const [
|
||||
{ generatedMockObjectMetadataItems },
|
||||
{ mockedCoreViews },
|
||||
{ mockedNavigationMenuItems },
|
||||
] = await Promise.all([
|
||||
import('~/testing/utils/generatedMockObjectMetadataItems'),
|
||||
import('~/testing/mock-data/generated/metadata/views/mock-views-data'),
|
||||
import(
|
||||
'~/testing/mock-data/generated/metadata/navigation-menu-items/mock-navigation-menu-items-data'
|
||||
),
|
||||
]);
|
||||
|
||||
const { flatObjects, flatFields, flatIndexes } =
|
||||
splitObjectMetadataItemWithRelated(generatedMockObjectMetadataItems);
|
||||
|
||||
updateDraft('objectMetadataItems', flatObjects, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('fieldMetadataItems', flatFields, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('indexMetadataItems', flatIndexes, MOCKED_COLLECTION_HASH);
|
||||
|
||||
const {
|
||||
flatViews,
|
||||
flatViewFields,
|
||||
flatViewFilters,
|
||||
flatViewSorts,
|
||||
flatViewGroups,
|
||||
flatViewFilterGroups,
|
||||
flatViewFieldGroups,
|
||||
} = splitViewWithRelated(mockedCoreViews);
|
||||
|
||||
updateDraft('views', flatViews, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('viewFields', flatViewFields, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('viewFilters', flatViewFilters, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('viewSorts', flatViewSorts, MOCKED_COLLECTION_HASH);
|
||||
updateDraft('viewGroups', flatViewGroups, MOCKED_COLLECTION_HASH);
|
||||
updateDraft(
|
||||
'viewFilterGroups',
|
||||
flatViewFilterGroups,
|
||||
MOCKED_COLLECTION_HASH,
|
||||
);
|
||||
updateDraft('viewFieldGroups', flatViewFieldGroups, MOCKED_COLLECTION_HASH);
|
||||
|
||||
updateDraft(
|
||||
'navigationMenuItems',
|
||||
mockedNavigationMenuItems,
|
||||
MOCKED_COLLECTION_HASH,
|
||||
);
|
||||
|
||||
applyChanges();
|
||||
}, [updateDraft, applyChanges, resetMetadataStore]);
|
||||
|
||||
return { loadMockedMinimalMetadata };
|
||||
};
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { type MetadataEntityKey } from '@/metadata-store/states/metadataStoreState';
|
||||
import { splitObjectMetadataItemWithRelated } from '@/metadata-store/utils/splitObjectMetadataItemWithRelated';
|
||||
import { splitPageLayoutWithRelated } from '@/metadata-store/utils/splitPageLayoutWithRelated';
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
||||
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
|
||||
import { logicFunctionsState } from '@/settings/logic-functions/states/logicFunctionsState';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import {
|
||||
FindAllCoreViewsDocument,
|
||||
FindAllRecordPageLayoutsDocument,
|
||||
FindFieldsWidgetCoreViewsDocument,
|
||||
FindManyLogicFunctionsDocument,
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
type ObjectMetadataItemsQuery,
|
||||
ViewType,
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
const OBJECTS_GROUP_KEYS: MetadataEntityKey[] = [
|
||||
'objectMetadataItems',
|
||||
'fieldMetadataItems',
|
||||
'indexMetadataItems',
|
||||
];
|
||||
|
||||
const VIEWS_GROUP_KEYS: MetadataEntityKey[] = [
|
||||
'views',
|
||||
'viewFields',
|
||||
'viewFilters',
|
||||
'viewSorts',
|
||||
'viewGroups',
|
||||
'viewFilterGroups',
|
||||
'viewFieldGroups',
|
||||
];
|
||||
|
||||
const PAGE_LAYOUTS_GROUP_KEYS: MetadataEntityKey[] = [
|
||||
'pageLayouts',
|
||||
'pageLayoutTabs',
|
||||
'pageLayoutWidgets',
|
||||
];
|
||||
|
||||
const INDEX_VIEW_TYPES = [ViewType.TABLE, ViewType.KANBAN, ViewType.CALENDAR];
|
||||
const FIELDS_WIDGET_VIEW_TYPES = [ViewType.FIELDS_WIDGET];
|
||||
|
||||
const hasOverlap = (
|
||||
staleKeys: MetadataEntityKey[],
|
||||
groupKeys: MetadataEntityKey[],
|
||||
): boolean => staleKeys.some((key) => groupKeys.includes(key));
|
||||
|
||||
export const useLoadStaleMetadataEntities = () => {
|
||||
const client = useApolloClient();
|
||||
const store = useStore();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const loadStaleMetadataEntities = useCallback(
|
||||
async (staleEntityKeys: MetadataEntityKey[]) => {
|
||||
if (staleEntityKeys.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchPromises: Promise<void>[] = [];
|
||||
|
||||
if (hasOverlap(staleEntityKeys, OBJECTS_GROUP_KEYS)) {
|
||||
fetchPromises.push(
|
||||
client
|
||||
.query<ObjectMetadataItemsQuery>({
|
||||
query: FIND_MANY_OBJECT_METADATA_ITEMS,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
const compositeObjects =
|
||||
mapPaginatedObjectMetadataItemsToObjectMetadataItems({
|
||||
pagedObjectMetadataItems: result.data,
|
||||
});
|
||||
|
||||
const { flatObjects, flatFields, flatIndexes } =
|
||||
splitObjectMetadataItemWithRelated(compositeObjects);
|
||||
|
||||
updateDraft('objectMetadataItems', flatObjects);
|
||||
updateDraft('fieldMetadataItems', flatFields);
|
||||
updateDraft('indexMetadataItems', flatIndexes);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (hasOverlap(staleEntityKeys, VIEWS_GROUP_KEYS)) {
|
||||
fetchPromises.push(
|
||||
Promise.all([
|
||||
client.query({
|
||||
query: FindAllCoreViewsDocument,
|
||||
variables: { viewTypes: INDEX_VIEW_TYPES },
|
||||
fetchPolicy: 'network-only',
|
||||
}),
|
||||
client.query({
|
||||
query: FindFieldsWidgetCoreViewsDocument,
|
||||
variables: { viewTypes: FIELDS_WIDGET_VIEW_TYPES },
|
||||
fetchPolicy: 'network-only',
|
||||
}),
|
||||
]).then(([indexViewsResult, fieldsWidgetViewsResult]) => {
|
||||
const allViews = [
|
||||
...(indexViewsResult.data?.getCoreViews ?? []),
|
||||
...(fieldsWidgetViewsResult.data?.getCoreViews ?? []),
|
||||
];
|
||||
|
||||
const {
|
||||
flatViews,
|
||||
flatViewFields,
|
||||
flatViewFilters,
|
||||
flatViewSorts,
|
||||
flatViewGroups,
|
||||
flatViewFilterGroups,
|
||||
flatViewFieldGroups,
|
||||
} = splitViewWithRelated(allViews);
|
||||
|
||||
updateDraft('views', flatViews);
|
||||
updateDraft('viewFields', flatViewFields);
|
||||
updateDraft('viewFilters', flatViewFilters);
|
||||
updateDraft('viewSorts', flatViewSorts);
|
||||
updateDraft('viewGroups', flatViewGroups);
|
||||
updateDraft('viewFilterGroups', flatViewFilterGroups);
|
||||
updateDraft('viewFieldGroups', flatViewFieldGroups);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (hasOverlap(staleEntityKeys, PAGE_LAYOUTS_GROUP_KEYS)) {
|
||||
fetchPromises.push(
|
||||
client
|
||||
.query({
|
||||
query: FindAllRecordPageLayoutsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
if (!isDefined(result.data?.getPageLayouts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const transformed =
|
||||
result.data.getPageLayouts.map(transformPageLayout);
|
||||
|
||||
const {
|
||||
flatPageLayouts,
|
||||
flatPageLayoutTabs,
|
||||
flatPageLayoutWidgets,
|
||||
} = splitPageLayoutWithRelated(transformed);
|
||||
|
||||
updateDraft('pageLayouts', flatPageLayouts);
|
||||
updateDraft('pageLayoutTabs', flatPageLayoutTabs);
|
||||
updateDraft('pageLayoutWidgets', flatPageLayoutWidgets);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (staleEntityKeys.includes('logicFunctions')) {
|
||||
fetchPromises.push(
|
||||
client
|
||||
.query({
|
||||
query: FindManyLogicFunctionsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
if (!isDefined(result.data?.findManyLogicFunctions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
store.set(
|
||||
logicFunctionsState.atom,
|
||||
result.data.findManyLogicFunctions,
|
||||
);
|
||||
updateDraft('logicFunctions', result.data.findManyLogicFunctions);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (staleEntityKeys.includes('navigationMenuItems')) {
|
||||
fetchPromises.push(
|
||||
client
|
||||
.query({
|
||||
query: FindManyNavigationMenuItemsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
if (!isDefined(result.data?.navigationMenuItems)) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateDraft(
|
||||
'navigationMenuItems',
|
||||
result.data.navigationMenuItems,
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(fetchPromises);
|
||||
applyChanges();
|
||||
},
|
||||
[client, store, updateDraft, applyChanges],
|
||||
);
|
||||
|
||||
return { loadStaleMetadataEntities };
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
import { metadataCollectionHashesState } from '@/metadata-store/states/metadataCollectionHashesState';
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import {
|
||||
ALL_METADATA_ENTITY_KEYS,
|
||||
metadataStoreState,
|
||||
@@ -37,8 +36,7 @@ export const resetMetadataStore = (store: JotaiStore) => {
|
||||
store.set(metadataStoreState.atomFamily(key), EMPTY_ENTRY);
|
||||
}
|
||||
|
||||
store.set(metadataCollectionHashesState.atom, {});
|
||||
store.set(isAppMetadataReadyState.atom, false);
|
||||
store.set(isMinimalMetadataReadyState.atom, false);
|
||||
};
|
||||
|
||||
const changeMetadataEntityAsUpToDate = (
|
||||
@@ -51,6 +49,9 @@ const changeMetadataEntityAsUpToDate = (
|
||||
current: entry.draft,
|
||||
draft: [],
|
||||
status: 'up-to-date',
|
||||
currentCollectionHash:
|
||||
entry.draftCollectionHash ?? entry.currentCollectionHash,
|
||||
draftCollectionHash: undefined,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -58,7 +59,11 @@ export const useMetadataStore = () => {
|
||||
const store = useStore();
|
||||
|
||||
const updateDraft = useCallback(
|
||||
<K extends MetadataEntityKey>(key: K, data: MetadataEntityTypeMap[K][]) => {
|
||||
<K extends MetadataEntityKey>(
|
||||
key: K,
|
||||
data: MetadataEntityTypeMap[K][],
|
||||
collectionHash?: string,
|
||||
) => {
|
||||
const currentEntry = store.get(metadataStoreState.atomFamily(key));
|
||||
|
||||
if (
|
||||
@@ -72,6 +77,9 @@ export const useMetadataStore = () => {
|
||||
...prev,
|
||||
draft: data,
|
||||
status: 'draft-pending' as const,
|
||||
...(collectionHash !== undefined
|
||||
? { draftCollectionHash: collectionHash }
|
||||
: {}),
|
||||
}));
|
||||
},
|
||||
[store],
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { splitViewWithRelated } from '@/metadata-store/utils/splitViewWithRelated';
|
||||
import { useLoadMockedObjectMetadataItems } from '@/object-metadata/hooks/useLoadMockedObjectMetadataItems';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useReloadWorkspaceMetadata = () => {
|
||||
const store = useStore();
|
||||
const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems();
|
||||
const { loadMockedObjectMetadataItems } = useLoadMockedObjectMetadataItems();
|
||||
const { updateDraft, applyChanges, resetMetadataStore } = useMetadataStore();
|
||||
|
||||
const reloadWorkspaceMetadata = useCallback(async () => {
|
||||
resetMetadataStore();
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
|
||||
const loadedViews = store.get(coreViewsState.atom);
|
||||
const {
|
||||
flatViews,
|
||||
flatViewFields,
|
||||
flatViewFilters,
|
||||
flatViewSorts,
|
||||
flatViewGroups,
|
||||
flatViewFilterGroups,
|
||||
flatViewFieldGroups,
|
||||
} = splitViewWithRelated(loadedViews);
|
||||
|
||||
updateDraft('views', flatViews);
|
||||
updateDraft('viewFields', flatViewFields);
|
||||
updateDraft('viewFilters', flatViewFilters);
|
||||
updateDraft('viewSorts', flatViewSorts);
|
||||
updateDraft('viewGroups', flatViewGroups);
|
||||
updateDraft('viewFilterGroups', flatViewFilterGroups);
|
||||
updateDraft('viewFieldGroups', flatViewFieldGroups);
|
||||
applyChanges();
|
||||
}, [
|
||||
resetMetadataStore,
|
||||
refreshObjectMetadataItems,
|
||||
store,
|
||||
updateDraft,
|
||||
applyChanges,
|
||||
]);
|
||||
|
||||
const resetToMockedMetadata = useCallback(async () => {
|
||||
resetMetadataStore();
|
||||
|
||||
await loadMockedObjectMetadataItems();
|
||||
}, [resetMetadataStore, loadMockedObjectMetadataItems]);
|
||||
|
||||
return { reloadWorkspaceMetadata, resetToMockedMetadata };
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { ViewType } from '~/generated-metadata/graphql';
|
||||
import { isDeeplyEqual } from '~/utils/isDeeplyEqual';
|
||||
|
||||
export const useSetIndexViews = () => {
|
||||
const store = useStore();
|
||||
|
||||
const setIndexViews = useCallback(
|
||||
(indexViews: CoreViewWithRelations[]) => {
|
||||
const existingCoreViews = store.get(coreViewsState.atom);
|
||||
const existingFieldsWidgetViews = existingCoreViews.filter(
|
||||
(view) => view.type === ViewType.FIELDS_WIDGET,
|
||||
);
|
||||
const mergedViews = [...indexViews, ...existingFieldsWidgetViews];
|
||||
|
||||
if (!isDeeplyEqual(existingCoreViews, mergedViews)) {
|
||||
store.set(coreViewsState.atom, mergedViews);
|
||||
}
|
||||
},
|
||||
[store],
|
||||
);
|
||||
|
||||
return {
|
||||
setIndexViews,
|
||||
};
|
||||
};
|
||||
@@ -1,27 +0,0 @@
|
||||
import { metadataCollectionHashesState } from '@/metadata-store/states/metadataCollectionHashesState';
|
||||
import {
|
||||
ALL_METADATA_ENTITY_KEYS,
|
||||
type MetadataEntityKey,
|
||||
} from '@/metadata-store/states/metadataStoreState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
// Returns the list of MetadataEntityKey whose local collection hash
|
||||
// is missing or differs from the last known server collection hash.
|
||||
export const useStaleMetadataEntities = (): MetadataEntityKey[] => {
|
||||
const metadataCollectionHashes = useAtomStateValue(
|
||||
metadataCollectionHashesState,
|
||||
);
|
||||
|
||||
return useMemo(() => {
|
||||
const staleKeys: MetadataEntityKey[] = [];
|
||||
|
||||
for (const entityKey of ALL_METADATA_ENTITY_KEYS) {
|
||||
if (metadataCollectionHashes[entityKey] === undefined) {
|
||||
staleKeys.push(entityKey);
|
||||
}
|
||||
}
|
||||
|
||||
return staleKeys;
|
||||
}, [metadataCollectionHashes]);
|
||||
};
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
|
||||
export const isAppMetadataReadyState = createAtomState<boolean>({
|
||||
key: 'isAppMetadataReadyState',
|
||||
export const isMinimalMetadataReadyState = createAtomState<boolean>({
|
||||
key: 'isMinimalMetadataReadyState',
|
||||
defaultValue: false,
|
||||
});
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
import { type MetadataEntityKey } from '@/metadata-store/states/metadataStoreState';
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
|
||||
export const metadataCollectionHashesState = createAtomState<
|
||||
Partial<Record<MetadataEntityKey, string>>
|
||||
>({
|
||||
key: 'metadataCollectionHashesState',
|
||||
defaultValue: {},
|
||||
useLocalStorage: true,
|
||||
localStorageOptions: { getOnInit: true },
|
||||
});
|
||||
@@ -38,6 +38,8 @@ export type MetadataStoreItem = {
|
||||
current: object[];
|
||||
draft: object[];
|
||||
status: MetadataEntityStoreStatus;
|
||||
currentCollectionHash?: string;
|
||||
draftCollectionHash?: string;
|
||||
};
|
||||
|
||||
const METADATA_STORE_ITEM_INITIAL_VALUE: MetadataStoreItem = {
|
||||
|
||||
+18
-16
@@ -1,4 +1,3 @@
|
||||
import { metadataCollectionHashesState } from '@/metadata-store/states/metadataCollectionHashesState';
|
||||
import {
|
||||
metadataStoreState,
|
||||
type MetadataEntityKey,
|
||||
@@ -22,19 +21,29 @@ type SSEEventOperation =
|
||||
deletedRecordId: string;
|
||||
};
|
||||
|
||||
export const patchMetadataStoreFromSSEEvent = (
|
||||
store: JotaiStore,
|
||||
entityKey: MetadataEntityKey,
|
||||
operation: SSEEventOperation,
|
||||
updatedCollectionHash?: string,
|
||||
) => {
|
||||
export const patchMetadataStoreFromSSEEvent = ({
|
||||
store,
|
||||
entityKey,
|
||||
operation,
|
||||
updatedCollectionHash,
|
||||
}: {
|
||||
store: JotaiStore;
|
||||
entityKey: MetadataEntityKey;
|
||||
operation: SSEEventOperation;
|
||||
updatedCollectionHash?: string;
|
||||
}) => {
|
||||
const entry = store.get(metadataStoreState.atomFamily(entityKey));
|
||||
const currentItems = entry.current as Array<{ id: string }>;
|
||||
|
||||
const hashUpdate = isDefined(updatedCollectionHash)
|
||||
? { currentCollectionHash: updatedCollectionHash }
|
||||
: {};
|
||||
|
||||
switch (operation.type) {
|
||||
case 'create': {
|
||||
store.set(metadataStoreState.atomFamily(entityKey), {
|
||||
...entry,
|
||||
...hashUpdate,
|
||||
current: [...currentItems, operation.createdRecord],
|
||||
});
|
||||
break;
|
||||
@@ -42,6 +51,7 @@ export const patchMetadataStoreFromSSEEvent = (
|
||||
case 'update': {
|
||||
store.set(metadataStoreState.atomFamily(entityKey), {
|
||||
...entry,
|
||||
...hashUpdate,
|
||||
current: currentItems.map((item) =>
|
||||
item.id === (operation.updatedRecord as { id: string }).id
|
||||
? { ...item, ...operation.updatedRecord }
|
||||
@@ -53,6 +63,7 @@ export const patchMetadataStoreFromSSEEvent = (
|
||||
case 'delete': {
|
||||
store.set(metadataStoreState.atomFamily(entityKey), {
|
||||
...entry,
|
||||
...hashUpdate,
|
||||
current: currentItems.filter(
|
||||
(item) => item.id !== operation.deletedRecordId,
|
||||
),
|
||||
@@ -60,13 +71,4 @@ export const patchMetadataStoreFromSSEEvent = (
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDefined(updatedCollectionHash)) {
|
||||
const currentHashes = store.get(metadataCollectionHashesState.atom);
|
||||
|
||||
store.set(metadataCollectionHashesState.atom, {
|
||||
...currentHashes,
|
||||
[entityKey]: updatedCollectionHash,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { NavigationDrawerSubItem } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSubItem';
|
||||
import { getNavigationSubItemLeftAdornment } from '@/ui/navigation/navigation-drawer/utils/getNavigationSubItemLeftAdornment';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { ViewKey } from '@/views/types/ViewKey';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
|
||||
@@ -38,7 +38,7 @@ export const WorkspaceNavigationMenuItemFolderSubItem = ({
|
||||
isNavigationMenuInEditModeState,
|
||||
);
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
const objectMetadataItem =
|
||||
navigationMenuItem.itemType === NavigationMenuItemType.VIEW ||
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ import { validateAndExtractWorkspaceFolderId } from '@/navigation-menu-item/util
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
@@ -42,7 +42,7 @@ export const useHandleAddToNavigationDrop = () => {
|
||||
const { openNavigationMenuItemInSidePanel } =
|
||||
useOpenNavigationMenuItemInSidePanel();
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const { getIcon } = useIcons();
|
||||
const setIsNavigationMenuInEditMode = useSetAtomState(
|
||||
isNavigationMenuInEditModeState,
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import { recordIdentifierToObjectRecordIdentifier } from '@/navigation-menu-item
|
||||
import { sortNavigationMenuItems } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
|
||||
@@ -26,7 +26,7 @@ type NavigationMenuItemFolderEntry = Pick<
|
||||
>;
|
||||
|
||||
export const useNavigationMenuItemsByFolder = () => {
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
|
||||
const { navigationMenuItems, workspaceNavigationMenuItems } =
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { getObjectMetadataIdsInDraft } from '@/navigation-menu-item/utils/getObjectMetadataIdsInDraft';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { ViewKey } from '@/views/types/ViewKey';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
|
||||
@@ -15,7 +15,7 @@ type NavigationMenuItemDraft = {
|
||||
export const useNavigationMenuObjectMetadataFromDraft = (
|
||||
currentDraft: NavigationMenuItemDraft[],
|
||||
) => {
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
|
||||
const objectMetadataIdsInWorkspace = getObjectMetadataIdsInDraft(
|
||||
|
||||
+14
-9
@@ -1,9 +1,12 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { useApolloCoreClient } from '@/object-metadata/hooks/useApolloCoreClient';
|
||||
import { FindManyNavigationMenuItemsDocument } from '~/generated-metadata/graphql';
|
||||
import { navigationMenuItemsState } from '@/navigation-menu-item/states/navigationMenuItemsState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import {
|
||||
FindManyNavigationMenuItemsDocument,
|
||||
type NavigationMenuItem,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useStore } from 'jotai';
|
||||
|
||||
@@ -11,15 +14,16 @@ export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
const store = useStore();
|
||||
const apolloCoreClient = useApolloCoreClient();
|
||||
const cache = apolloCoreClient.cache;
|
||||
|
||||
const setNavigationMenuItems = useSetAtomState(navigationMenuItemsState);
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const removeNavigationMenuItemsByTargetRecordIds = useCallback(
|
||||
(targetRecordIds: string[]) => {
|
||||
const targetRecordIdsSet = new Set(targetRecordIds);
|
||||
const currentNavigationMenuItems = store.get(
|
||||
navigationMenuItemsState.atom,
|
||||
const entry = store.get(
|
||||
metadataStoreState.atomFamily('navigationMenuItems'),
|
||||
);
|
||||
const currentNavigationMenuItems =
|
||||
entry.current as unknown as NavigationMenuItem[];
|
||||
|
||||
const updatedNavigationMenuItems = currentNavigationMenuItems.filter(
|
||||
(item) =>
|
||||
@@ -27,7 +31,8 @@ export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
!targetRecordIdsSet.has(item.targetRecordId),
|
||||
);
|
||||
|
||||
setNavigationMenuItems(updatedNavigationMenuItems);
|
||||
updateDraft('navigationMenuItems', updatedNavigationMenuItems);
|
||||
applyChanges();
|
||||
|
||||
cache.updateQuery(
|
||||
{ query: FindManyNavigationMenuItemsDocument },
|
||||
@@ -43,7 +48,7 @@ export const useRemoveNavigationMenuItemByTargetRecordId = () => {
|
||||
},
|
||||
);
|
||||
},
|
||||
[cache, setNavigationMenuItems, store],
|
||||
[cache, store, updateDraft, applyChanges],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
+2
-2
@@ -2,12 +2,12 @@ import { useSelectedNavigationMenuItemEditItem } from '@/navigation-menu-item/ho
|
||||
import { getObjectMetadataForNavigationMenuItem } from '@/navigation-menu-item/utils/getObjectMetadataForNavigationMenuItem';
|
||||
import { useObjectMetadataItems } from '@/object-metadata/hooks/useObjectMetadataItems';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
|
||||
export const useSelectedNavigationMenuItemEditItemObjectMetadata = () => {
|
||||
const { selectedItem } = useSelectedNavigationMenuItemEditItem();
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
const { objectMetadataItems } = useObjectMetadataItems();
|
||||
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import { recordIdentifierToObjectRecordIdentifier } from '@/navigation-menu-item
|
||||
import { sortNavigationMenuItems } from '@/navigation-menu-item/utils/sortNavigationMenuItems';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { type ObjectRecordIdentifier } from '@/object-record/types/ObjectRecordIdentifier';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useNavigationMenuItemsData } from './useNavigationMenuItemsData';
|
||||
export const useSortedNavigationMenuItems = () => {
|
||||
const { navigationMenuItems, workspaceNavigationMenuItems } =
|
||||
useNavigationMenuItemsData();
|
||||
const coreViews = useAtomStateValue(coreViewsState).map(
|
||||
const coreViews = useAtomStateValue(coreViewsSelector).map(
|
||||
convertCoreViewToView,
|
||||
);
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import { isNavigationMenuItemFolder } from '@/navigation-menu-item/utils/isNavig
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -15,7 +15,7 @@ export const useWorkspaceNavigationMenuItems = (): {
|
||||
} => {
|
||||
const { workspaceNavigationMenuItems: rawWorkspaceNavigationMenuItems } =
|
||||
useNavigationMenuItemsData();
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadat
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -35,7 +35,7 @@ export const useWorkspaceSectionItems = (): FlatWorkspaceItem[] => {
|
||||
const { workspaceNavigationMenuItemsSorted } = useSortedNavigationMenuItems();
|
||||
const { workspaceNavigationMenuItemsByFolder } =
|
||||
useNavigationMenuItemsByFolder();
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
|
||||
+10
-3
@@ -1,7 +1,14 @@
|
||||
import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState';
|
||||
import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
|
||||
import { type NavigationMenuItem } from '~/generated-metadata/graphql';
|
||||
|
||||
export const navigationMenuItemsState = createAtomState<NavigationMenuItem[]>({
|
||||
export const navigationMenuItemsState = createAtomSelector<
|
||||
NavigationMenuItem[]
|
||||
>({
|
||||
key: 'navigationMenuItemsState',
|
||||
defaultValue: [],
|
||||
get: ({ get }) => {
|
||||
const entry = get(metadataStoreState, 'navigationMenuItems');
|
||||
|
||||
return entry.current as unknown as NavigationMenuItem[];
|
||||
},
|
||||
});
|
||||
|
||||
+11
-12
@@ -1,14 +1,12 @@
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { createElement, useEffect, type ReactNode } from 'react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePath';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { AggregateOperations } from '@/object-record/record-table/constants/AggregateOperations';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { renderHook, waitFor } from '@testing-library/react';
|
||||
import { Provider as JotaiProvider } from 'jotai';
|
||||
import { createElement, useEffect, type ReactNode } from 'react';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
import {
|
||||
ViewOpenRecordIn,
|
||||
@@ -16,8 +14,10 @@ import {
|
||||
ViewVisibility,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { mockedUserData } from '~/testing/mock-data/users';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
import { setTestCoreViewsInMetadataStore } from '~/testing/utils/setTestCoreViewsInMetadataStore';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) =>
|
||||
createElement(JotaiProvider, { store: jotaiStore }, children);
|
||||
@@ -40,11 +40,10 @@ const renderHooks = ({
|
||||
const setCurrentUserWorkspace = useSetAtomState(
|
||||
currentUserWorkspaceState,
|
||||
);
|
||||
const setCoreViews = useSetAtomState(coreViewsState);
|
||||
|
||||
useEffect(() => {
|
||||
if (withExistingView) {
|
||||
setCoreViews([
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [
|
||||
{
|
||||
id: 'viewId',
|
||||
name: 'Test View',
|
||||
@@ -69,14 +68,14 @@ const renderHooks = ({
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
setCoreViews([]);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, []);
|
||||
}
|
||||
|
||||
if (withCurrentUser) {
|
||||
setCurrentUser(mockedUserData);
|
||||
setCurrentUserWorkspace(mockedUserData.currentUserWorkspace);
|
||||
}
|
||||
}, [setCurrentUser, setCurrentUserWorkspace, setCoreViews]);
|
||||
}, [setCurrentUser, setCurrentUserWorkspace]);
|
||||
|
||||
return useDefaultHomePagePath();
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilte
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { getObjectPermissionsFromMapByObjectMetadataId } from '@/settings/roles/role-permissions/objects-permissions/utils/getObjectPermissionsFromMapByObjectMetadataId';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import isEmpty from 'lodash.isempty';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
@@ -43,7 +43,7 @@ export const useDefaultHomePagePath = () => {
|
||||
[readableAlphaSortedActiveNonSystemObjectMetadataItems],
|
||||
);
|
||||
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
|
||||
const getFirstView = useCallback(
|
||||
(objectMetadataItemId: string | undefined | null) => {
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
import { lastVisitedViewPerObjectMetadataItemState } from '@/navigation/states/lastVisitedViewPerObjectMetadataItemState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -16,7 +16,7 @@ export const useSetLastVisitedViewForObjectMetadataNamePlural = () => {
|
||||
objectNamePlural: string;
|
||||
viewId: string;
|
||||
}) => {
|
||||
const views = store.get(coreViewsState.atom);
|
||||
const views = store.get(coreViewsSelector.atom);
|
||||
|
||||
const view = views.find(
|
||||
(view: CoreViewWithRelations) => view.id === viewId,
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ import { NavigationDrawerItemForObjectMetadataItem } from '@/object-metadata/com
|
||||
import type { WorkspaceSectionItemContentProps } from '@/object-metadata/components/WorkspaceSectionItemContentProps';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
|
||||
type NavigationDrawerSectionForWorkspaceItemObjectContentProps =
|
||||
@@ -17,7 +17,7 @@ export const NavigationDrawerSectionForWorkspaceItemObjectContent = ({
|
||||
onActiveObjectMetadataItemClick,
|
||||
}: NavigationDrawerSectionForWorkspaceItemObjectContentProps) => {
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsState);
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
const objectMetadataItem = getObjectMetadataForNavigationMenuItem(
|
||||
item as ProcessedNavigationMenuItem,
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ import { NavigationDrawerSection } from '@/ui/navigation/navigation-drawer/compo
|
||||
import { NavigationDrawerSectionTitle } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerSectionTitle';
|
||||
import { useNavigationSection } from '@/ui/navigation/navigation-drawer/hooks/useNavigationSection';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { styled } from '@linaria/react';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
@@ -64,7 +64,7 @@ export const NavigationDrawerSectionForWorkspaceItems = ({
|
||||
);
|
||||
const { toggleNavigationSection, isNavigationSectionOpen } =
|
||||
useNavigationSection('Workspace');
|
||||
const coreViews = useAtomStateValue(coreViewsState);
|
||||
const coreViews = useAtomStateValue(coreViewsSelector);
|
||||
const views = coreViews.map(convertCoreViewToView);
|
||||
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
-2
@@ -244,7 +244,6 @@ describe('useFieldMetadataItem', () => {
|
||||
await act(async () => {
|
||||
const res = await result.current.deleteMetadataField({
|
||||
idToDelete: fieldMetadataItem.id,
|
||||
objectMetadataId,
|
||||
});
|
||||
jestExpectSuccessfulMetadataRequestResult(res);
|
||||
|
||||
@@ -264,7 +263,6 @@ describe('useFieldMetadataItem', () => {
|
||||
await act(async () => {
|
||||
const res = await result.current.deleteMetadataField({
|
||||
idToDelete: fieldRelationMetadataItem.id,
|
||||
objectMetadataId,
|
||||
});
|
||||
jestExpectSuccessfulMetadataRequestResult(res);
|
||||
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
import { MockedProvider } from '@apollo/client/testing/react';
|
||||
import { renderHook } from '@testing-library/react';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import { useFindManyObjectMetadataItems } from '@/object-metadata/hooks/useFindManyObjectMetadataItems';
|
||||
|
||||
import { SnackBarComponentInstanceContext } from '@/ui/feedback/snack-bar-manager/contexts/SnackBarComponentInstanceContext';
|
||||
import {
|
||||
query,
|
||||
responseData,
|
||||
} from '@/object-metadata/hooks/__mocks__/useFindManyObjectMetadataItems';
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query,
|
||||
},
|
||||
result: jest.fn(() => ({
|
||||
data: {
|
||||
objects: responseData,
|
||||
},
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
const Wrapper = ({ children }: { children: ReactNode }) => (
|
||||
<MockedProvider mocks={mocks}>
|
||||
<SnackBarComponentInstanceContext.Provider
|
||||
value={{ instanceId: 'snack-bar-manager' }}
|
||||
>
|
||||
{children}
|
||||
</SnackBarComponentInstanceContext.Provider>
|
||||
</MockedProvider>
|
||||
);
|
||||
|
||||
describe('useFindManyObjectMetadataItems', () => {
|
||||
it('should activateMetadataField', async () => {
|
||||
const { result } = renderHook(() => useFindManyObjectMetadataItems(), {
|
||||
wrapper: Wrapper,
|
||||
});
|
||||
|
||||
const { loading, error, objectMetadataItems } = result.current;
|
||||
|
||||
expect(loading).toBe(true);
|
||||
expect(error).toBeUndefined();
|
||||
expect(objectMetadataItems).toEqual([]);
|
||||
});
|
||||
});
|
||||
-12
@@ -5,25 +5,17 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
|
||||
export const useCreateOneFieldMetadataItem = () => {
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
|
||||
const [createOneFieldMetadataItemMutation] = useMutation(
|
||||
CreateOneFieldMetadataItemDocument,
|
||||
);
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
@@ -43,10 +35,6 @@ export const useCreateOneFieldMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
|
||||
await refreshCoreViewsByObjectMetadataId(input.objectMetadataId);
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
-17
@@ -5,21 +5,12 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useCreateOneObjectMetadataItem = () => {
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const [createOneObjectMetadataItemMutation] = useMutation(
|
||||
CreateOneObjectMetadataItemDocument,
|
||||
);
|
||||
@@ -41,14 +32,6 @@ export const useCreateOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
|
||||
if (isDefined(createdObjectMetadata.data?.createOneObject?.id)) {
|
||||
await refreshCoreViewsByObjectMetadataId(
|
||||
createdObjectMetadata.data.createOneObject.id,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response: createdObjectMetadata,
|
||||
|
||||
-12
@@ -3,7 +3,6 @@ import { DeleteOneFieldMetadataItemDocument } from '~/generated-metadata/graphql
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { recordIndexGroupAggregateFieldMetadataItemComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateFieldMetadataItemComponentState';
|
||||
import { recordIndexGroupAggregateOperationComponentState } from '@/object-record/record-index/states/recordIndexGroupAggregateOperationComponentState';
|
||||
@@ -11,7 +10,6 @@ import { AggregateOperations } from '@/object-record/record-table/constants/Aggr
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
@@ -21,11 +19,6 @@ export const useDeleteOneFieldMetadataItem = () => {
|
||||
DeleteOneFieldMetadataItemDocument,
|
||||
);
|
||||
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
@@ -56,10 +49,8 @@ export const useDeleteOneFieldMetadataItem = () => {
|
||||
|
||||
const deleteOneFieldMetadataItem = async ({
|
||||
idToDelete,
|
||||
objectMetadataId,
|
||||
}: {
|
||||
idToDelete: string;
|
||||
objectMetadataId: string;
|
||||
}): Promise<
|
||||
MetadataRequestResult<
|
||||
Awaited<ReturnType<typeof deleteOneFieldMetadataItemMutation>>
|
||||
@@ -75,9 +66,6 @@ export const useDeleteOneFieldMetadataItem = () => {
|
||||
// TODO: see if we can remove this lin altogether
|
||||
await resetRecordIndexKanbanAggregateOperation(idToDelete);
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
await refreshCoreViewsByObjectMetadataId(objectMetadataId);
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
-10
@@ -2,10 +2,8 @@ import { useMutation } from '@apollo/client/react';
|
||||
import { DeleteOneObjectMetadataItemDocument } from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRefreshAllCoreViews } from '@/views/hooks/useRefreshAllCoreViews';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
@@ -15,11 +13,6 @@ export const useDeleteOneObjectMetadataItem = () => {
|
||||
DeleteOneObjectMetadataItemDocument,
|
||||
);
|
||||
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
|
||||
const { refreshAllCoreViews } = useRefreshAllCoreViews();
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
@@ -37,9 +30,6 @@ export const useDeleteOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
await refreshAllCoreViews();
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
import { useQuery } from '@apollo/client/react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useSnackBarOnQueryError } from '@/apollo/hooks/useSnackBarOnQueryError';
|
||||
import {
|
||||
type ObjectMetadataItemsQuery,
|
||||
type ObjectMetadataItemsQueryVariables,
|
||||
} from '~/generated-metadata/graphql';
|
||||
import { enrichObjectMetadataItemsWithPermissions } from '@/object-metadata/utils/enrichObjectMetadataItemsWithPermissions';
|
||||
import { useObjectPermissions } from '@/object-record/hooks/useObjectPermissions';
|
||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
||||
|
||||
export const useFindManyObjectMetadataItems = ({
|
||||
skip,
|
||||
}: {
|
||||
skip?: boolean;
|
||||
} = {}) => {
|
||||
const { objectPermissionsByObjectMetadataId } = useObjectPermissions();
|
||||
|
||||
const { data, loading, error, refetch } = useQuery<
|
||||
ObjectMetadataItemsQuery,
|
||||
ObjectMetadataItemsQueryVariables
|
||||
>(FIND_MANY_OBJECT_METADATA_ITEMS, {
|
||||
skip,
|
||||
});
|
||||
|
||||
useSnackBarOnQueryError(error);
|
||||
|
||||
const objectMetadataItems = useMemo(() => {
|
||||
const objectMetadataItemsArray =
|
||||
mapPaginatedObjectMetadataItemsToObjectMetadataItems({
|
||||
pagedObjectMetadataItems: data,
|
||||
});
|
||||
|
||||
return enrichObjectMetadataItemsWithPermissions({
|
||||
objectMetadataItems: objectMetadataItemsArray,
|
||||
objectPermissionsByObjectMetadataId,
|
||||
});
|
||||
}, [data, objectPermissionsByObjectMetadataId]);
|
||||
|
||||
return {
|
||||
objectMetadataItems,
|
||||
loading,
|
||||
error,
|
||||
refetch,
|
||||
};
|
||||
};
|
||||
+1
-8
@@ -1,11 +1,8 @@
|
||||
import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { splitObjectMetadataItemWithRelated } from '@/metadata-store/utils/splitObjectMetadataItemWithRelated';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const useLoadMockedObjectMetadataItems = () => {
|
||||
const store = useStore();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const loadMockedObjectMetadataItems = useCallback(async () => {
|
||||
@@ -20,11 +17,7 @@ export const useLoadMockedObjectMetadataItems = () => {
|
||||
updateDraft('fieldMetadataItems', flatFields);
|
||||
updateDraft('indexMetadataItems', flatIndexes);
|
||||
applyChanges();
|
||||
|
||||
if (store.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
store.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
}
|
||||
}, [store, updateDraft, applyChanges]);
|
||||
}, [updateDraft, applyChanges]);
|
||||
|
||||
return {
|
||||
loadMockedObjectMetadataItems,
|
||||
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
import { isAppEffectRedirectEnabledState } from '@/app/states/isAppEffectRedirectEnabledState';
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { splitObjectMetadataItemWithRelated } from '@/metadata-store/utils/splitObjectMetadataItemWithRelated';
|
||||
import { FIND_MANY_OBJECT_METADATA_ITEMS } from '@/object-metadata/graphql/queries';
|
||||
import { mapPaginatedObjectMetadataItemsToObjectMetadataItems } from '@/object-metadata/utils/mapPaginatedObjectMetadataItemsToObjectMetadataItems';
|
||||
import { type FetchPolicy } from '@apollo/client';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { type ObjectMetadataItemsQuery } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useRefreshObjectMetadataItems = (
|
||||
fetchPolicy: FetchPolicy = 'network-only',
|
||||
) => {
|
||||
const store = useStore();
|
||||
const client = useApolloClient();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const refreshObjectMetadataItems = useCallback(async () => {
|
||||
const objectMetadataItemsResult =
|
||||
await client.query<ObjectMetadataItemsQuery>({
|
||||
query: FIND_MANY_OBJECT_METADATA_ITEMS,
|
||||
variables: {},
|
||||
fetchPolicy,
|
||||
});
|
||||
|
||||
const compositeObjects =
|
||||
mapPaginatedObjectMetadataItemsToObjectMetadataItems({
|
||||
pagedObjectMetadataItems: objectMetadataItemsResult.data,
|
||||
});
|
||||
|
||||
const { flatObjects, flatFields, flatIndexes } =
|
||||
splitObjectMetadataItemWithRelated(compositeObjects);
|
||||
|
||||
updateDraft('objectMetadataItems', flatObjects);
|
||||
updateDraft('fieldMetadataItems', flatFields);
|
||||
updateDraft('indexMetadataItems', flatIndexes);
|
||||
applyChanges();
|
||||
|
||||
if (store.get(isAppEffectRedirectEnabledState.atom) === false) {
|
||||
store.set(isAppEffectRedirectEnabledState.atom, true);
|
||||
}
|
||||
}, [client, fetchPolicy, store, updateDraft, applyChanges]);
|
||||
|
||||
return {
|
||||
refreshObjectMetadataItems,
|
||||
};
|
||||
};
|
||||
-11
@@ -5,11 +5,9 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { lastFieldMetadataItemUpdateState } from '@/object-metadata/states/lastFieldMetadataItemUpdateState';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
@@ -17,12 +15,6 @@ import { CrudOperationType } from 'twenty-shared/types';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
export const useUpdateOneFieldMetadataItem = () => {
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const [updateOneFieldMetadataItemMutation] = useMutation(
|
||||
UpdateOneFieldMetadataItemDocument,
|
||||
);
|
||||
@@ -66,9 +58,6 @@ export const useUpdateOneFieldMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
await refreshCoreViewsByObjectMetadataId(objectMetadataId);
|
||||
|
||||
setLastFieldMetadataItemUpdate({
|
||||
fieldMetadataItemId: fieldMetadataIdToUpdate,
|
||||
objectMetadataId,
|
||||
|
||||
-11
@@ -5,10 +5,8 @@ import {
|
||||
} from '~/generated-metadata/graphql';
|
||||
|
||||
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
|
||||
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { CombinedGraphQLErrors } from '@apollo/client/errors';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { CrudOperationType } from 'twenty-shared/types';
|
||||
@@ -19,12 +17,6 @@ export const useUpdateOneObjectMetadataItem = () => {
|
||||
UpdateOneObjectMetadataItemDocument,
|
||||
);
|
||||
|
||||
const { refreshObjectMetadataItems } =
|
||||
useRefreshObjectMetadataItems('network-only');
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { handleMetadataError } = useMetadataErrorHandler();
|
||||
const { enqueueErrorSnackBar } = useSnackBar();
|
||||
|
||||
@@ -47,9 +39,6 @@ export const useUpdateOneObjectMetadataItem = () => {
|
||||
},
|
||||
});
|
||||
|
||||
await refreshObjectMetadataItems();
|
||||
await refreshCoreViewsByObjectMetadataId(idToUpdate);
|
||||
|
||||
return {
|
||||
status: 'successful',
|
||||
response,
|
||||
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
import { objectMetadataItemsSelector } from '@/metadata-store/states/objectMetadataItemsSelector';
|
||||
import { flatObjectMetadataItemsSelector } from '@/object-metadata/states/flatObjectMetadataItemsSelector';
|
||||
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
|
||||
|
||||
export const activeObjectNameSingularsSelector = createAtomSelector<string[]>({
|
||||
key: 'activeObjectNameSingularsSelector',
|
||||
get: ({ get }) => {
|
||||
const flatObjects = get(objectMetadataItemsSelector);
|
||||
const flatObjects = get(flatObjectMetadataItemsSelector);
|
||||
|
||||
return flatObjects
|
||||
.filter((flatObject) => flatObject.isActive)
|
||||
|
||||
+2
-2
@@ -2,10 +2,10 @@ import { metadataStoreState } from '@/metadata-store/states/metadataStoreState';
|
||||
import { type FlatObjectMetadataItem } from '@/metadata-store/types/FlatObjectMetadataItem';
|
||||
import { createAtomSelector } from '@/ui/utilities/state/jotai/utils/createAtomSelector';
|
||||
|
||||
export const objectMetadataItemsSelector = createAtomSelector<
|
||||
export const flatObjectMetadataItemsSelector = createAtomSelector<
|
||||
FlatObjectMetadataItem[]
|
||||
>({
|
||||
key: 'objectMetadataItemsSelector',
|
||||
key: 'flatObjectMetadataItemsSelector',
|
||||
get: ({ get }) => {
|
||||
const storeItem = get(metadataStoreState, 'objectMetadataItems');
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { objectMetadataItemsSelector } from '@/metadata-store/states/objectMetadataItemsSelector';
|
||||
import { flatObjectMetadataItemsSelector } from '@/object-metadata/states/flatObjectMetadataItemsSelector';
|
||||
import { createAtomFamilySelector } from '@/ui/utilities/state/jotai/utils/createAtomFamilySelector';
|
||||
|
||||
export const isSystemObjectByNameSingularFamilySelector =
|
||||
@@ -7,7 +7,7 @@ export const isSystemObjectByNameSingularFamilySelector =
|
||||
get:
|
||||
(nameSingular: string) =>
|
||||
({ get }) => {
|
||||
const flatObjects = get(objectMetadataItemsSelector);
|
||||
const flatObjects = get(flatObjectMetadataItemsSelector);
|
||||
|
||||
return (
|
||||
flatObjects.find(
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { fieldMetadataItemsSelector } from '@/metadata-store/states/fieldMetadataItemsSelector';
|
||||
import { indexMetadataItemsSelector } from '@/metadata-store/states/indexMetadataItemsSelector';
|
||||
import { objectMetadataItemsSelector } from '@/metadata-store/states/objectMetadataItemsSelector';
|
||||
import { flatObjectMetadataItemsSelector } from '@/object-metadata/states/flatObjectMetadataItemsSelector';
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getNonReadableFieldMetadataIdsFromObjectPermissions } from '@/object-metadata/utils/getNonReadableFieldMetadataIdsFromObjectPermissions';
|
||||
import { getNonUpdatableFieldMetadataIdsFromObjectPermissions } from '@/object-metadata/utils/getNonUpdatableFieldMetadataIdsFromObjectPermissions';
|
||||
@@ -15,7 +15,7 @@ export const objectMetadataItemsWithFieldsSelector = createAtomSelector<
|
||||
>({
|
||||
key: 'objectMetadataItemsWithFieldsSelector',
|
||||
get: ({ get }) => {
|
||||
const flatObjects = get(objectMetadataItemsSelector);
|
||||
const flatObjects = get(flatObjectMetadataItemsSelector);
|
||||
const allFlatFields = get(fieldMetadataItemsSelector);
|
||||
const allFlatIndexes = get(indexMetadataItemsSelector);
|
||||
const currentUserWorkspace = get(currentUserWorkspaceState);
|
||||
|
||||
+2
-35
@@ -5,11 +5,10 @@ import { useRecordIndexContextOrThrow } from '@/object-record/record-index/conte
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { recordIndexViewTypeState } from '@/object-record/record-index/states/recordIndexViewTypeState';
|
||||
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { coreViewsSelector } from '@/views/states/selectors/coreViewsSelector';
|
||||
import { type GraphQLView } from '@/views/types/GraphQLView';
|
||||
import { ViewType, viewTypeIconMapping } from '@/views/types/ViewType';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { convertViewTypeToCore } from '@/views/utils/convertViewTypeToCore';
|
||||
import { useGetAvailableFieldsForCalendar } from '@/views/view-picker/hooks/useGetAvailableFieldsForCalendar';
|
||||
import { useGetAvailableFieldsToGroupRecordsBy } from '@/views/view-picker/hooks/useGetAvailableFieldsToGroupRecordsBy';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
@@ -39,7 +38,7 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}),
|
||||
);
|
||||
|
||||
const existingCoreViews = store.get(coreViewsState.atom);
|
||||
const existingCoreViews = store.get(coreViewsSelector.atom);
|
||||
|
||||
if (!isDefined(currentViewId)) {
|
||||
throw new Error('No view id found');
|
||||
@@ -74,16 +73,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
}
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
mainGroupByFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
await updateCurrentView(updateCurrentViewParams);
|
||||
return;
|
||||
}
|
||||
@@ -95,16 +84,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
updateCurrentViewParams.mainGroupByFieldMetadataId = null;
|
||||
await updateCurrentView(updateCurrentViewParams);
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
mainGroupByFieldMetadataId: null,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
case ViewType.Calendar: {
|
||||
@@ -115,18 +94,6 @@ export const useSetViewTypeFromLayoutOptionsMenu = () => {
|
||||
const calendarFieldMetadataId = availableFieldsForCalendar[0].id;
|
||||
|
||||
setRecordIndexViewType(viewType);
|
||||
store.set(coreViewsState.atom, [
|
||||
...existingCoreViews.filter(
|
||||
(coreView) => coreView.id !== currentView.id,
|
||||
),
|
||||
{
|
||||
...currentCoreView,
|
||||
mainGroupByFieldMetadataId: null,
|
||||
type: convertViewTypeToCore(viewType),
|
||||
calendarLayout: ViewCalendarLayout.MONTH,
|
||||
calendarFieldMetadataId,
|
||||
},
|
||||
]);
|
||||
|
||||
loadRecordIndexStates(
|
||||
{
|
||||
|
||||
+4
-7
@@ -4,12 +4,12 @@ import { useEffect, useMemo, useState } from 'react';
|
||||
import { type TaskGroups } from '@/activities/tasks/components/TaskGroups';
|
||||
import { contextStoreCurrentViewIdComponentState } from '@/context-store/states/contextStoreCurrentViewIdComponentState';
|
||||
import { CoreObjectNamePlural } from '@/object-metadata/types/CoreObjectNamePlural';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { RecordIndexContextProvider } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordTableComponentInstanceContext } from '@/object-record/record-table/states/context/RecordTableComponentInstanceContext';
|
||||
import { useSetAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useSetAtomComponentState';
|
||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
|
||||
import { MAIN_CONTEXT_STORE_INSTANCE_ID } from '@/context-store/constants/MainContextStoreInstanceId';
|
||||
import { RecordComponentInstanceContextsWrapper } from '@/object-record/components/RecordComponentInstanceContextsWrapper';
|
||||
@@ -18,9 +18,8 @@ import { RecordCalendarMonth } from '@/object-record/record-calendar/month/compo
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||
import { ContextStoreDecorator } from '~/testing/decorators/ContextStoreDecorator';
|
||||
import { IconsProviderDecorator } from '~/testing/decorators/IconsProviderDecorator';
|
||||
@@ -28,6 +27,7 @@ import { ObjectMetadataItemsDecorator } from '~/testing/decorators/ObjectMetadat
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
import { mockedCoreViews } from '~/testing/mock-data/generated/metadata/views/mock-views-data';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
import { setTestCoreViewsInMetadataStore } from '~/testing/utils/setTestCoreViewsInMetadataStore';
|
||||
|
||||
const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
title: 'Modules/ObjectRecord/RecordCalendar/Month',
|
||||
@@ -44,8 +44,6 @@ const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
instanceId,
|
||||
);
|
||||
|
||||
const setCoreViews = useSetAtomState(coreViewsState);
|
||||
|
||||
const mockCoreView = mockedCoreViews.find(
|
||||
(v) => v.name === 'All Companies',
|
||||
)!;
|
||||
@@ -73,12 +71,11 @@ const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setCoreViews([mockCoreView]);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [mockCoreView]);
|
||||
setContextStoreCurrentViewId(mockCoreView.id);
|
||||
setCurrentRecordFields(columns);
|
||||
setIsLoaded(true);
|
||||
}, [
|
||||
setCoreViews,
|
||||
setContextStoreCurrentViewId,
|
||||
setCurrentRecordFields,
|
||||
mockCoreView,
|
||||
|
||||
-6
@@ -6,7 +6,6 @@ import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/use
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { usePerformViewAPIUpdate } from '@/views/hooks/internal/usePerformViewAPIUpdate';
|
||||
import { useGetViewFromState } from '@/views/hooks/useGetViewFromState';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { type ViewGroup } from '@/views/types/ViewGroup';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { useStore } from 'jotai';
|
||||
@@ -29,8 +28,6 @@ export const useHandleRecordGroupField = () => {
|
||||
|
||||
const { performViewAPIUpdate } = usePerformViewAPIUpdate();
|
||||
const { loadRecordIndexStates } = useLoadRecordIndexStates();
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
@@ -121,8 +118,6 @@ export const useHandleRecordGroupField = () => {
|
||||
viewGroups: newViewGroupsList,
|
||||
objectMetadataItem,
|
||||
});
|
||||
|
||||
await refreshCoreViewsByObjectMetadataId(objectMetadataItem.id);
|
||||
},
|
||||
[
|
||||
currentViewIdCallbackState,
|
||||
@@ -130,7 +125,6 @@ export const useHandleRecordGroupField = () => {
|
||||
performViewAPIUpdate,
|
||||
setRecordGroupsFromViewGroups,
|
||||
objectMetadataItem,
|
||||
refreshCoreViewsByObjectMetadataId,
|
||||
loadRecordIndexStates,
|
||||
store,
|
||||
],
|
||||
|
||||
-8
@@ -1,4 +1,3 @@
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { RecordTableColumnAggregateFooterDropdownContext } from '@/object-record/record-table/record-table-footer/components/RecordTableColumnAggregateFooterDropdownContext';
|
||||
import { viewFieldAggregateOperationState } from '@/object-record/record-table/record-table-footer/states/viewFieldAggregateOperationState';
|
||||
import { type ExtendedAggregateOperations } from '@/object-record/record-table/types/ExtendedAggregateOperations';
|
||||
@@ -6,7 +5,6 @@ import { convertExtendedAggregateOperationToAggregateOperation } from '@/object-
|
||||
import { useAtomFamilyStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilyStateValue';
|
||||
import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import { useRefreshCoreViewsByObjectMetadataId } from '@/views/hooks/useRefreshCoreViewsByObjectMetadataId';
|
||||
import { useContext } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -20,10 +18,6 @@ export const useViewFieldAggregateOperation = () => {
|
||||
(viewField) => viewField.fieldMetadataId === fieldMetadataId,
|
||||
);
|
||||
|
||||
const { refreshCoreViewsByObjectMetadataId } =
|
||||
useRefreshCoreViewsByObjectMetadataId();
|
||||
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
const { performViewFieldAPIUpdate } = usePerformViewFieldAPIPersist();
|
||||
const updateViewFieldAggregateOperation = async (
|
||||
aggregateOperation: ExtendedAggregateOperations | null,
|
||||
@@ -48,8 +42,6 @@ export const useViewFieldAggregateOperation = () => {
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
refreshCoreViewsByObjectMetadataId(objectMetadataItem.id);
|
||||
};
|
||||
|
||||
const viewFieldAggregateOperation = useAtomFamilyStateValue(
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { type OnboardingStatus } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useOnboardingStatus = (): OnboardingStatus | null | undefined => {
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
const isLoggedIn = useIsLogged();
|
||||
return isLoggedIn ? currentUser?.onboardingStatus : undefined;
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
return hasAccessTokenPair ? currentUser?.onboardingStatus : undefined;
|
||||
};
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore';
|
||||
import { splitPageLayoutWithRelated } from '@/metadata-store/utils/splitPageLayoutWithRelated';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { recordPageLayoutsState } from '@/page-layout/states/recordPageLayoutsState';
|
||||
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
|
||||
import { transformPageLayout } from '@/page-layout/utils/transformPageLayout';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { type PageLayout as PageLayoutGenerated } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useApplyPageLayouts = () => {
|
||||
const store = useStore();
|
||||
const { updateDraft, applyChanges } = useMetadataStore();
|
||||
|
||||
const applyPageLayouts = useCallback(
|
||||
(pageLayouts: PageLayoutGenerated[]) => {
|
||||
const transformedPageLayouts = pageLayouts.map(transformPageLayout);
|
||||
|
||||
for (const pageLayout of transformedPageLayouts) {
|
||||
store.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayout.id,
|
||||
}),
|
||||
pageLayout,
|
||||
);
|
||||
store.set(
|
||||
pageLayoutCurrentLayoutsComponentState.atomFamily({
|
||||
instanceId: pageLayout.id,
|
||||
}),
|
||||
convertPageLayoutToTabLayouts(pageLayout),
|
||||
);
|
||||
}
|
||||
|
||||
store.set(recordPageLayoutsState.atom, transformedPageLayouts);
|
||||
|
||||
const { flatPageLayouts, flatPageLayoutTabs, flatPageLayoutWidgets } =
|
||||
splitPageLayoutWithRelated(transformedPageLayouts);
|
||||
|
||||
updateDraft('pageLayouts', flatPageLayouts);
|
||||
updateDraft('pageLayoutTabs', flatPageLayoutTabs);
|
||||
updateDraft('pageLayoutWidgets', flatPageLayoutWidgets);
|
||||
applyChanges();
|
||||
},
|
||||
[store, updateDraft, applyChanges],
|
||||
);
|
||||
|
||||
return {
|
||||
applyPageLayouts,
|
||||
};
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
import { useApplyPageLayouts } from '@/page-layout/hooks/useApplyPageLayouts';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useApolloClient } from '@apollo/client/react';
|
||||
import { FindAllPageLayoutsDocument } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useRefreshPageLayouts = () => {
|
||||
const client = useApolloClient();
|
||||
|
||||
const { applyPageLayouts } = useApplyPageLayouts();
|
||||
|
||||
const refreshPageLayouts = useCallback(async () => {
|
||||
const result = await client.query({
|
||||
query: FindAllPageLayoutsDocument,
|
||||
fetchPolicy: 'network-only',
|
||||
});
|
||||
|
||||
if (!isDefined(result.data?.getPageLayouts)) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyPageLayouts(result.data.getPageLayouts);
|
||||
}, [client, applyPageLayouts]);
|
||||
|
||||
return {
|
||||
refreshPageLayouts,
|
||||
};
|
||||
};
|
||||
@@ -6,7 +6,6 @@ import { fieldsWidgetGroupsPersistedComponentState } from '@/page-layout/states/
|
||||
import { fieldsWidgetUngroupedFieldsDraftComponentState } from '@/page-layout/states/fieldsWidgetUngroupedFieldsDraftComponentState';
|
||||
import { fieldsWidgetUngroupedFieldsPersistedComponentState } from '@/page-layout/states/fieldsWidgetUngroupedFieldsPersistedComponentState';
|
||||
import { useAtomComponentStateCallbackState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateCallbackState';
|
||||
import { useRefreshAllCoreViews } from '@/views/hooks/useRefreshAllCoreViews';
|
||||
import { useMutation } from '@apollo/client/react';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
@@ -82,8 +81,6 @@ export const useSaveFieldsWidgetGroups = ({
|
||||
{ input: UpsertFieldsWidgetInput }
|
||||
>(UPSERT_FIELDS_WIDGET);
|
||||
|
||||
const { refreshAllCoreViews } = useRefreshAllCoreViews();
|
||||
|
||||
const store = useStore();
|
||||
|
||||
const saveFieldsWidgetGroups = useCallback(async () => {
|
||||
@@ -165,8 +162,6 @@ export const useSaveFieldsWidgetGroups = ({
|
||||
);
|
||||
store.set(fieldsWidgetEditorModePersistedState, allEditorModes);
|
||||
|
||||
await refreshAllCoreViews();
|
||||
|
||||
return { status: 'successful' as const };
|
||||
}, [
|
||||
fieldsWidgetGroupsDraftState,
|
||||
@@ -176,7 +171,6 @@ export const useSaveFieldsWidgetGroups = ({
|
||||
fieldsWidgetEditorModeDraftState,
|
||||
fieldsWidgetEditorModePersistedState,
|
||||
upsertFieldsWidgetMutation,
|
||||
refreshAllCoreViews,
|
||||
store,
|
||||
]);
|
||||
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
|
||||
@@ -37,7 +37,7 @@ const meta: Meta<typeof DashboardWidgetPlaceholder> = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
|
||||
+15
-15
@@ -8,7 +8,7 @@ import { CatalogDecorator, type CatalogStory } from 'twenty-ui/testing';
|
||||
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreClientContext';
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
@@ -281,7 +281,7 @@ export const WithNumberChart: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -368,7 +368,7 @@ export const WithGaugeChart: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -459,7 +459,7 @@ export const WithBarChart: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -553,7 +553,7 @@ export const SmallWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -651,7 +651,7 @@ export const MediumWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -749,7 +749,7 @@ export const LargeWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -843,7 +843,7 @@ export const WideWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -941,7 +941,7 @@ export const TallWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(widget);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
@@ -1035,7 +1035,7 @@ export const WithManyToOneRelationFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
@@ -1154,7 +1154,7 @@ export const WithOneToManyRelationFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
@@ -1265,7 +1265,7 @@ export const OneToManyRelationFieldWidgetWithSeeAllButton: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
@@ -1403,7 +1403,7 @@ export const OnMobile: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
@@ -1501,7 +1501,7 @@ export const InSidePanel: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
PageLayoutType.RECORD_PAGE,
|
||||
@@ -1660,7 +1660,7 @@ export const Catalog: CatalogStory<Story, typeof WidgetRenderer> = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
|
||||
if (state === 'hover') {
|
||||
jotaiStore.set(
|
||||
|
||||
+18
-18
@@ -5,7 +5,7 @@ import { MemoryRouter } from 'react-router-dom';
|
||||
import { expect, userEvent, waitFor, within } from 'storybook/test';
|
||||
|
||||
import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreClientContext';
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
@@ -360,7 +360,7 @@ export const TextFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -454,7 +454,7 @@ export const AddressFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -551,7 +551,7 @@ export const NumberFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -645,7 +645,7 @@ export const LinkFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -739,7 +739,7 @@ export const ManyToOneRelationFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -843,7 +843,7 @@ export const OneToManyRelationFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -939,7 +939,7 @@ export const BooleanFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -1032,7 +1032,7 @@ export const CurrencyFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -1125,7 +1125,7 @@ export const EmailsFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
personObjectMetadataItem.id,
|
||||
@@ -1219,7 +1219,7 @@ export const PhonesFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
personObjectMetadataItem.id,
|
||||
@@ -1313,7 +1313,7 @@ export const SelectFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
opportunityObjectMetadataItem.id,
|
||||
@@ -1408,7 +1408,7 @@ export const MultiSelectFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -1506,7 +1506,7 @@ export const TimelineActivityRelationFieldWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
timelineActivityObjectMetadataItem.id,
|
||||
@@ -1605,7 +1605,7 @@ export const ManyToOneRelationCardWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -1717,7 +1717,7 @@ export const OneToManyRelationCardWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
@@ -1812,7 +1812,7 @@ export const TimelineActivityRelationCardWidget: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
timelineActivityObjectMetadataItem.id,
|
||||
@@ -1973,7 +1973,7 @@ export const OneToManyRelationCardWidgetWithProgressiveLoading: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
const pageLayoutData = createPageLayoutWithWidget(
|
||||
widget,
|
||||
companyObjectMetadataItem.id,
|
||||
|
||||
+77
-129
@@ -4,10 +4,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { expect, waitFor, within } from 'storybook/test';
|
||||
|
||||
import { isAppMetadataReadyState } from '@/metadata-store/states/isAppMetadataReadyState';
|
||||
import { isMinimalMetadataReadyState } from '@/metadata-store/states/isMinimalMetadataReadyState';
|
||||
import { ApolloCoreClientContext } from '@/object-metadata/contexts/ApolloCoreClientContext';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
import { recordStoreFamilyState } from '@/object-record/record-store/states/recordStoreFamilyState';
|
||||
import { type ObjectRecord } from '@/object-record/types/ObjectRecord';
|
||||
import { PageLayoutContentProvider } from '@/page-layout/contexts/PageLayoutContentContext';
|
||||
@@ -23,8 +21,8 @@ import { FieldsWidget } from '@/page-layout/widgets/fields/components/FieldsWidg
|
||||
import { WidgetComponentInstanceContext } from '@/page-layout/widgets/states/contexts/WidgetComponentInstanceContext';
|
||||
import { LayoutRenderingProvider } from '@/ui/layout/contexts/LayoutRenderingContext';
|
||||
import { jotaiStore } from '@/ui/utilities/state/jotai/jotaiStore';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { type CoreViewWithRelations } from '@/views/types/CoreViewWithRelations';
|
||||
import { CoreObjectNameSingular } from 'twenty-shared/types';
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import {
|
||||
ViewOpenRecordIn as CoreViewOpenRecordIn,
|
||||
@@ -41,6 +39,8 @@ import { getJestMetadataAndApolloMocksWrapper } from '~/testing/jest/getJestMeta
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
import { getMockFieldMetadataItemOrThrow } from '~/testing/utils/getMockFieldMetadataItemOrThrow';
|
||||
import { getMockObjectMetadataItemOrThrow } from '~/testing/utils/getMockObjectMetadataItemOrThrow';
|
||||
import { setTestCoreViewsInMetadataStore } from '~/testing/utils/setTestCoreViewsInMetadataStore';
|
||||
import { setTestObjectMetadataItemsInMetadataStore } from '~/testing/utils/setTestObjectMetadataItemsInMetadataStore';
|
||||
|
||||
const companyObjectMetadataItem = getMockObjectMetadataItemOrThrow(
|
||||
CoreObjectNameSingular.Company,
|
||||
@@ -206,6 +206,39 @@ const createCoreView = (
|
||||
...overrides,
|
||||
});
|
||||
|
||||
const createViewField = (
|
||||
id: string,
|
||||
fieldMetadataId: string,
|
||||
position: number,
|
||||
viewFieldGroupId?: string,
|
||||
) => ({
|
||||
id,
|
||||
fieldMetadataId,
|
||||
position,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
...(viewFieldGroupId !== undefined && { viewFieldGroupId }),
|
||||
});
|
||||
|
||||
const createViewFieldGroup = (
|
||||
id: string,
|
||||
name: string,
|
||||
position: number,
|
||||
viewFields: ReturnType<typeof createViewField>[],
|
||||
isVisible = true,
|
||||
) => ({
|
||||
id,
|
||||
name,
|
||||
position,
|
||||
isVisible,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
viewFields,
|
||||
});
|
||||
|
||||
const meta: Meta<typeof FieldsWidget> = {
|
||||
title: 'Modules/PageLayout/Widgets/FieldsWidget',
|
||||
component: FieldsWidget,
|
||||
@@ -229,88 +262,38 @@ type Story = StoryObj<typeof FieldsWidget>;
|
||||
|
||||
export const WithViewFieldGroups: Story = {
|
||||
render: () => {
|
||||
const contactInfoFields = [
|
||||
createViewField('vf-name', nameField.id, 0, 'group-contact-info'),
|
||||
createViewField('vf-address', addressField.id, 1, 'group-contact-info'),
|
||||
createViewField('vf-linkedin', linkedinField.id, 2, 'group-contact-info'),
|
||||
];
|
||||
|
||||
const businessFields = [
|
||||
createViewField('vf-employees', employeesField.id, 0, 'group-business'),
|
||||
createViewField(
|
||||
'vf-arr',
|
||||
annualRecurringRevenueField.id,
|
||||
1,
|
||||
'group-business',
|
||||
),
|
||||
createViewField(
|
||||
'vf-icp',
|
||||
idealCustomerProfileField.id,
|
||||
2,
|
||||
'group-business',
|
||||
),
|
||||
];
|
||||
|
||||
const coreView = createCoreView({
|
||||
viewFields: [...contactInfoFields, ...businessFields],
|
||||
viewFieldGroups: [
|
||||
{
|
||||
id: 'group-contact-info',
|
||||
name: 'Contact Info',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
viewFields: [
|
||||
{
|
||||
id: 'vf-name',
|
||||
fieldMetadataId: nameField.id,
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-address',
|
||||
fieldMetadataId: addressField.id,
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-linkedin',
|
||||
fieldMetadataId: linkedinField.id,
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'group-business',
|
||||
name: 'Business',
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
viewFields: [
|
||||
{
|
||||
id: 'vf-employees',
|
||||
fieldMetadataId: employeesField.id,
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-arr',
|
||||
fieldMetadataId: annualRecurringRevenueField.id,
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-icp',
|
||||
fieldMetadataId: idealCustomerProfileField.id,
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
],
|
||||
},
|
||||
createViewFieldGroup(
|
||||
'group-contact-info',
|
||||
'Contact Info',
|
||||
0,
|
||||
contactInfoFields,
|
||||
),
|
||||
createViewFieldGroup('group-business', 'Business', 1, businessFields),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -325,8 +308,8 @@ export const WithViewFieldGroups: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(coreViewsState.atom, [coreView]);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [coreView]);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
@@ -394,36 +377,9 @@ export const WithInlineViewFields: Story = {
|
||||
render: () => {
|
||||
const coreView = createCoreView({
|
||||
viewFields: [
|
||||
{
|
||||
id: 'vf-name',
|
||||
fieldMetadataId: nameField.id,
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-employees',
|
||||
fieldMetadataId: employeesField.id,
|
||||
position: 1,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
{
|
||||
id: 'vf-address',
|
||||
fieldMetadataId: addressField.id,
|
||||
position: 2,
|
||||
isVisible: true,
|
||||
size: 200,
|
||||
aggregateOperation: null,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
},
|
||||
createViewField('vf-name', nameField.id, 0),
|
||||
createViewField('vf-employees', employeesField.id, 1),
|
||||
createViewField('vf-address', addressField.id, 2),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -438,8 +394,8 @@ export const WithInlineViewFields: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(coreViewsState.atom, [coreView]);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [coreView]);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
@@ -507,15 +463,7 @@ export const Empty: Story = {
|
||||
render: () => {
|
||||
const coreView = createCoreView({
|
||||
viewFieldGroups: [
|
||||
{
|
||||
id: 'group-empty',
|
||||
name: 'Empty Group',
|
||||
position: 0,
|
||||
isVisible: false,
|
||||
isOverridden: false,
|
||||
viewId: FIELDS_VIEW_ID,
|
||||
viewFields: [],
|
||||
},
|
||||
createViewFieldGroup('group-empty', 'Empty Group', 0, [], false),
|
||||
],
|
||||
});
|
||||
|
||||
@@ -530,8 +478,8 @@ export const Empty: Story = {
|
||||
jotaiStore,
|
||||
generatedMockObjectMetadataItems,
|
||||
);
|
||||
jotaiStore.set(isAppMetadataReadyState.atom, true);
|
||||
jotaiStore.set(coreViewsState.atom, [coreView]);
|
||||
jotaiStore.set(isMinimalMetadataReadyState.atom, true);
|
||||
setTestCoreViewsInMetadataStore(jotaiStore, [coreView]);
|
||||
jotaiStore.set(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: PAGE_LAYOUT_TEST_INSTANCE_ID,
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import { type ReactNode } from 'react';
|
||||
@@ -21,13 +21,13 @@ export const SettingsProtectedRouteWrapper = ({
|
||||
settingsPermission,
|
||||
requiredFeatureFlag,
|
||||
}: SettingsProtectedRouteWrapperProps) => {
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const hasPermission = useHasPermissionFlag(settingsPermission);
|
||||
const requiredFeatureFlagEnabled = useIsFeatureEnabled(
|
||||
requiredFeatureFlag || null,
|
||||
);
|
||||
|
||||
if (!isLoggedIn) {
|
||||
if (!hasAccessTokenPair) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
-1
@@ -262,7 +262,6 @@ export const SettingsObjectFieldItemTableRow = ({
|
||||
onDelete={() =>
|
||||
deleteOneFieldMetadataItem({
|
||||
idToDelete: fieldMetadataItem.id,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
||||
-1
@@ -242,7 +242,6 @@ export const SettingsObjectRelationItemTableRow = ({
|
||||
onDelete={() =>
|
||||
deleteOneFieldMetadataItem({
|
||||
idToDelete: fieldMetadataItem.id,
|
||||
objectMetadataId: objectMetadataItem.id,
|
||||
})
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems';
|
||||
import { SaveAndCancelButtons } from '@/settings/components/SaveAndCancelButtons/SaveAndCancelButtons';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsRoleAssignment } from '@/settings/roles/role-assignment/components/SettingsRoleAssignment';
|
||||
@@ -35,7 +34,6 @@ type SettingsRoleProps = {
|
||||
};
|
||||
|
||||
export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
||||
const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems();
|
||||
const activeTabId = useAtomComponentStateValue(
|
||||
activeTabIdComponentState,
|
||||
SETTINGS_ROLE_DETAIL_TABS.COMPONENT_INSTANCE_ID + '-' + roleId,
|
||||
@@ -126,7 +124,6 @@ export const SettingsRole = ({ roleId, isCreateMode }: SettingsRoleProps) => {
|
||||
try {
|
||||
await saveDraftRoleToDB();
|
||||
await loadCurrentUser();
|
||||
await refreshObjectMetadataItems();
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
|
||||
+1
@@ -93,6 +93,7 @@ export const SignInBackgroundMockContainer = () => {
|
||||
<ViewBar
|
||||
viewBarId={viewBarId}
|
||||
optionsDropdownButton={<></>}
|
||||
isReadOnly
|
||||
/>
|
||||
|
||||
<RecordTableWithWrappers
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { tokenPairState } from '@/auth/states/tokenPairState';
|
||||
import { useHandleSseClientConnectionRetry } from '@/sse-db-event/hooks/useHandleSseClientConnectionRetry';
|
||||
import { activeQueryListenersState } from '@/sse-db-event/states/activeQueryListenersState';
|
||||
@@ -14,7 +14,7 @@ import { useStore } from 'jotai';
|
||||
|
||||
export const SSEClientEffect = () => {
|
||||
const store = useStore();
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const [sseClient, setSseClient] = useAtomState(sseClientState);
|
||||
const tokenPair = useAtomStateValue(tokenPairState);
|
||||
|
||||
@@ -32,7 +32,7 @@ export const SSEClientEffect = () => {
|
||||
useHandleSseClientConnectionRetry();
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoggedIn && !isDefined(sseClient) && isDefined(tokenPair)) {
|
||||
if (hasAccessTokenPair && !isDefined(sseClient) && isDefined(tokenPair)) {
|
||||
const token = tokenPair?.accessOrWorkspaceAgnosticToken?.token;
|
||||
|
||||
const newSseClient = createClient({
|
||||
@@ -52,7 +52,7 @@ export const SSEClientEffect = () => {
|
||||
}
|
||||
}, [
|
||||
handleSSEClientConnected,
|
||||
isLoggedIn,
|
||||
hasAccessTokenPair,
|
||||
setSseClient,
|
||||
sseClient,
|
||||
tokenPair,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useIsLogged } from '@/auth/hooks/useIsLogged';
|
||||
import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState';
|
||||
import { useTriggerEventStreamCreation } from '@/sse-db-event/hooks/useTriggerEventStreamCreation';
|
||||
@@ -27,7 +27,7 @@ export const SSEEventStreamEffect = () => {
|
||||
isDestroyingEventStreamState,
|
||||
);
|
||||
|
||||
const isLoggedIn = useIsLogged();
|
||||
const hasAccessTokenPair = useHasAccessTokenPair();
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
|
||||
const { triggerEventStreamCreation } = useTriggerEventStreamCreation();
|
||||
@@ -39,7 +39,7 @@ export const SSEEventStreamEffect = () => {
|
||||
|
||||
const willCreateEventStream =
|
||||
isSseClientAvailable &&
|
||||
isLoggedIn &&
|
||||
hasAccessTokenPair &&
|
||||
isDefined(currentUser) &&
|
||||
currentUser.onboardingStatus === OnboardingStatus.COMPLETED &&
|
||||
!shouldDestroyEventStream &&
|
||||
@@ -59,7 +59,7 @@ export const SSEEventStreamEffect = () => {
|
||||
}, [
|
||||
isCreatingSseEventStream,
|
||||
triggerEventStreamCreation,
|
||||
isLoggedIn,
|
||||
hasAccessTokenPair,
|
||||
currentUser,
|
||||
isDestroyingEventStream,
|
||||
triggerEventStreamDestroy,
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
import { FieldMetadataSSEEffect } from '@/metadata-store/effect-components/FieldMetadataSSEEffect';
|
||||
import { NavigationMenuItemSSEEffect } from '@/metadata-store/effect-components/NavigationMenuItemSSEEffect';
|
||||
import { ObjectMetadataItemSSEEffect } from '@/metadata-store/effect-components/ObjectMetadataItemSSEEffect';
|
||||
import { PageLayoutSSEEffect } from '@/metadata-store/effect-components/PageLayoutSSEEffect';
|
||||
import { PageLayoutTabSSEEffect } from '@/metadata-store/effect-components/PageLayoutTabSSEEffect';
|
||||
import { PageLayoutWidgetSSEEffect } from '@/metadata-store/effect-components/PageLayoutWidgetSSEEffect';
|
||||
import { ViewFieldSSEEffect } from '@/metadata-store/effect-components/ViewFieldSSEEffect';
|
||||
import { ViewFilterGroupSSEEffect } from '@/metadata-store/effect-components/ViewFilterGroupSSEEffect';
|
||||
import { ViewFilterSSEEffect } from '@/metadata-store/effect-components/ViewFilterSSEEffect';
|
||||
import { ViewSortSSEEffect } from '@/metadata-store/effect-components/ViewSortSSEEffect';
|
||||
import { ViewSSEEffect } from '@/metadata-store/effect-components/ViewSSEEffect';
|
||||
import { MetadataStoreSSEEffect } from '@/metadata-store/effect-components/MetadataStoreSSEEffect';
|
||||
import { SSEClientEffect } from '@/sse-db-event/components/SSEClientEffect';
|
||||
import { SSEEventStreamEffect } from '@/sse-db-event/components/SSEEventStreamEffect';
|
||||
import { SSEQuerySubscribeEffect } from '@/sse-db-event/components/SSEQuerySubscribeEffect';
|
||||
@@ -24,17 +14,7 @@ export const SSEProvider = ({ children }: SSEProviderProps) => {
|
||||
<SSEClientEffect />
|
||||
<SSEEventStreamEffect />
|
||||
<SSEQuerySubscribeEffect />
|
||||
<NavigationMenuItemSSEEffect />
|
||||
<FieldMetadataSSEEffect />
|
||||
<ObjectMetadataItemSSEEffect />
|
||||
<PageLayoutSSEEffect />
|
||||
<PageLayoutTabSSEEffect />
|
||||
<PageLayoutWidgetSSEEffect />
|
||||
<ViewSSEEffect />
|
||||
<ViewFieldSSEEffect />
|
||||
<ViewFilterSSEEffect />
|
||||
<ViewSortSSEEffect />
|
||||
<ViewFilterGroupSSEEffect />
|
||||
<MetadataStoreSSEEffect />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user