Replace sign-in mocked metadata with hardcoded BackgroundMock#20308
Replace sign-in mocked metadata with hardcoded BackgroundMock#20308charlesBochet merged 10 commits intomainfrom
Conversation
When the user is logged out, the sign-in/auth modal is rendered on top of a sample table. Until now, this was achieved by loading a full set of mocked object/field/view metadata into the runtime metadata store and then rendering the real RecordTable + AppNavigationDrawer behind the modal. This added non-trivial bundle weight, runtime cost, and exposed plenty of surface area where logged-out users could trigger metadata-driven code paths. This PR removes that flow entirely. The background is now a small, self-contained `BackgroundMock` component tree that does not consume any metadata state: - `BackgroundMockPage` / `BackgroundMockViewBar` / `BackgroundMockTable` / `BackgroundMockTableRow` render a hardcoded "Companies" table. - `BackgroundMockNavigationDrawer` renders a hardcoded sidebar with the standard People / Companies / Opportunities / Tasks / Notes items. - `MinimalMetadataLoadEffect` no longer calls `loadMockedMetadataAtomic` for unauthenticated users; `IsMinimalMetadataReadyEffect` now reports ready immediately when there is no access token pair. - `MainContextStoreProvider`, `useRecordIndexTableQuery`, and `useTriggerInitialRecordTableDataLoad` lose their `showAuthModal` branches since the real RecordTable is no longer mounted behind the modal. `useLoadMockedMetadata` and `preloadMockedMetadata` are kept for Storybook decorators, which still rely on the mocked metadata fixtures.
There was a problem hiding this comment.
Pull request overview
This PR replaces the logged-out “auth modal over a live-looking app” background from a metadata-driven mock (mocked metadata + real RecordTable/navigation components) to a lightweight, hardcoded BackgroundMock component tree that does not depend on runtime metadata.
Changes:
- Introduces a new hardcoded sign-in background mock (page, view bar, table, navigation drawer) backed by simple constants.
- Removes unauthenticated mocked-metadata loading and related
showAuthModalbranches in record-table/metadata/context-store flows. - Updates
DefaultLayoutandNotFoundto render the newBackgroundMockPage/BackgroundMockNavigationDrawer.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/twenty-front/src/pages/not-found/NotFound.tsx | Swaps old sign-in background mock page lazy import for BackgroundMockPage. |
| packages/twenty-front/src/modules/ui/layout/page/components/DefaultLayout.tsx | Uses new BackgroundMockPage + BackgroundMockNavigationDrawer when showAuthModal is true. |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockViewFields.ts | Removes metadata-backed mock view fields fixture. |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockCompanies.ts | Removes large GraphQL-shaped mock company fixture and conversion logic. |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/SignInBackgroundMockColumnDefinitions.ts | Removes metadata-derived mock column definitions. |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/BackgroundMockNavigationItems.ts | Adds hardcoded navigation item list (label/icon/color). |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/BackgroundMockCompanies.ts | Adds simplified hardcoded company dataset for the background table. |
| packages/twenty-front/src/modules/sign-in-background-mock/constants/BackgroundMockColumns.ts | Adds simplified hardcoded column config (label/iconName/width). |
| packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainerEffect.tsx | Removes metadata-store wiring effect previously required by real RecordTable. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/SignInBackgroundMockContainer.tsx | Removes the prior container that mounted real record-table/view-bar infrastructure. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockViewBar.tsx | Adds a lightweight, hardcoded view bar for the mock page. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockTableRow.tsx | Adds a lightweight row renderer for the mock table. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockTable.tsx | Adds a lightweight mock table (header/body/footer) that renders without metadata. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockPage.tsx | Replaces prior mock container with the new hardcoded view bar + table. |
| packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockNavigationDrawer.tsx | Replaces metadata-driven workspace section with hardcoded navigation items. |
| packages/twenty-front/src/modules/object-record/record-table/virtualization/hooks/useTriggerInitialRecordTableDataLoad.ts | Removes showAuthModal path that injected mock records into the real record table. |
| packages/twenty-front/src/modules/object-record/record-index/hooks/useRecordIndexTableQuery.ts | Removes showAuthModal branch and always uses the real query hook. |
| packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx | Stops loading mocked metadata for unauthenticated users; loads minimal metadata only when authenticated + active/suspended workspace. |
| packages/twenty-front/src/modules/metadata-store/effect-components/IsMinimalMetadataReadyEffect.tsx | Marks minimal metadata ready immediately when logged out so loaders don’t hang. |
| packages/twenty-front/src/modules/context-store/components/MainContextStoreProvider.tsx | Removes showAuthModal-specific object selection and context-store computation gating. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const findColumn = (label: string) => { | ||
| const column = BACKGROUND_MOCK_COLUMNS.find((c) => c.label === label); | ||
| if (column === undefined) { | ||
| throw new Error(`Background mock column "${label}" is not configured`); | ||
| } | ||
| return column; | ||
| }; | ||
|
|
| const formatNumber = (value: number) => | ||
| value.toLocaleString('en-US').replace(/,/g, ','); |
| <StyledFooterRow> | ||
| <IconPlus size={theme.icon.size.sm} stroke={theme.icon.stroke.sm} /> | ||
| Add New | ||
| </StyledFooterRow> | ||
| <StyledFooterRow> | ||
| Calculate | ||
| <IconChevronDown | ||
| size={theme.icon.size.sm} | ||
| stroke={theme.icon.stroke.sm} | ||
| /> | ||
| </StyledFooterRow> |
| <StyledCell width={opportunitiesColumn.width}> | ||
| {company.opportunitiesCount > 0 && ( | ||
| <StyledOpportunityChip>Untitled</StyledOpportunityChip> | ||
| )} |
|
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:8955 This environment will automatically shut down after 5 hours. |
…anies layout Switch BackgroundMockTableRow to render Avatar + Chip (with twenty-icons logos), TopBar for the view bar, Button for the page header action, and expand the navigation drawer with the full set of workspace and Other sections so the logged-out background mirrors the loaded Companies page without forking custom styles.
There was a problem hiding this comment.
1 issue found across 23 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx">
<violation number="1" location="packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx:33">
P1: The version-only dedup guard can skip required metadata reload after transitioning from unauthenticated back to authenticated in the same SPA session.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
| } | ||
|
|
||
| if (!versionChanged && lastMetadataLoadData.state === desiredLoadState) { | ||
| if (metadataLoadedVersion === lastLoadedVersion) { |
There was a problem hiding this comment.
P1: The version-only dedup guard can skip required metadata reload after transitioning from unauthenticated back to authenticated in the same SPA session.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-front/src/modules/metadata-store/effect-components/MinimalMetadataLoadEffect.tsx, line 33:
<comment>The version-only dedup guard can skip required metadata reload after transitioning from unauthenticated back to authenticated in the same SPA session.</comment>
<file context>
@@ -2,70 +2,41 @@ import { useHasAccessTokenPair } from '@/auth/hooks/useHasAccessTokenPair';
+ }
- if (!versionChanged && lastMetadataLoadData.state === desiredLoadState) {
+ if (metadataLoadedVersion === lastLoadedVersion) {
return;
}
</file context>
- Replace custom checkbox div with twenty-ui Checkbox component (gives proper border colors and hover states) - Drop checkbox column width from 36px to 28px to match real table - Use theme.icon.size.md for header icons (was sm) - Move row border-bottom onto each cell to match real RecordTable layout - Centralize row/checkbox dimensions in BackgroundMockTableDimensions - Remove right borders on footer cells
- Wrap page header and view bar building icon in TintedIconTile (blue) to match the colored object header used on the real Companies page - Add kebab (IconDotsVertical) and side panel toggle buttons next to the primary action so the page header silhouette mirrors the real one
| label={item.label} | ||
| Icon={item.Icon} | ||
| onClick={() => {}} | ||
| /> | ||
| ))} | ||
| </NavigationDrawerSection> | ||
| </NavigationDrawer> | ||
| ); |
There was a problem hiding this comment.
Bug: The color property in BACKGROUND_MOCK_OTHER_ITEMS is ignored because the iconColor prop isn't passed to NavigationDrawerItem, causing a visual inconsistency with other navigation items.
Severity: LOW
Suggested Fix
When mapping over BACKGROUND_MOCK_OTHER_ITEMS, pass the iconColor prop to the NavigationDrawerItem component. The implementation should be iconColor={item.color}, mirroring the pattern used for BACKGROUND_MOCK_WORKSPACE_ITEMS in the same file.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockNavigationDrawer.tsx#L68-L75
Potential issue: The `BACKGROUND_MOCK_OTHER_ITEMS` constant defines a `color` property
for its items. However, when these items are rendered in
`BackgroundMockNavigationDrawer.tsx`, the `iconColor` prop is not passed to the
`NavigationDrawerItem` component. This is inconsistent with how
`BACKGROUND_MOCK_WORKSPACE_ITEMS` are rendered in the same component, which do pass the
`iconColor` prop. As a result, the "Settings" and "Documentation" icons will be rendered
with the default `currentColor` instead of the intended tinted gray background, creating
a visual inconsistency in the navigation drawer mock.
Also affects:
packages/twenty-front/src/modules/sign-in-background-mock/constants/BackgroundMockOtherItems.ts:1~8
Did we get this right? 👍 / 👎 to inform future reviews.
The real RecordTable starts with a 12px drag-handle column before the checkbox; without it the checkbox sat flush against the left edge. Added a leading drag-handle column on the header, rows and footer. The aggregate footer cell relied on flex justify-content alone, so labels like "Max of Em…" wrapped vertically. Wrap the label in OverflowingTextWithTooltip (same component the real footer uses) and add white-space: nowrap to the cell so the text truncates with an ellipsis instead of wrapping.
There was a problem hiding this comment.
1 issue found across 5 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockTableRow.tsx">
<violation number="1" location="packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockTableRow.tsx:103">
P2: Use a non-interactive checkbox for the mock background row. As written, this adds focusable/toggleable inputs to decorative content.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
| <StyledRow> | ||
| <StyledDragHandleColumn /> | ||
| <StyledCheckboxColumn> | ||
| <Checkbox hoverable checked={false} /> |
There was a problem hiding this comment.
P2: Use a non-interactive checkbox for the mock background row. As written, this adds focusable/toggleable inputs to decorative content.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/twenty-front/src/modules/sign-in-background-mock/components/BackgroundMockTableRow.tsx, line 103:
<comment>Use a non-interactive checkbox for the mock background row. As written, this adds focusable/toggleable inputs to decorative content.</comment>
<file context>
@@ -100,8 +98,9 @@ export const BackgroundMockTableRow = ({
+ <StyledDragHandleColumn />
<StyledCheckboxColumn>
- <StyledCheckbox />
+ <Checkbox hoverable checked={false} />
</StyledCheckboxColumn>
<StyledCell width={BACKGROUND_MOCK_COLUMN_WIDTHS.Name}>
</file context>
| <Checkbox hoverable checked={false} /> | |
| <Checkbox hoverable={false} checked={false} disabled /> |
Tip: Review your code locally with the cubic CLI to iterate faster.
The production MinimalMetadataLoadEffect no longer loads the mocked metadata snapshot for signed-out users (we render the hardcoded BackgroundMock instead), but storybook page tests still rely on object metadata being available — e.g. SettingsAccountsBlocklistSection looks up the "blocklist" object and crashes against an empty store. Introduce a storybook-only MockedMetadataLoadEffect that loads the mocked snapshot directly and only flips isMinimalMetadataReady once the object metadata is in place, so MinimalMetadataGater waits for it.
Mirror the real RecordTable layout by adding a trailing add-column placeholder followed by a flex-fill last empty cell in the body rows and footer, matching `RecordTableHeaderLastEmptyColumn` / `RecordTableLastEmptyCell` so the right edge stays aligned and the table fills remaining width.
The checkbox header column was missing `box-sizing: border-box` while the row checkbox column had it, so the 4px right padding pushed the header's external width to 32px while rows stayed at 28px. This shifted every column from the checkbox onward by 4px. Using border-box on the header makes header/body/footer columns line up exactly.
|
|
||
| const isReady = !areObjectsLoaded | ||
| ? false | ||
| : !hasAccessTokenPair || | ||
| (isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded)); | ||
|
|
||
| if (!areObjectsLoaded) { | ||
| setIsMinimalMetadataReady(false); | ||
| return; | ||
| } | ||
|
|
||
| const isReady = | ||
| isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded); | ||
|
|
||
| if (isReady) { | ||
| setIsMinimalMetadataReady(true); |
There was a problem hiding this comment.
Bug: The IsMinimalMetadataReadyEffect fails to set isMinimalMetadataReady to false during login when metadata is ready but user data is still loading, causing a race condition.
Severity: HIGH
Suggested Fix
Add logic to the useEffect hook to handle the case where readiness conditions are not met. Specifically, add a condition to call setIsMinimalMetadataReady(false) when isReady is false. For example: if (!isReady) { setIsMinimalMetadataReady(false); }.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
packages/twenty-front/src/modules/metadata-store/effect-components/IsMinimalMetadataReadyEffect.tsx#L31-L50
Potential issue: When a user logs out and then logs back in, a race condition can occur.
The `IsMinimalMetadataReadyEffect` sets `isMinimalMetadataReady` to `true` in the
logged-out state. Upon login, if metadata is already cached (`metadataStore.status ===
'up-to-date'`) but the asynchronous fetch for `currentUser` has not yet completed, the
`isReady` check evaluates to `false`. However, the effect lacks a corresponding `else`
branch to set `isMinimalMetadataReady` to `false`. As a result, `isMinimalMetadataReady`
remains `true`, causing the `MinimalMetadataGater` to render child components
prematurely before `currentUser` is defined, which can lead to application crashes or
rendering errors.
The header had a fixed 32px add-column cell followed by a flex-fill empty cell, which left a visible boundary inside the right side of the table. Merge them: the add-column header cell now grows to fill remaining width and contains the icon at the start (in a 32px wrapper to keep its visual position). Drop the matching 32px trailing placeholder in rows and footer so their flex-fill last cells take the full remaining width in lockstep with the header.
| const isReady = | ||
| isDefined(currentUser) && (!hasActiveWorkspace || areViewsLoaded); | ||
|
|
||
| if (isReady) { | ||
| setIsMinimalMetadataReady(true); |
There was a problem hiding this comment.
Bug: The IsMinimalMetadataReadyEffect fails to reset isMinimalMetadataReady to false during login when cached metadata is present but the user session isn't fully ready, causing premature rendering.
Severity: HIGH
Suggested Fix
In IsMinimalMetadataReadyEffect.tsx, add an else block to the if (isReady) condition to explicitly set isMinimalMetadataReady to false when the metadata is not fully ready for use.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location:
packages/twenty-front/src/modules/metadata-store/effect-components/IsMinimalMetadataReadyEffect.tsx#L46-L50
Potential issue: In `IsMinimalMetadataReadyEffect`, when a user logs in, there's a
scenario where `isMinimalMetadataReady` can be incorrectly left as `true`. This happens
if the user was previously logged out (which sets it to `true`), and upon login, cached
metadata exists (`areObjectsLoaded` is true) but the user session is not yet fully
established (`isReady` is false because `currentUser` is null). The effect checks `if
(isReady)` but lacks an `else` block to reset `isMinimalMetadataReady` to `false`. This
causes the `MinimalMetadataGater` to skip its loading state and render child components
prematurely with incomplete data, potentially leading to runtime errors.
…oaded (#20330) ## Summary Fixes the merge-queue E2E failures introduced after #20308. After login, users were being silently redirected to `/settings/profile` instead of their workspace home, which broke every dependent E2E test that re-uses the post-login URL (`workflow-creation.spec.ts`, `authentication/signup_invite_email.spec.ts`, etc.). ## Root cause `useDefaultHomePagePath` falls back to `/settings/profile` when `readableNonSystemObjectMetadataItems` is empty. That list is empty in two cases: 1. The user genuinely has no readable objects → `/settings/profile` is the intended fallback. 2. Object metadata simply hasn't been loaded yet (transient post-login window). Before #20308 the frontend always loaded mocked metadata for authenticated users, so case (2) never happened. After #20308 mocked metadata is gone, and during the post-verify window (`handleLoadWorkspaceAfterAuthentication` finishes, `setIsAppEffectRedirectEnabled(true)` re-enables redirects, `PageChangeEffect` fires) the metadata store is still empty. The hook then returns `/settings/profile`. Because that path is not in `ONBOARDING_PATHS` / `ONGOING_USER_CREATION_PATHS`, `usePageChangeEffectNavigateLocation` doesn't fire a corrective redirect once metadata finally loads — the user is stranded. `login.setup.ts` captures `process.env.LINK = page.url()` after verify, so subsequent tests `goto(LINK)` end up in Settings looking for app navigation that isn't there → click timeouts. ## Fix Distinguish the two empty cases by reading `metadataStoreState('objectMetadataItems').status`. If it isn't `'up-to-date'` we defer to `AppPath.Index` instead of `/settings/profile`. The memo recomputes when the status flips, and the user is then routed to their actual home page. A regression test is added in `useDefaultHomePagePath.test.ts` for the not-loaded-yet case. ## Test plan - [x] Unit: `npx jest src/modules/navigation/hooks/__tests__/useDefaultHomePagePath.test.ts` (5/5 pass, including new regression case) - [ ] CI: Playwright E2E (`workflow-creation.spec.ts`, `authentication/signup_invite_email.spec.ts`) pass on this branch - [ ] Manual: log in to a fresh local instance and confirm landing page is the workspace home, not `/settings/profile`
…q#20341) ## Summary Follow-up to twentyhq#20308. After that PR, production code no longer loads mocked metadata when the user is unauthenticated. The remaining mocked-metadata helpers (`useLoadMockedMetadata`, `preloadMockedMetadata`) are now only consumed by Storybook decorators, so move them next to the other testing-only utilities to make their scope explicit and prevent accidental re-introduction of a runtime dependency on mocks. - `src/modules/metadata-store/hooks/useLoadMockedMetadata.ts` → `src/testing/hooks/useLoadMockedMetadata.ts` - `src/modules/metadata-store/utils/preloadMockedMetadata.ts` → `src/testing/utils/preloadMockedMetadata.ts` The three Storybook decorator imports (`MockedMetadataLoadEffect`, `ObjectMetadataItemsDecorator`, `WorkflowStepDecorator`) are updated to the new `~/testing/...` paths. No runtime behavior change. ## Test plan - [x] `npx oxlint --type-aware -c .oxlintrc.json` on touched files — clean - [x] `npx prettier --check` on touched files — clean - [ ] CI: storybook, unit tests, e2e tests
Summary
When the user is logged out, we render the auth modal on top of a sample table to make the empty page feel alive. So far this was achieved by loading a full set of mocked object / field / view / navigation-menu metadata into the runtime metadata store and then mounting the real
RecordTableandAppNavigationDrawerbehind the modal. This had a few downsides:RecordTablevirtualization stack).useRecordIndexTableQuery,useTriggerInitialRecordTableDataLoad,MainContextStoreProvider,IsMinimalMetadataReadyEffect...).This PR replaces the entire flow with a small, self-contained
BackgroundMockcomponent tree that does not consume any metadata and does not load any mocked metadata at runtime.What changed
sign-in-background-mock:BackgroundMockPage+BackgroundMockViewBar+BackgroundMockTable+BackgroundMockTableRowrender a hardcoded "Companies" table that visually mirrors the real one.BackgroundMockNavigationDrawerrenders a hardcoded sidebar with People / Companies / Opportunities / Tasks / Notes (with their standard colors).BackgroundMockCompanies.ts,BackgroundMockColumns.ts,BackgroundMockNavigationItems.ts.MinimalMetadataLoadEffectno longer callsloadMockedMetadataAtomicfor unauthenticated users — it just doesn't load anything.IsMinimalMetadataReadyEffectnow reports ready immediately when there is no access token pair, so the skeleton loader doesn't hang waiting for metadata that will never come.MainContextStoreProvider,useRecordIndexTableQuery, anduseTriggerInitialRecordTableDataLoaddrop theirshowAuthModalbranches — the realRecordTableis no longer mounted behind the modal.DefaultLayoutandNotFoundnow lazily loadBackgroundMockPage/BackgroundMockNavigationDrawerinstead of the deletedSignInBackgroundMockPage/SignInAppNavigationDrawerMock.SignInBackgroundMockPage,SignInBackgroundMockContainer,SignInBackgroundMockContainerEffect,SignInAppNavigationDrawerMock,SignInBackgroundMockColumnDefinitions,SignInBackgroundMockCompanies,SignInBackgroundMockViewFields.useLoadMockedMetadataandpreloadMockedMetadataare kept on purpose: Storybook decorators (ObjectMetadataItemsDecorator,WorkflowStepDecorator) still rely on the mocked metadata fixtures, but production unauthenticated runtime no longer touches them.Visual parity
Side-by-side at 1440×900 on
/sign-in:Before (loads mocked metadata + real RecordTable):
After (purely hardcoded BackgroundMock):
Test plan
npx nx typecheck twenty-front✅ (passes locally)npx nx lint:diff-with-main twenty-front✅ (oxlint + prettier clean)npx jest useRecordIndexTableQuery✅/sign-inrenders the table + nav drawer behind the modal/not-foundstill renders the background