Commit Graph

43 Commits

Author SHA1 Message Date
Félix Malfait bfefcd3755 feat(twenty-front): generalize the page primary/secondary bars (flat redesign) (#21308)
Replaces #21279 and #21282 with one clean PR from `main`.

Generalizes the settings primary-bar / secondary-bar card chrome to the
record index, record show and standalone pages via a shared
`PageCardLayout` + `PageCardHeader` (the side panel sits as a sibling of
the content card), and applies the new flat design direction: square
corners on the card, side panel and loading skeletons.

Iterating toward the new design (Figma node 102282-221623); the
confirmed direction and the explicit "remove rounded corners" change are
in, remaining designer specifics to follow.
2026-06-08 22:47:05 +02:00
nitin 097432d3a2 [Command Menu] Refactor layout customization conditional availability [Warning] (#19974)
closes
https://discord.com/channels/1130383047699738754/1494312529286004837
2026-04-24 10:18:02 +00:00
Charles Bochet de1e592cd3 fix(front): suppress full-page skeleton inside auth modal (#19875)
## Summary

- Lazy auth-flow routes (`SignInUp`, `Invite`, `ResetPassword`,
`CreateWorkspace`, `CreateProfile`, `SyncEmails`, `InviteTeam`,
`PlanRequired`, `PlanRequiredSuccess`, `BookCallDecision`, `BookCall`)
render through `<Outlet/>` inside `<AuthModal>`. Their `LazyRoute`
`<Suspense>` fallback was the page-level `PageContentSkeletonLoader`, so
the two grey shimmer bars painted **inside the modal box** for a few
hundred ms while each chunk downloaded.
- `LazyRoute` now accepts an optional `fallback` prop (default
unchanged: the existing page skeleton). Every auth-modal route passes
`fallback={null}` so the modal stays empty until the lazy chunk resolves
instead of flashing the shimmer.
- `AuthModal`'s inner `StyledContent` gets a `min-height: 320px` so the
framer-motion `layout` animation doesn't rapidly resize the modal as
inner steps (loader → form → password → 2FA / workspace selection) swap.
The modal can still grow for taller steps; only the rapid jump is
removed.

## Why default-parameter syntax for `fallback`

`fallback ?? <LazyRouteFallback/>` would treat an explicit `null` as "no
value" and still render the default skeleton. Using a default parameter
(`fallback = <LazyRouteFallback/>`) preserves an explicit `null` because
defaults only kick in for `undefined`.
2026-04-20 09:39:09 +00:00
Raphaël Bosi a88d1f4442 Introduce standalone page (#19675)
Add support for standalone pages: a new `PageLayout` type
(`STANDALONE_PAGE`) that can be rendered independently at
`/page/:pageLayoutId`, not tied to any record or object context.

- New `STANDALONE_PAGE` page layout type
- New `PAGE_LAYOUT` navigation menu item type: adds a `pageLayoutId`
foreign key to `NavigationMenuItemEntity`, allowing sidebar items to
link directly to standalone pages
- New `GLOBAL_OBJECT_CONTEXT` command menu availability type: separates
object-context-dependent commands (Create Record, Import, Export, See
Deleted, Create View, Hide Deleted) from truly global ones, so
standalone pages only show relevant commands
- Frontend routing & rendering: adds a `/page/:pageLayoutId` route with
its own page component, header, and command menu
- Widget rendering refactor
- Instance commands: two fast 1.22 migrations: `pageLayoutId` column +
`STANDALONE_PAGE` enum, and `GLOBAL_OBJECT_CONTEXT` availability type
enum
- Workspace command: backfills existing command menu items from `GLOBAL`
to `GLOBAL_OBJECT_CONTEXT` where appropriate
- Dev seeds: adds a sample "Star History" standalone page with an iframe
widget for local development
2026-04-14 15:52:45 +00:00
Baptiste Devessier e2bd3e8ef4 Unselect widget when exiting layout customization mode (#19411) 2026-04-07 17:26:07 +00:00
Félix Malfait 77d4bd9158 Add billing usage analytics dashboard with ClickHouse integration (#18592)
## Summary
This PR adds a comprehensive billing usage analytics feature that
provides detailed breakdowns of credit consumption across execution
types, users, resources, and time periods. The implementation includes a
new ClickHouse-backed analytics service, GraphQL API endpoint, and a
frontend dashboard component.

## Key Changes

### Backend
- **New BillingAnalyticsService**: Queries ClickHouse for usage
breakdowns by user, resource, execution type, and time series data
- **BillingEventWriterService**: Writes billing events to ClickHouse for
analytics while maintaining best-effort semantics (never blocks Stripe
billing)
- **ClickHouse Schema**: Added `billingEvent` table with 3-year TTL for
storing detailed billing event data
- **GraphQL Resolver**: New `getBillingAnalytics` query that aggregates
usage data for the current billing period, protected by feature flag and
billing permissions
- **Enhanced BillingUsageEvent**: Added `userWorkspaceId` field to track
per-user credit consumption
- **AI Billing Integration**: Updated AI billing service to pass
`userWorkspaceId` when recording usage events

### Frontend
- **SettingsBillingAnalyticsSection**: New component displaying:
  - Usage breakdown by execution type with progress bars
  - Daily usage time series chart (28-day view)
  - Per-user credit consumption breakdown
  - Per-resource (agent/workflow) credit consumption breakdown
- **SettingsUsage Page**: Dedicated page for viewing usage analytics
- **GraphQL Query**: `GetBillingAnalytics` query with generated hooks
- **Navigation**: Added Usage menu item in settings (feature-flagged)
- **Mock Data**: Included screenshot mock data for preview/testing

### Feature Flag
- Added `IS_USAGE_ANALYTICS_ENABLED` feature flag to control visibility
and access to analytics features

## Implementation Details
- Analytics data is queried in parallel for performance
- ClickHouse writes are non-blocking to ensure billing operations never
fail
- Progress bars use dynamic coloring from a predefined palette
- Time series visualization normalizes bar heights relative to max value
- Empty state handling when no analytics data is available
- Responsive UI with proper text truncation for long names

https://claude.ai/code/session_01Y1EqrX6PFq3EJxJq89h7DF

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-23 10:28:23 +01:00
nitin ab881350b2 refactor: unify layout customization mode (record pages + navigation) (#18640)
### What

Unifies record page layout editing and navigation menu editing into a
single global "layout customization" session. Dashboard editing stays
separate.

  ### How it works

  **Two edit mode systems, one context-based read:**
- `isLayoutCustomizationModeEnabledState` -- global atom for record
pages + navigation
- `isDashboardInEditModeComponentState` -- dashboard-only, independent
per-component atom
- `PageLayoutEditModeProvider` -- context that dispatches to
`RecordPageLayoutEditModeProvider` (reads global atom) or
`DashboardPageLayoutEditModeProvider` (reads component atom), one
component per file

  **Session registry + independent atoms:**
- `activeCustomizationPageLayoutIdsState` -- accumulates page layout IDs
as user navigates during customization (`string[]`)
- Save/cancel iterate the ID list and read each layout's draft/persisted
atoms independently
- Follows the same pattern as `settingsRoleIdsState` +
`settingsDraftRoleFamilyState`

  **Unified UI:**
- `LayoutCustomizationBar` replaces the old `NavigationMenuEditModeBar`
- Enter once -- edit record layouts + navigation -- save/cancel
everything together
- `useSaveLayoutCustomization` orchestrates sequential save: navigation
draft -- page layouts -- field widget groups
- Error snackbar on partial save failure (with TODO for future atomic
server mutation)

  **Draft protection during customization:**
- `PageLayoutRelationWidgetsSyncEffect` guarded -- only updates
persisted state from server, skips draft/currentLayouts while
customization is active
- `useExecuteTasksOnAnyLocationChange` skips draft reset when
customization mode is enabled
  - Command execution blocked during layout customization

  ### Cleanup
- Deleted `NavigationMenuEditModeBar`,
`isNavigationMenuInEditModeState`,
`isPageLayoutInEditModeComponentState`,
`useIsGlobalLayoutCustomizationActive`
- `DraftPageLayout` type changed from `Omit` to `Pick` (explicit fields)
- Removed save/cancel from `DefaultRecordCommandMenuItemsConfig` (bar
handles it now)
  - Extracted `useSaveFieldsWidgetGroups` from save orchestration
- Split `PageLayoutEditModeProvider` into 3 separate files (one
component per file, Twenty convention)

  ### Known issues
- **Stale deleted widget after save (pre-existing on `main`)**: Delete
widget -- save -- exit customization -- Apollo cache stale -- sync
effect overwrites Jotai from stale data -- widget reappears until
refresh. Separate PR needed, likely tied to the planned server-side
`saveLayoutCustomization` atomic endpoint.

  ### Open questions
- **Module location**: Layout customization hooks/states live in `/app`
-- should they move to their own `modules/layout-customization/`?
- **Atomic server mutation**: All save mutations are on metadata schema
(`createNavigationMenuItem`, `deleteNavigationMenuItem`,
`updateNavigationMenuItem`, `updatePageLayoutWithTabsAndWidgets`,
`upsertFieldsWidget`). A single `saveLayoutCustomization` endpoint could
make saves truly atomic.


https://github.com/user-attachments/assets/036ef542-97f3-485b-a68f-3726002c81fb
2026-03-17 16:24:09 +01:00
Baptiste Devessier 926dd545f4 Create fake hidden fields group (#18525)
## Demo


https://github.com/user-attachments/assets/43f31c43-fe37-4553-ad42-fc97a948d6ea

## Ungrouped fields

<img width="3456" height="2160" alt="CleanShot 2026-03-10 at 13 52
57@2x"
src="https://github.com/user-attachments/assets/13d1db63-59ac-4e2b-8950-fccf430176c4"
/>
2026-03-10 16:26:35 +01:00
Charles Bochet d37ed7e07c Optimize merge queue to only run E2E and integrate prettier into lint (#18459)
## Summary

- **Merge queue optimization**: Created a dedicated
`ci-merge-queue.yaml` workflow that only runs Playwright E2E tests on
`ubuntu-latest-8-cores`. Removed `merge_group` trigger from all 7
existing CI workflows (front, server, shared, website, sdk, zapier,
docker-compose). The merge queue goes from ~30+ parallel jobs to a
single focused E2E job.
- **Label-based merge queue simulation**: Added `run-merge-queue` label
support so developers can trigger the exact merge queue E2E pipeline on
any open PR before it enters the queue.
- **Prettier in lint**: Chained `prettier --check` into `lint` and
`prettier --write` into `lint --configuration=fix` across `nx.json`
defaults, `twenty-front`, and `twenty-server`. Prettier formatting
errors are now caught by `lint` and fixed by `lint:fix` /
`lint:diff-with-main --configuration=fix`.

## After merge (manual repo settings)

Update GitHub branch protection required status checks:
1. Remove old per-workflow merge queue checks (`ci-front-status-check`,
`ci-e2e-status-check`, `ci-server-status-check`, etc.)
2. Add `ci-merge-queue-status-check` as the required check for the merge
queue
2026-03-06 13:20:57 +01:00
Charles Bochet 364c944ca6 Improve build performance 2x (#18449)
## Summary

Front Before:
<img width="1199" height="670" alt="image"
src="https://github.com/user-attachments/assets/b978f67c-c0a6-49fc-bedd-a443f11c365d"
/>

Front After:
<img width="1199" height="670" alt="image"
src="https://github.com/user-attachments/assets/a4939dbb-a8b4-4c74-978c-daa7f27d00f3"
/>


Server Before:
<img width="1199" height="670" alt="image"
src="https://github.com/user-attachments/assets/da53e97f-ec65-4224-a656-ca41040aef6e"
/>


Server After:
<img width="1199" height="670" alt="image"
src="https://github.com/user-attachments/assets/8cdf3885-f515-4d6c-989f-a421a4e8206c"
/>


### CI Server Pipeline Restructuring
- Split monolithic `server-setup` job into three parallel jobs:
`server-build`, `server-lint-typecheck`, and `server-validation`
- `server-build` only handles build + Nx cache save (~1m vs old 3.5m),
unblocking downstream jobs faster
- `server-lint-typecheck` runs in parallel with no DB dependency
- `server-validation` handles DB setup, migration checks, and GraphQL
generation checks in parallel with tests
- Make `server-test` (unit tests) fully independent — no longer waits
for server-setup, builds its own artifacts
- Increase integration test shards from 8 to 10 for better parallelism
- Expected critical path reduction: ~10m → ~7m (~30% faster)

### CI Front Pipeline Improvements
- Use artifact upload/download for storybook build instead of rebuilding
in test shards
- Serve pre-built storybook via `http-server` in test jobs, with
`STORYBOOK_URL` env var
- Update `vitest.config.ts` to use `storybookUrl` when `STORYBOOK_URL`
is set
- Remove redundant `twenty-shared`, `twenty-ui`, `twenty-sdk` builds
from storybook test shards

### Vite Build Optimizations
- Conditionally enable `rollup-plugin-visualizer` behind `ANALYZE=true`
env var (not loaded by default)
- Broaden Istanbul coverage exclusions to skip test files, stories,
mocks, and decorators
- Remove `@tabler/icons-react` alias from twenty-front and storybook
configs
- Bundle `@tabler/icons-react` into twenty-ui instead of treating it as
an external dependency
- Add lazy loading with `React.lazy` + `Suspense` for all page-level
route components in `useCreateAppRouter`
2026-03-06 11:02:26 +01:00
Charles Bochet 9d57bc39e5 Migrate from ESLint to OxLint (#18443)
## Summary

Fully replaces ESLint with OxLint across the entire monorepo:

- **Replaced all ESLint configs** (`eslint.config.mjs`) with OxLint
configs (`.oxlintrc.json`) for every package: `twenty-front`,
`twenty-server`, `twenty-emails`, `twenty-ui`, `twenty-shared`,
`twenty-sdk`, `twenty-zapier`, `twenty-docs`, `twenty-website`,
`twenty-apps/*`, `create-twenty-app`
- **Migrated custom lint rules** from ESLint plugin format to OxLint JS
plugin system (`@oxlint/plugins`), including
`styled-components-prefixed-with-styled`, `no-hardcoded-colors`,
`sort-css-properties-alphabetically`,
`graphql-resolvers-should-be-guarded`,
`rest-api-methods-should-be-guarded`, `max-consts-per-file`, and
Jotai-related rules
- **Migrated custom rule tests** from ESLint `RuleTester` + Jest to
`oxlint/plugins-dev` `RuleTester` + Vitest
- **Removed all ESLint dependencies** from `package.json` files and
regenerated lockfiles
- **Updated Nx targets** (`lint`, `lint:diff-with-main`, `fmt`) in
`nx.json` and per-project `project.json` to use `oxlint` commands with
proper `dependsOn` for plugin builds
- **Updated CI workflows** (`.github/workflows/ci-*.yaml`) — no more
ESLint executor
- **Updated IDE setup**: replaced `dbaeumer.vscode-eslint` with
`oxc.oxc-vscode` extension, configured `source.fixAll.oxc` and
format-on-save with Prettier
- **Replaced all `eslint-disable` comments** with `oxlint-disable`
equivalents across the codebase
- **Updated docs** (`twenty-docs`) to reference OxLint instead of ESLint
- **Renamed** `twenty-eslint-rules` package to `twenty-oxlint-rules`

### Temporarily disabled rules (tracked in `OXLINT_MIGRATION_TODO.md`)

| Rule | Package | Violations | Auto-fixable |
|------|---------|-----------|-------------|
| `twenty/sort-css-properties-alphabetically` | twenty-front | 578 | Yes
|
| `typescript/consistent-type-imports` | twenty-server | 3814 | Yes |
| `twenty/max-consts-per-file` | twenty-server | 94 | No |

### Dropped plugins (no OxLint equivalent)

`eslint-plugin-project-structure`, `lingui/*`, `@stylistic/*`,
`import/order`, `prefer-arrow/prefer-arrow-functions`,
`eslint-plugin-mdx`, `@next/eslint-plugin-next`,
`eslint-plugin-storybook`, `eslint-plugin-react-refresh`. Partial
coverage for `jsx-a11y` and `unused-imports`.

### Additional fixes (pre-existing issues exposed by merge)

- Fixed `EmailThreadPreview.tsx` broken import from main rename
(`useOpenEmailThreadInSidePanel`)
- Restored truthiness guard in `getActivityTargetObjectRecords.ts`
- Fixed `AgentTurnResolver` return types to match entity (virtual
`fileMediaType`/`fileUrl` are resolved via `@ResolveField()`)

## Test plan

- [x] `npx nx lint twenty-front` passes
- [x] `npx nx lint twenty-server` passes
- [x] `npx nx lint twenty-docs` passes
- [x] Custom oxlint rules validated with Vitest: `npx nx test
twenty-oxlint-rules`
- [x] `npx nx typecheck twenty-front` passes
- [x] `npx nx typecheck twenty-server` passes
- [x] CI workflows trigger correctly with `dependsOn:
["twenty-oxlint-rules:build"]`
- [x] IDE linting works with `oxc.oxc-vscode` extension
2026-03-06 01:03:50 +01:00
Félix Malfait 6351c6c1c6 feat: remember original URL and redirect after login (#18308)
## Summary

- Implement a return-to-path mechanism that preserves the user's
intended destination across authentication flows (login, magic link,
cross-domain redirects)
- Uses layered persistence: Jotai atom (in-memory), sessionStorage with
TTL (tab-switch resilience), URL query parameter (cross-domain
propagation)
- Includes path validation to prevent open redirects, automatic cleanup
after successful login, and comprehensive test coverage
- Replaces the unused `previousUrlState` with a robust
`returnToPathState` system

## Test plan

- [ ] Visit a deep link (e.g. `/objects/tasks`) while logged out —
should redirect to login, then back to `/objects/tasks` after logging in
- [ ] Visit an OAuth authorize link while logged out — should redirect
to login, then to the authorize page
- [ ] Test magic link flow: click sign-in link that opens new tab —
should still redirect to original destination
- [ ] Test cross-domain: visit `app.twenty.com/objects/tasks` — should
preserve path through workspace domain redirect
- [ ] Verify auth/onboarding paths are excluded from being saved as
return paths
- [ ] Verify return-to-path is cleared after successful navigation
- [ ] All 215 existing `usePageChangeEffectNavigateLocation` tests pass


Made with [Cursor](https://cursor.com)
2026-03-02 19:00:48 +01:00
Charles Bochet 121788c42f Fully deprecate old recoil (#18210)
## Summary

Removes the `recoil` dependency entirely from `package.json` and
`twenty-front/package.json`, completing the migration to Jotai as the
sole state management library.

Removes all Recoil infrastructure: `RecoilRoot` wrapper from `App.tsx`
and test decorators, `RecoilDebugObserver`, Recoil-specific ESLint rules
(`use-getLoadable-and-getValue-to-get-atoms`,
`useRecoilCallback-has-dependency-array`), and legacy Recoil utility
hooks/types (`useRecoilComponentState`, `useRecoilComponentValue`,
`createComponentState`, `createFamilyState`, `getSnapshotValue`,
`cookieStorageEffect`, `localStorageEffect`, etc.).

Renames all `V2`-suffixed Jotai state files and types to their canonical
names (e.g., `ComponentStateV2` -> `ComponentState`,
`agentChatInputStateV2` -> `agentChatInputState`, `SelectorCallbacksV2`
-> `SelectorCallbacks`), and removes the now-redundant V1 counterparts.

Updates ~433 files across the codebase to use the renamed Jotai imports,
remove Recoil imports, and clean up test wrappers (`RecoilRootDecorator`
-> `JotaiRootDecorator`).
2026-02-25 12:26:42 +01:00
Charles Bochet eaf9fe27b2 Improve Jotai work (#18205) 2026-02-24 20:38:30 +01:00
Charles Bochet 0f2af6a6cb Jotai 13 (#18178)
## Recoil to Jotai Migration — PR 13: Workflow, Page Layout, AI,
Activities, Settings, SSE & Remaining Modules

### Summary

This is the 13th PR in the [14-PR migration
series](packages/twenty-front/src/modules/ui/utilities/state/jotai/MIGRATION_PLAN.md)
to replace Recoil with Jotai as the state management library in
`twenty-front`. This PR migrates the remaining consumer code across all
modules — updating ~1,076 files with ~10k insertions/deletions.

### What changed

**New Jotai infrastructure (13 new files):**
- `createComponentSelectorV2` and `createComponentFamilySelectorV2` —
instance-scoped derived atoms, replacing Recoil's component selectors
- 6 new hooks: `useRecoilComponentSelectorValueV2`,
`useRecoilComponentFamilySelectorValueV2`,
`useRecoilComponentSelectorCallbackStateV2`,
`useRecoilComponentFamilySelectorCallbackStateV2`,
`useRecoilComponentStateCallbackStateV2`,
`useRecoilComponentFamilyStateCallbackStateV2`
- New types: `ComponentSelectorV2`, `ComponentFamilySelectorV2`,
`SelectorCallbacksV2`
- Extended `buildGetHelper` to support the new selector patterns

**State definition migrations:**
- `createState()` → `createStateV2()` (Jotai `atom()`)
- `createFamilyState()` → `createFamilyStateV2()` (Jotai `atom()` with
family cache)
- Recoil `selector`/`selectorFamily` → Jotai derived `atom()` via V2
utilities

**Hook migrations (~2,400 removed, ~1,545 added V2 equivalents):**
- `useRecoilValue` → `useRecoilValueV2`
- `useRecoilState` → `useRecoilStateV2`
- `useSetRecoilState` → `useSetRecoilStateV2`
- `useRecoilCallback` → `useCallback` + `jotaiStore.get/set`
- `useRecoilComponentValue` → `useRecoilComponentValueV2`
- `useSetRecoilComponentState` → `useSetRecoilComponentStateV2`
- `useRecoilComponentFamilyValue` → `useRecoilComponentFamilyValueV2` /
`useFamilySelectorValueV2`
- ~397 direct `import from 'recoil'` removed

**Deleted files (9 files):**
- `dateLocaleState.ts` — consolidated
- `currentAIChatThreadTitleStateV2.ts` — renamed to replace the original
- `isCommandMenuOpenedState.ts` — removed
- `filesFieldUploadState.ts` — replaced by V2
- `recordStoreFamilySelector.ts`, `recordStoreFieldValueSelector.ts`,
`recordStoreRecordsSelector.ts` — replaced by V2 equivalents
- `settingsAllRolesSelector.ts` — replaced by `useSettingsAllRoles` hook
- `settingsRoleIdsStateV2.ts` — consolidated

**Modules migrated:**
- Workflow (diagram, steps, variables, filters)
- Page Layout (widgets, fields, graph, tabs)
- AI (chat, agents, browsing context)
- Activities (rich text editor, targets, timeline)
- Action Menu (single/multiple record actions)
- Command Menu (navigation, history, pages, workflow)
- Context Store
- Record Board, Record Table, Record Calendar, Record Index
- Record Field, Record Filter, Record Sort, Record Group
- Record Drag, Record Picker, Record Store
- Views (view bar, view picker, filters, sorts)
- Settings (roles, permissions, SSO, security, data model, developers,
domains)
- SSE (event streams, subscriptions)
- Spreadsheet Import
- Auth, Favorites, Front Components, Information Banner
2026-02-24 17:37:01 +01:00
Charles Bochet 0d4fe4575b Various SDK improvements (#18115)
## Summary

- **Refactor frontend metadata loading architecture**: Split the
monolithic `EagerMetadataLoadEffect` into focused provider effects
(`UserMetadataProviderEffect`, `ObjectMetadataProviderEffect`,
`ViewMetadataProviderEffect`) orchestrated by `MetadataProviderEffects`.
Replaced `UserProvider` + `ObjectMetadataItemsProvider` with a single
`MetadataGater` that gates rendering on `isAppMetadataReadyState`. The
metadata store now validates view-object consistency before promoting
views, and `updateDraft` skips no-op updates via deep equality checks.

- **SDK CLI improvements**: Added `app:typecheck` command, improved
error handling in API sync (extracts GraphQL error messages), added
`serializeError` utility for human-readable error output, added `error`
file status to dev mode orchestrator with UI support, and fixed
ClickHouse migration/seed commands to use `transpile-only`.
2026-02-23 19:57:02 +01:00
Charles Bochet b51eb6471f Jotai 12 (#18160)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-23 12:01:37 +01:00
Baptiste Devessier 00209f7e2c Wire fields widget to backend + basic edition (#17965)
Closes https://github.com/twentyhq/core-team-issues/issues/2215
Closes https://github.com/twentyhq/core-team-issues/issues/2216
Closes https://github.com/twentyhq/core-team-issues/issues/2218

## Fields widget edition demo


https://github.com/user-attachments/assets/08626d70-8fcb-4ae2-9222-10ef57e75f90

## Dashboards still work


https://github.com/user-attachments/assets/aa9a9c45-a0a2-481e-b132-bc52254778da
2026-02-20 13:18:00 +00:00
nitin 27e5b9797b [Dashboards] Fix page layout navigation edit mode sync (#17478)
navigating away - 

before - 


https://github.com/user-attachments/assets/ffd4c592-cf6d-403c-8aa2-9f55692fac65


after - 


https://github.com/user-attachments/assets/fc298e20-21ac-4f2f-b52a-8ecfdfd4eb38

new dashbaord - 

before - 


https://github.com/user-attachments/assets/f9a2d7ab-6b5b-41c3-b993-33745ab61683


after -


https://github.com/user-attachments/assets/cad68c35-6dfa-4fa2-ab9b-890900be3444




empty page layout - 

before - 



https://github.com/user-attachments/assets/27a5b61b-cd0c-4786-a461-e28f1e348822



after - 


https://github.com/user-attachments/assets/213e5242-493b-45de-a622-cf1463bb6380
2026-01-27 15:25:41 +00:00
Raphaël Bosi 3c3d837cb7 Introduce primary actions (#15826)
- These actions are displayed in the accent color
- Added new context store state
`contextStoreIsPageInEditModeComponentState`
- Reverted the order in which the actions are displayed (the first
action should appear to the right of the top bar action menu)



https://github.com/user-attachments/assets/3a0769cf-61ed-4619-8c4d-e3a01765b63c
2025-11-20 10:57:33 +01:00
Raphaël Bosi 3b868c3d2a Page layout refactoring (#14535)
In this PR:
- Refactored the page layout renderer
- Converted all the states to component states
- Removed the page layout edition in settings

TODOs in next PRs:
- Fix bug with the drag selector not taking the scroll into account to
display the dragged area
- Readd the tab edition in edit mode
2025-09-16 15:42:51 +00:00
Félix Malfait f7cde28dd6 🔧 Restore PRs #14348 and #14352 that were reverted by PR #14347 (#14359)
## Problem

**CRITICAL:** Two PRs were accidentally reverted when PR #14347 "Prevent
csv export injections" was merged:

1. **PR #14348** "[Page Layout] - Review Refactor" -  **RESTORED**
2. **PR #14352** "Fix wrong path used by backend" -  **RESTORED**

## Root Cause Analysis

During the merge of PR #14347, there was a complex merge conflict with
PR #14352 "Fix wrong path used by backend". The merge commit
`324d7204bb` in the PR #14347 branch brought in changes from PR #14352,
but during the conflict resolution, **BOTH PR #14348 and PR #14352's
changes were accidentally overwritten**.

## What This PR Restores

This PR restores **BOTH** PRs by cherry-picking their commits:

###  PR #14348 Changes Restored:
- `GraphWidgetRenderer.tsx` - was deleted, now restored
- `WidgetRenderer.tsx` - was missing, now restored  
- `SettingsPageLayoutTabsInstanceId.ts` - was deleted, now restored
- `useUpdatePageLayoutWidget.ts` - was renamed back, now restored with
correct name
- Multiple test files that were deleted
- Several hook files that were renamed/reverted
- File renames: `usePageLayoutWidgetUpdate.ts` →
`useUpdatePageLayoutWidget.ts`
- Hook refactoring and test file organization
- Page layout component improvements

###  PR #14352 Changes Restored:
- **Types moved to twenty-shared:**
  - `packages/twenty-shared/src/types/AppBasePath.ts`  RESTORED
  - `packages/twenty-shared/src/types/AppPath.ts`  RESTORED
  - `packages/twenty-shared/src/types/SettingsPath.ts`  RESTORED
- **Navigation utilities moved to twenty-shared:**
- `packages/twenty-shared/src/utils/navigation/getAppPath.ts`  RESTORED
- `packages/twenty-shared/src/utils/navigation/getSettingsPath.ts` 
RESTORED
- **200+ import statements updated** across the codebase to use
twenty-shared
- **Old type files deleted** from twenty-front/src/modules/types/

## Evidence of Complete Restoration

**Before (reverted state):**
-  Types were in `packages/twenty-front/src/modules/types/`
-  Page layout files missing
-  Hook files incorrectly named

**After (this PR):**
-  Types correctly in `packages/twenty-shared/src/types/`
-  All page layout files restored
-  Hook files correctly named
-  All import statements updated

## Verification

**Total changes:**
- PR #14348: 36 files changed, 863 insertions(+), 442 deletions(-)
- PR #14352: 243 files changed, 492 insertions(+), 461 deletions(-)
- **Combined: 279 files changed, 1355 insertions(+), 903 deletions(-)**

## Impact

This completely restores both PRs that were accidentally lost, ensuring:
1. Page layout refactoring work is back
2. Type organization and path utilities are correctly in twenty-shared
3. Backend email paths work correctly again
4. No functionality is lost

Fixes the reversion caused by the merge conflict in PR #14347.

---------

Co-authored-by: nitin <142569587+ehconitin@users.noreply.github.com>
2025-09-08 21:48:13 +02:00
Félix Malfait cebcf4f1f5 Prevent csv export injections (#14347)
**Small Security Issue:** CSV exports were vulnerable to formula
injection attacks when users entered values starting with =, +, -, or @.
(only happens if a logged-in user injects corrupted data)

Solution:
- Added ZWJ (Zero-Width Joiner) protection that prefixes dangerous
values with invisible Unicode character
- This is the best way to preserve original data while preventing Excel
from executing formulas
- Added import cleanup to restore original values when re-importing
 
Changes:
- New sanitizeValueForCSVExport() function for security
- Updated all CSV export paths to use both security + formatting
functions
- Added comprehensive tests covering attack vectors and international
characters
- Also added cursor rules for better code consistency

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-09-08 17:57:46 +02:00
Félix Malfait 502bd07db9 Fix wrong path used by backend (#14352)
After moving a section on the frontend, this broke the path that was
sent by email on the backend.
This kind of error comes back every ~2-3 month under different forms so
we need a more robust solution: I moved routes to the shared folder,
that way we will share one common source of truth between the frontend
and the backend.

Fixes #14343
2025-09-08 16:07:13 +02:00
nitin 1b2f079359 Page Layout - Addition of widgets (#14184)
https://github.com/user-attachments/assets/130f12d7-5cef-4b83-912f-a9d42241f69f

~~This could be considered a POC 😅~~

addressing - 
https://github.com/twentyhq/core-team-issues/issues/1400
https://github.com/twentyhq/core-team-issues/issues/1403
2025-09-02 10:20:28 +00:00
Félix Malfait 464a480043 Continue ESLINT9 Migration (#13795)
Might already fix #13793
2025-08-10 23:25:58 +02:00
nitin a8fb039e65 poc - cal.com integration in onboarding flow (#12530) 2025-06-19 15:27:38 +05:30
Etienne 081376f594 Onboarding - add nextPath logic after email verification (#12342)
Context :
Plan choice [on pricing page on website](https://twenty.com/pricing)
should redirect you the right plan on app /plan-required page (after
sign in), thanks to query parameters and BillingCheckoutSessionState
sync.
With email verification, an other session starts at CTA click in
verification email. Initial BillingCheckoutSessionState is lost and user
can't submit to the plan he choose.

Solution : 
Pass a nextPath query parameter in email verification link

To test : 
- Modify .env to add IS_BILLING_ENABLED (+ reset db + sync billing) +
IS_EMAIL_VERIFICATION_REQUIRED
- Start test from this page
http://app.localhost:3001/welcome?billingCheckoutSession={%22plan%22:%22ENTERPRISE%22,%22interval%22:%22Year%22,%22requirePaymentMethod%22:true}
- After verification, check you arrive on /plan-required page with
Enterprise plan on a yearly interval (default is Pro/monthly).

closes https://github.com/twentyhq/twenty/issues/12288
2025-05-28 17:20:31 +00:00
Charles Bochet d6ae4d59f0 Various fixes charles 3 (#11573) 2025-04-15 13:45:04 +02:00
Félix Malfait e8db0176a1 Remove recoil sync (#11569)
Recoil-sync was causing issues with Firefox, replacing it with a simpler
mechanism to hydrate variables on page load

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-15 13:32:12 +02:00
Charles Bochet 15eb96337f Various fixes (#11567)
In this PR:
- Remove SignUpLoading blank screen by an empty dark overlay =>
VerifyEffect
- Add ModalContent from pages themselves instead of using it the Layout.
This allow for empty dark overlay without showing an empty modal with
padding
2025-04-14 17:24:16 +02:00
Lucas Bordeau f8f11894e8 Introduce generic way to close any open dropdown on page location change (#11504)
In this PR we introduce a generic way to close any open dropdown
idempotently, with the hook useCloseAnyOpenDropdown.

We also introduce a generic hook useExecuteTasksOnAnyLocationChange that
is called each time the page location changes.

This way we can close any open dropdown when the page location changes,
which fixes the original issue of having advanced filter dropdown
staying open between page changes.

Fixes https://github.com/twentyhq/core-team-issues/issues/659
2025-04-10 16:00:50 +02:00
Guillim 10e140495c Fixing Singup sequence FLASHING💥 (#11371)
After investiagting the different options ([see related
issue](https://github.com/twentyhq/core-team-issues/issues/660#issuecomment-2766030972))
I decided to add a "Verify Component" and a to build a custom Layout for
this route.

Reason I cannot use the default one is to have all preloaded once the
user changes website and lands on the verify route.

Reason I did not modify the DefaultLayout to match our need is that is
would require many changes in order to avoid preloading states for our
specific usecase.

Fixes https://github.com/twentyhq/core-team-issues/issues/660

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-04 15:25:15 +00:00
Weiko 2fca60436b Add settingsPermission gate on the frontend (#10179)
## Context
With the new permissions system, we now need to hide some items from the
settings navigation and gate some routes so they can't be accessed
directly.
To avoid having to set permission gates in all the component pages, I'm
introducing wrapper at the route level and in the Navigation. This is
not required and is mostly for pages that are strictly mapped to a
single permission, for the rest we still need to use the different hooks
manually but it should avoid a bit of boilerplate for most of the cases.

- currentUserWorkspaceState to access settingsPermissions
- SettingsProtectedRouteWrapper in the router that can take a
settingFeature or a featureFlag as a gate logic, if the currentUser does
not have access to the settingFeature or the featureFlag is not enabled
they will be redirected to the profile page.
- SettingsNavigationItemWrapper & SettingsNavigationSectionWrapper. The
former will check the same logic as SettingsProtectedRouteWrapper and
not display the item if needed. The later will check if all
SettingsNavigationItemWrapper are not visible and hide itself if that's
the case.
- useHasSettingsPermission to get a specific permission state for the
current user
- useSettingsPermissionMap to get a map of all permissions with their
values for the current user
- useFeatureFlagsMap same but for featureFlags
2025-02-18 15:50:23 +01:00
Weiko 02ced028e5 add role assignment page (#10115)
## Context
This PR introduces the "assignment" tab in the Role edit page, currently
allowing admin users to assign workspace members to specific roles.

Note: For now, a user can only have one role and a modal will warn you
if you try to re-assign a user to a new role.

## Test
<img width="648" alt="Screenshot 2025-02-10 at 17 59 21"
src="https://github.com/user-attachments/assets/dabd7a17-6aca-4d2b-95d8-46182f53e1e8"
/>
<img width="668" alt="Screenshot 2025-02-10 at 17 59 33"
src="https://github.com/user-attachments/assets/802aab7a-db67-4f83-9a44-35773df100f7"
/>
<img width="629" alt="Screenshot 2025-02-10 at 17 59 42"
src="https://github.com/user-attachments/assets/277db061-3f05-4ccd-8a83-7a96d6c1673e"
/>
2025-02-11 14:51:31 +01:00
Antoine Moreaux 47487f5d1c feat(sso): fix saml + allow to use public invite with sso + fix invite page with multiple sso provider (#9963)
- Fix SAML issue
- Fix the wrong state on the Invite page when multiple SSO provider
exists
- Allow to signup with SSO and public invite link
- For OIDC, use the property upn to guess email for Microsoft and enable
oidc with a specific context in azure
- Improve error in OIDC flow when email not found
2025-02-03 17:48:25 +00:00
martmull 3ab193f298 Remove isServerlessFunctionSettingsEnabled feature flag (#9797)
Removes `isFunctionSettingsEnabled` feature flag
We consider this featureFlag as false for everyone. We decided to keep
the code in the code base for now
2025-01-22 22:39:52 +01:00
Félix Malfait 152902d1be New useNavigateApp (#9729)
Todo : 
- replace all instances of useNavigate(
- remove getSettingsPagePath
- add eslint rule to enfore usage of useNavigateApp instead of
useNavigate
2025-01-18 13:58:12 +01:00
Samyak Piya f722a2d619 Add Email Verification for non-Microsoft/Google Emails (#9288)
Closes twentyhq/twenty#8240 

This PR introduces email verification for non-Microsoft/Google Emails:

## Email Verification SignInUp Flow:

https://github.com/user-attachments/assets/740e9714-5413-4fd8-b02e-ace728ea47ef

The email verification link is sent as part of the
`SignInUpStep.EmailVerification`. The email verification token
validation is handled on a separate page (`AppPath.VerifyEmail`). A
verification email resend can be triggered from both pages.

## Email Verification Flow Screenshots (In Order):

![image](https://github.com/user-attachments/assets/d52237dc-fcc6-4754-a40f-b7d6294eebad)

![image](https://github.com/user-attachments/assets/263a4b6b-db49-406b-9e43-6c0f90488bb8)

![image](https://github.com/user-attachments/assets/0343ae51-32ef-48b8-8167-a96deb7db99e)

## Sent Email Details (Subject & Template):
![Screenshot 2025-01-05 at 11 56
56 PM](https://github.com/user-attachments/assets/475840d1-7d47-4792-b8c6-5c9ef5e02229)

![image](https://github.com/user-attachments/assets/a41b3b36-a36f-4a8e-b1f9-beeec7fe23e4)

### Successful Email Verification Redirect:

![image](https://github.com/user-attachments/assets/e2fad9e2-f4b1-485e-8f4a-32163c2718e7)

### Unsuccessful Email Verification (invalid token, invalid email, token
expired, user does not exist, etc.):

![image](https://github.com/user-attachments/assets/92f4b65e-2971-4f26-a9fa-7aafadd2b305)

### Force Sign In When Email Not Verified:

![image](https://github.com/user-attachments/assets/86d0f188-cded-49a6-bde9-9630fd18d71e)

# TODOs:

## Sign Up Process

- [x] Introduce server-level environment variable
IS_EMAIL_VERIFICATION_REQUIRED (defaults to false)
- [x] Ensure users joining an existing workspace through an invite are
not required to validate their email
- [x] Generate an email verification token
- [x] Store the token in appToken
- [x] Send email containing the verification link
  - [x] Create new email template for email verification
- [x] Create a frontend page to handle verification requests

## Sign In Process

- [x] After verifying user credentials, check if user's email is
verified and prompt to to verify
- [x] Show an option to resend the verification email

## Database

- [x] Rename the `emailVerified` colum on `user` to to `isEmailVerified`
for consistency

## During Deployment
- [x] Run a script/sql query to set `isEmailVerified` to `true` for all
users with a Google/Microsoft email and all users that show an
indication of a valid subscription (e.g. linked credit card)
- I have created a draft migration file below that shows one possible
approach to implementing this change:

```typescript
import { MigrationInterface, QueryRunner } from 'typeorm';

export class UpdateEmailVerifiedForActiveUsers1733318043628
  implements MigrationInterface
{
  name = 'UpdateEmailVerifiedForActiveUsers1733318043628';

  public async up(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      CREATE TABLE core."user_email_verified_backup" AS
      SELECT id, email, "isEmailVerified"
      FROM core."user"
      WHERE "deletedAt" IS NULL;
    `);

    await queryRunner.query(`
      -- Update isEmailVerified for users who have been part of workspaces with active subscriptions
      UPDATE core."user" u
      SET "isEmailVerified" = true
      WHERE EXISTS (
        -- Check if user has been part of a workspace through userWorkspace table
        SELECT 1 
        FROM core."userWorkspace" uw
        JOIN core."workspace" w ON uw."workspaceId" = w.id
        WHERE uw."userId" = u.id
        -- Check for valid subscription indicators
        AND (
          w."activationStatus" = 'ACTIVE'
          -- Add any other subscription-related conditions here
        )
      )
      AND u."deletedAt" IS NULL;
  `);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    await queryRunner.query(`
      UPDATE core."user" u
      SET "isEmailVerified" = b."isEmailVerified"
      FROM core."user_email_verified_backup" b
      WHERE u.id = b.id;
    `);

    await queryRunner.query(`DROP TABLE core."user_email_verified_backup";`);
  }
}

```

---------

Co-authored-by: Antoine Moreaux <moreaux.antoine@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-01-15 18:43:40 +01:00
Antoine Moreaux 5648c3b31c [refactor]: Remove isSSOEnabled logic throughout the codebase (#9462)
Eliminated all references to `isSSOEnabled` across the frontend,
backend, and configuration files. This change simplifies the codebase by
removing unnecessary feature flag checks, associated logic, and
environment variables. The SSO feature remains available without
reliance on this flag.
2025-01-10 14:45:35 +01:00
nitin e96ad9a1f2 Admin panel init (#8742)
WIP
Related issues - 
#7090 
#8547 
Master issue - 
#4499

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-28 13:43:11 +01:00
Antoine Moreaux 0f0a7966b1 feat(sso): allow to use OIDC and SAML (#7246)
## What it does
### Backend
- [x] Add a mutation to create OIDC and SAML configuration
- [x] Add a mutation to delete an SSO config
- [x] Add a feature flag to toggle SSO
- [x] Add a mutation to activate/deactivate an SSO config
- [x] Add a mutation to delete an SSO config
- [x] Add strategy to use OIDC or SAML
- [ ] Improve error management

### Frontend
- [x] Add section "security" in settings
- [x] Add page to list SSO configurations
- [x] Add page and forms to create OIDC or SAML configuration
- [x] Add field to "connect with SSO" in the signin/signup process
- [x] Trigger auth when a user switch to a workspace with SSO enable
- [x] Add an option on the security page to activate/deactivate the
global invitation link
- [ ] Add new Icons for SSO Identity Providers (okta, Auth0, Azure,
Microsoft)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2024-10-21 20:07:08 +02:00
Charles Bochet eccf0bf8ba Enforce front project structure through ESLINT (#7863)
Fixes: https://github.com/twentyhq/twenty/issues/7329
2024-10-20 20:20:19 +02:00