From 660536d6bb66276cd09bb9315faa65e1d3a25f92 Mon Sep 17 00:00:00 2001 From: Charles Bochet Date: Thu, 12 Mar 2026 13:15:05 +0100 Subject: [PATCH] Fix onboarding flow: workspace creation modal and invite team skip (#18577) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - **Fix create-profile modal not showing after workspace creation**: After activating a workspace, `CreateWorkspace.onSubmit` called `refreshObjectMetadataItems()` which only updated the `objectMetadataItemsState` atom but never marked the metadata store as ready (`metadataStoreState` stayed at `'empty'`). Since `MetadataGater` excludes `CreateWorkspace` but not `CreateProfile` from its loading check, navigating to `/create/profile` triggered the skeleton loader instead of the modal. The fix adds the full metadata pipeline after refresh — `updateDraft('objectMetadataItems')` + `applyChanges()` for objects, and `fetchAndLoadIndexViews()` for views — so `isAppMetadataReady` is `true` before navigation. - **Fix invite-team "Skip" not persisting to server**: Clicking "Skip" on the invite-team page called `setNextOnboardingStatus()` which only updated the local Jotai atom. The early return for empty emails bypassed `sendInvitation`, so the server never cleared the `ONBOARDING_INVITE_TEAM_PENDING` user var. On page refresh, `GetCurrentUser` returned `INVITE_TEAM` and the user was stuck. The fix removes the early return so `sendInvitation({ emails: [] })` always runs — the server handles empty arrays fine and clears the pending flag. --- .../src/pages/onboarding/CreateWorkspace.tsx | 19 ++++++++++++++++++- .../src/pages/onboarding/InviteTeam.tsx | 6 +----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx index f85e21497c..2fefd9ca75 100644 --- a/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx +++ b/packages/twenty-front/src/pages/onboarding/CreateWorkspace.tsx @@ -9,7 +9,10 @@ import { Logo } from '@/auth/components/Logo'; import { SubTitle } from '@/auth/components/SubTitle'; import { Title } from '@/auth/components/Title'; import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState'; +import { useFetchAndLoadIndexViews } from '@/metadata-store/hooks/useFetchAndLoadIndexViews'; +import { useMetadataStore } from '@/metadata-store/hooks/useMetadataStore'; import { useRefreshObjectMetadataItems } from '@/object-metadata/hooks/useRefreshObjectMetadataItems'; +import { objectMetadataItemsState } from '@/object-metadata/states/objectMetadataItemsState'; import { useSetNextOnboardingStatus } from '@/onboarding/hooks/useSetNextOnboardingStatus'; import { WorkspaceLogoUploader } from '@/settings/workspace/components/WorkspaceLogoUploader'; import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; @@ -19,6 +22,7 @@ import { useLoadCurrentUser } from '@/users/hooks/useLoadCurrentUser'; import { ApolloError } from '@apollo/client'; import { Trans, useLingui } from '@lingui/react/macro'; import { isNonEmptyString } from '@sniptt/guards'; +import { useStore } from 'jotai'; import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; import { isDefined } from 'twenty-shared/utils'; import { H2Title } from 'twenty-ui/display'; @@ -68,6 +72,9 @@ export const CreateWorkspace = () => { const { enqueueErrorSnackBar } = useSnackBar(); const setNextOnboardingStatus = useSetNextOnboardingStatus(); const { refreshObjectMetadataItems } = useRefreshObjectMetadataItems(); + const { updateDraft, applyChanges } = useMetadataStore(); + const { fetchAndLoadIndexViews } = useFetchAndLoadIndexViews(); + const store = useStore(); const { loadCurrentUser } = useLoadCurrentUser(); const [activateWorkspace] = useActivateWorkspaceMutation(); @@ -117,12 +124,18 @@ export const CreateWorkspace = () => { }, }, }); - if (isDefined(result.errors)) { throw result.errors ?? new Error(t`Unknown error`); } await refreshObjectMetadataItems(); + + const loadedObjects = store.get(objectMetadataItemsState.atom); + updateDraft('objectMetadataItems', loadedObjects); + applyChanges(); + + await fetchAndLoadIndexViews(); + await loadCurrentUser(); setNextOnboardingStatus(); } catch (error: any) { @@ -138,6 +151,10 @@ export const CreateWorkspace = () => { enqueueErrorSnackBar, loadCurrentUser, refreshObjectMetadataItems, + updateDraft, + applyChanges, + store, + fetchAndLoadIndexViews, setNextOnboardingStatus, t, ], diff --git a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx index f3fa2cdd43..45d074df22 100644 --- a/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx +++ b/packages/twenty-front/src/pages/onboarding/InviteTeam.tsx @@ -131,16 +131,12 @@ export const InviteTeam = () => { ), ); - if (emails.length === 0) { - setNextOnboardingStatus(); - return; - } - const result = await sendInvitation({ emails }); if (isDefined(result.errors)) { throw result.errors; } + if (emails.length > 0) { enqueueSuccessSnackBar({ message: t`Invite link sent to email addresses`,