Commit Graph

101 Commits

Author SHA1 Message Date
Félix Malfait b470cb21a1 Upgrade Apollo Client to v4 and refactor error handling (#18584)
## Summary
This PR upgrades Apollo Client from v3.10.0 to v4 and refactors error
handling patterns across the codebase to use a new centralized
`useSnackBarOnQueryError` hook.

## Key Changes

- **Dependency Update**: Upgraded `@apollo/client` from `^3.10.0` to
`^3.11.0` in root package.json
- **New Hook**: Added `useSnackBarOnQueryError` hook for centralized
Apollo query error handling with snack bar notifications
- **Error Handling Refactor**: Updated 100+ files to use the new error
handling pattern:
  - Removed direct `ApolloError` imports where no longer needed
- Replaced manual error handling logic with `useSnackBarOnQueryError`
hook
- Simplified error handling in hooks and components across multiple
modules
- **GraphQL Codegen**: Updated codegen configuration files to work with
Apollo Client v3.11.0
- **Type Definitions**: Added TypeScript declaration file for
`apollo-upload-client` module
- **Test Updates**: Updated test files to reflect new error handling
patterns

## Notable Implementation Details

- The new `useSnackBarOnQueryError` hook provides a consistent way to
handle Apollo query errors with automatic snack bar notifications
- Changes span across multiple feature areas: auth, object records,
settings, workflows, billing, and more
- All changes maintain backward compatibility while improving code
maintainability and reducing duplication
- Jest configuration updated to work with the new Apollo Client version

https://claude.ai/code/session_019WGZ6Rd7sEHuBg9sTrXRqJ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 14:59:46 +01:00
Weiko 3f420c84d7 Fix Flow tab missing for workflow run (#18602)
## Context
Conditional tab rendering was recently introduced for system objects
that now have record page layouts. However Workflow run is a system
object and has a specific "Flow" tab that was not displayed anymore

## Before
<img width="1191" height="640" alt="Screenshot 2026-03-12 at 18 10 03"
src="https://github.com/user-attachments/assets/6f2c6319-6ddf-4906-a83c-0db8a27a8267"
/>

## After
<img width="1299" height="802" alt="Screenshot 2026-03-12 at 18 09 35"
src="https://github.com/user-attachments/assets/35e1e356-e995-43a2-9207-adc0f67cc426"
/>
2026-03-12 17:25:12 +00:00
Weiko c59f420d21 Hide tabs for system objects (#18583)
<img width="1286" height="793" alt="Screenshot 2026-03-12 at 13 57 16"
src="https://github.com/user-attachments/assets/bebfd23f-3172-424a-95ee-ba95358a6196"
/>
2026-03-12 14:46:15 +01:00
Thomas Trompette 2af3121c51 Fix dashboard creation + role permission page design (#18565)
1. **Creating a new dashboard crashes with "Tab not found"** and widgets
can't be added after the crash is prevented.

**Root cause:** `initializePageLayout` wrapped both the persisted and
draft state updates behind an `isDeeplyEqual` guard. After navigation,
`resetPageLayoutEditMode` resets the draft atom to its default but
leaves the persisted atom untouched. On re-initialization,
`isDeeplyEqual` returns true (persisted unchanged), so the draft is
never repopulated. But edit mode is still activated.

**Fix**: Move the draft store.set outside the isDeeplyEqual guard so
it's always set on initialization. Also add a defensive check in
`PageLayoutRendererContent` to prevent the crash when activeTabId
doesn't match available tabs.


https://github.com/user-attachments/assets/bcd69866-63eb-4e5e-a1bb-655e71ba6dc5

2. **Permission role page design broken**
Before
<img width="573" height="1130" alt="role-page-broken"
src="https://github.com/user-attachments/assets/09f60fd2-ef08-4133-bb28-034b15579481"
/>

After
<img width="573" height="266" alt="Capture d’écran 2026-03-11 à 14 25
55"
src="https://github.com/user-attachments/assets/c34f9993-51e1-4108-a7e6-f434f558edfd"
/>
2026-03-11 17:57:54 +00:00
Thomas Trompette 6e628bb751 Fix add more tab bottom separator (#18529)
Adding a full height prop

Before 
<img width="409" height="139" alt="Capture d’écran 2026-03-10 à 14 06
13"
src="https://github.com/user-attachments/assets/6f9bb8d1-8834-44b9-a0cf-1253dffc9ea0"
/>

After
<img width="409" height="139" alt="Capture d’écran 2026-03-10 à 14 06
33"
src="https://github.com/user-attachments/assets/1d3551fe-0b4b-4bbf-88e4-fd466c9bb704"
/>
2026-03-10 18:08:51 +01:00
neo773 dd58eb6814 Fix linaria css regressions (#18492)
before
<img width="310" height="60" alt="SCR-20260309-ctul"
src="https://github.com/user-attachments/assets/7141d495-b8f2-4fd6-bf3b-36bb2b11d1aa"
/>

after (fixed icon alignment)
<img width="235" height="67" alt="SCR-20260309-ctel"
src="https://github.com/user-attachments/assets/36078039-93dc-4c2c-b553-0bbcde4cb81c"
/>

before
<img width="637" height="318" alt="SCR-20260309-ctnp"
src="https://github.com/user-attachments/assets/34b66129-d619-43a2-8896-aa92b511644e"
/>

after (fixed chart colors)
<img width="650" height="317" alt="SCR-20260309-cthj"
src="https://github.com/user-attachments/assets/82c095b1-34bb-4ae4-a8f2-7a3746a31b0a"
/>


before



<img width="909" height="650" alt="image"
src="https://github.com/user-attachments/assets/14649aed-bfa8-4b9d-aa35-f4de2bfaddd6"
/>


after (fixed buttons text color)
<img width="930" height="646" alt="SCR-20260309-csob"
src="https://github.com/user-attachments/assets/c724a849-dabe-406c-8258-0674211374f2"
/>

before

<img width="544" height="141" alt="image"
src="https://github.com/user-attachments/assets/815c3b70-2f7c-42ca-8a32-3fbd5fe4c556"
/>


after (fixed missing border on :active state)

<img width="554" height="145" alt="image"
src="https://github.com/user-attachments/assets/845b1afd-36b6-4ae4-b6ef-c49ccbd89c10"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-10 16:26:53 +01:00
Weiko c433b2b73f Implement page layout override (#18472) 2026-03-09 17:21:08 +00:00
Baptiste Devessier a9696705c1 Make all widgets of record page layouts non-editable except Fields widgets (#18471)
## Demo


https://github.com/user-attachments/assets/d5746f81-beae-4c46-abfe-9723da9bcc1d
2026-03-09 09:06:07 +00:00
Arun 59029a0035 [Fix] : Dragged element is considered to be part of a dropdown in dashboard tab list (#18414)
Fixes #15327

The issue occurred because the drag clone's visual state was previously
tied strictly to hovering over the `VISIBLE_TABS` boundaries. When a tab
was dragged outside this area (such as the last tab naturally crossing
into the `MORE_BUTTON` hover zone), the drag clone incorrectly fell back
to the dropdown menu item style.

We fixed this by making the `isHoveringTabList` logic more robust.
Instead of enforcing the tab style only within the `VISIBLE_TABS`
boundary, the dropdown style is now strictly restricted to the
`OVERFLOW_TABS` boundary.

With this change:
- Visible tabs successfully maintain their appearance when dragged
anywhere outside the dropdown.
- Dropdown tabs correctly transition to the normal tab style when
dragged out of the dropdown area, improving UX.



https://github.com/user-attachments/assets/9474e4c1-26a8-46e3-b9ee-4c6dbd8a4ea6

---------

Co-authored-by: Arun kumar <arunkumar@Aruns-MacBook-Air.local>
Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: nitin <142569587+ehconitin@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-06 14:35:32 +00:00
Charles Bochet ef499b6d47 Re-enable disabled lint rules and right-size CI runners (#18461)
## Summary

- Re-enable one lint rule that was temporarily disabled during the
ESLint-to-Oxlint migration:
- **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578
violations auto-fixed across 390 files
- Document why **`typescript/consistent-type-imports`** cannot be
auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata`
for DI, so converting constructor parameter imports to `import type`
erases them at compile time and breaks dependency injection at runtime
- Right-size CI runners, reducing 8-core usage from 18 jobs to 3:

| Change | Jobs | Rationale |
|--------|------|-----------|
| **Keep 8-core** | `ci-merge-queue/e2e-test`,
`ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing
max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) |
| **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation,
test, integration-test), `ci-front/front-sb-test`,
`ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into
10-12 parallel instances, I/O-bound (DB/Redis), or moderate single
builds |
| **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight
(build + curl health check) |
| **Removed** | `ci-front/front-chromatic-deployment` | Dead code —
permanently disabled with `if: false` |

- Fix merge queue CI issues:
- **Concurrency**: Use `merge_group.base_ref` instead of unique merge
group ref so new queue entries cancel previous runs
- **Required status checks**: Add `merge_group` trigger to all 6
required CI workflows (front, server, shared, website, docker-compose,
sdk) with `changed-files-check` auto-skipped for merge_group events —
status check jobs auto-pass without re-running full CI
- **Build caching**: Add Nx build cache restore/save to E2E test job
with fallback to `main` branch cache for faster frontend and server
builds

## Test plan

- [ ] CI passes on this PR (verifies lint rule auto-fix works)
- [ ] Verify 4-core runner jobs complete within their 30-minute timeouts
- [ ] Verify merge queue status checks auto-pass (ci-front-status-check,
ci-server-status-check, etc.)
- [ ] Verify merge queue E2E concurrency cancels previous runs when a
new PR enters the queue
2026-03-06 13:33:02 +00: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
Charles Bochet 4797f97a95 fix: vertical alignment of +N More tab overflow button (#18446)
## Summary
- Add `align-items: center` to tab list `StyledContainer` so the
overflow button aligns vertically with tabs
- Remove ineffective `> * { height }` hack from `TabMoreButton` (was
being reset by `all: unset` in `StyledTabButton`)

## Test plan
- Open a record detail page with enough tabs to trigger the "+N More"
overflow
- Verify the overflow button is vertically centered with the visible
tabs
2026-03-05 22:20:14 +01:00
Charles Bochet c53a13417e Remove all styled(Component) patterns in favor of parent wrappers and props (#18430)
## Summary

Eliminates all ~350 `styled(Component)` usages across `twenty-front` and
`twenty-ui` (212 files changed). Each was replaced following these
rules:

- **Margin/layout CSS** (margin, padding, flex, align-self, width) →
wrapped in a `styled.div`/`styled.span` parent container
- **Third-party components** (Link, TextareaAutosize,
ReactPhoneNumberInput, Handle, etc.) → parent container with child CSS
selectors (`> a`, `> textarea`, `> input`, etc.)
- **Intrinsic behavior via existing props** (TableRow
`gridTemplateColumns`, TableCell `color`/`align`) → replaced
`styled(TableRow)` / `styled(TableCell)` with direct prop usage
- **Other visual overrides on twenty-ui components** (Card, Section,
TabList, Button, MenuItem, ScrollWrapper, etc.) → parent wrappers with
`> div` / `> *` child selectors
- **Extending styled.div/span** → merged all CSS into a single
`styled.div`/`styled.span`

Also adds `overflow: hidden` to parent containers wrapping
`ScrollWrapper` so scroll activates correctly with the new wrapper
structure.

### Migration patterns

| Before | After |
|--------|-------|
| `styled(Avatar)` with `margin-right` | `<StyledAvatarContainer><Avatar
/></StyledAvatarContainer>` |
| `styled(Link)` with `text-decoration: none` |
`<StyledLinkContainer><Link /></StyledLinkContainer>` with `> a { ... }`
|
| `styled(TableRow)` with `grid-template-columns` | `<TableRow
gridTemplateColumns="..." />` |
| `styled(TableCell)` with `color` / `align` | `<TableCell color={...}
align="right" />` |
| `styled(Card)` with `margin-top` | `<StyledCardContainer><Card
/></StyledCardContainer>` |
| `styled(TabList)` with `background` |
`<StyledTabListContainer><TabList /></StyledTabListContainer>` with `>
div { ... }` |
| `styled(StyledBase)` extending a `styled.div` | Single merged
`styled.div` with all styles inlined |
2026-03-05 18:16:25 +01:00
nitin 5853891b02 refactor!: rename Command Menu page/navigation layer to Side Panel (#18393) 2026-03-05 15:46:31 +01:00
Charles Bochet 647c32ff3e Deprecate runtime theme objects in favor of CSS variables (#18402)
## Summary

- **Eliminate `ICON_SIZES` / `ICON_STROKES` constants**: all icon
dimensions are now resolved at runtime via
`resolveThemeVariableAsNumber(themeCssVariables.icon.size.X)`, ensuring
values always come from computed CSS variables
- **No more consumer imports from `twenty-ui/theme`**: moved
`ColorSchemeContext`, `ColorSchemeProvider`, `ThemeColor`,
`MAIN_COLOR_NAMES`, `getNextThemeColor`, `AnimationDuration` to
`twenty-ui/theme-constants`
- **Remove `ThemeContext` / `ThemeContextProvider` / `ThemeProvider` /
`ThemeType`**: replaced across ~300 files with `themeCssVariables` (for
CSS contexts) or `resolveThemeVariable` / `resolveThemeVariableAsNumber`
(for JS runtime values)
- **Simplify provider chain**: only `ColorSchemeProvider` remains — it
toggles `light`/`dark` class on `document.documentElement` and provides
`colorScheme` via React context
- **Fix pre-existing test failures**: `useIcons.test.ts`
(non-configurable ES module spy) and
`turnRecordFilterGroupIntoGqlOperationFilter.test.ts`
(`Omit<RecordFilter, 'id'>` type mismatch)

### Theme access pattern (before → after)

| Context | Before | After |
|---------|--------|-------|
| CSS (Linaria) | `${({ theme }) => theme.font.color.primary}` |
`${themeCssVariables.font.color.primary}` |
| JS runtime (icon size, animation) | `theme.icon.size.md` /
`ICON_SIZES.md` |
`resolveThemeVariableAsNumber(themeCssVariables.icon.size.md)` |
| Color scheme check | `theme.name === 'dark'` |
`useContext(ColorSchemeContext).colorScheme === 'dark'` |
2026-03-05 14:39:01 +01:00
martmull 999dcd4468 Increase size of input in test setting logic function tab (#18369)
## Before
<img width="1031" height="836" alt="image"
src="https://github.com/user-attachments/assets/475ca1be-f7c4-49d0-b329-649dbe8da489"
/>


## After

<img width="1195" height="862" alt="image"
src="https://github.com/user-attachments/assets/b1bac131-e562-4439-8f8e-bda4d6e2a646"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-04 16:49:13 +01:00
Raphaël Bosi b11f77df2a [FRONT COMPONENTS] Introduce conditionalAvailabilityExpression to command menu items (#18319)
## PR Description

- Uses `expr-eval` to enable front components (SDK plugins) to define
conditional availability as declarative expressions.
- Moves shared types and constants to `twenty-shared`
- Introduces a `conditionalAvailabilityExpression` field on
`CommandMenuItemEntity`, allowing command menu items to store an
`expr-eval` compatible expression string that is evaluated against a
CommandMenuContext to determine if the item should be shown.
- Creates an esbuild transform plugin
`conditional-availability-transform-plugin` in `twenty-sdk` that
converts TypeScript conditional availability expressions into
`expr-eval` compatible syntax at build time, so SDK developers can write
natural TS expressions that get transformed to evaluable strings.
- Removes deprecated `forceRegisteredActionsByKey` state and its usage.
- Creates `useCommandMenuContext` hook that builds the full
`CommandMenuContext` object from React state, which is then passed to
`useCommandMenuItemFrontComponentActions` for evaluating conditional
availability expressions.
2026-03-04 16:33:58 +01:00
Charles Bochet 3bfdc2c83f chore(twenty-front): migrate command-menu, workflow, page-layout and UI modules from Emotion to Linaria (PR 4-6/10) (#18342)
## Summary

Continues the Emotion → Linaria migration (PR 4-6 from the [migration
plan](docs/emotion-to-linaria-migration-plan.md)). Migrates **311
files** across four module groups:

| Module | Files |
|---|---|
| command-menu | 53 |
| workflow | 84 |
| page-layout | 84 |
| UI (partial - first ~80 files) | ~80 |
| twenty-ui (TEXT_INPUT_STYLE) | 1 |
| misc (hooks, keyboard-shortcut-menu, file-upload) | ~9 |

### Migration patterns applied

- `import styled from '@emotion/styled'` → `import { styled } from
'@linaria/react'`
- `import { useTheme } from '@emotion/react'` → `import { useContext }
from 'react'` + `import { ThemeContext } from 'twenty-ui/theme'`
- `${({ theme }) => theme.X.Y.Z}` → `${themeCssVariables.X.Y.Z}` (static
CSS variables)
- `theme.spacing(N)` → `themeCssVariables.spacing[N]`
- `styled(motion.div)` → `motion.create(StyledBase)` (11 components)
- `styled(Component)<TypeParams>` → wrapper div approach for non-HTML
elements
- Multi-declaration interpolations split into one CSS property per
interpolation
- Interpolation return types fixed (`&&` → ternary `? : ''`)
- `TEXT_INPUT_STYLE` converted from function to static string constant
(backward compatible)
- Emotion `<Global>` replaced with `useEffect` style injection
- Complex runtime-dependent styles use CSS custom properties via
`style={}` prop

### After this PR

- **Remaining files**: ~400 (object-record: ~160, settings: ~200, UI:
~44)
- **No breaking changes**: CSS variables resolve identically to the
previous Emotion theme values
2026-03-03 16:42:03 +01:00
Charles Bochet bc4ae35bc4 Rework atom naming (#18240)
## Summary

- **Enhanced the `matching-state-variable` ESLint rule** to enforce
consistent naming for `ComponentState`, `FamilyState`, and
`ComponentFamilyState` hooks — previously it only covered `useAtomState`
and `useAtomStateValue`
- **The rule now checks 12 hooks** across three categories: value hooks
(`useAtomComponentStateValue`, `useAtomFamilyStateValue`, etc.), state
hooks (`useAtomComponentState`, `useAtomComponentFamilyState`), and
setter hooks (`useSetAtomState`, `useSetAtomComponentState`,
`useSetAtomFamilyState`, `useSetAtomComponentFamilyState`)
- **Fixed all 225 resulting lint violations** across 151 files, renaming
variables to match their state atom names (e.g. `currentViewId` →
`contextStoreCurrentViewId`, `selectedRecord` → `recordStore`). Cases
where the same state is accessed with different family keys/instance IDs
are suppressed with `eslint-disable-next-line`.

## Naming convention

| Hook | State argument | Valid | Invalid |
|------|---------------|-------|---------|
| `useAtomStateValue` | `fooState` | `const foo = ...` | `const bar =
...` |
| `useAtomComponentStateValue` | `fooComponentState` | `const foo = ...`
| `const bar = ...` |
| `useAtomFamilyStateValue` | `fooFamilyState` | `const foo = ...` |
`const bar = ...` |
| `useAtomComponentFamilyStateValue` | `fooComponentFamilyState` |
`const foo = ...` | `const bar = ...` |
| `useAtomState` | `fooState` | `const [foo, setFoo] = ...` | `const
[bar, setBar] = ...` |
| `useAtomComponentState` | `fooComponentState` | `const [foo, setFoo] =
...` | `const [bar, setBar] = ...` |
| `useAtomComponentFamilyState` | `fooComponentFamilyState` | `const
[foo, setFoo] = ...` | `const [bar, setBar] = ...` |
| `useSetAtomState` | `fooState` | `const setFoo = ...` | `const setBar
= ...` |
| `useSetAtomComponentState` | `fooComponentState` | `const setFoo =
...` | `const setBar = ...` |
| `useSetAtomFamilyState` | `fooFamilyState` | `const setFoo = ...` |
`const setBar = ...` |
| `useSetAtomComponentFamilyState` | `fooComponentFamilyState` | `const
setFoo = ...` | `const setBar = ...` |
2026-02-25 22:28:25 +01:00
Charles Bochet d81f006979 Rename Jotai state hooks and utilities to consistent Atom-based naming (#18209)
## Summary

Rename all Jotai-based state management hooks and utilities to a
consistent naming convention that:
1. Removes legacy Recoil naming (`useRecoilXxxV2`, `createXxxV2`)
2. Always includes `Atom` in the name to distinguish from jotai native
hooks
3. Follows a consistent ordering: `Atom` → `Component` → `Family` →
`Type` (`State`/`Selector`)
4. Includes the type qualifier (`State` or `Selector`) in all
value-reading hooks to avoid naming conflicts with jotai's native
`useAtomValue`

## Naming Convention

**Hooks**:
`use[Set]Atom[Component][Family][State|Selector][Value|State|CallbackState]`
**Utils**: `createAtom[Component][Family][State|Selector]`

## Changes

### Hooks renamed (definition files + all usages across ~1,500 files):

| Old Name (Recoil) | Intermediate (Atom) | Final Name |
|---|---|---|
| `useRecoilValueV2` | `useAtomValue` | **`useAtomStateValue`** |
| `useRecoilStateV2` | `useAtomState` | `useAtomState` |
| `useSetRecoilStateV2` | `useSetAtomState` | `useSetAtomState` |
| `useFamilyRecoilValueV2` | `useFamilyAtomValue` |
**`useAtomFamilyStateValue`** |
| `useSetFamilyRecoilStateV2` | `useSetFamilyAtomState` |
**`useSetAtomFamilyState`** |
| `useFamilySelectorValueV2` | `useFamilySelectorValue` |
**`useAtomFamilySelectorValue`** |
| `useFamilySelectorStateV2` | `useFamilySelectorState` |
**`useAtomFamilySelectorState`** |
| `useRecoilComponentValueV2` | `useAtomComponentValue` |
**`useAtomComponentStateValue`** |
| `useRecoilComponentStateV2` | `useAtomComponentState` |
`useAtomComponentState` |
| `useSetRecoilComponentStateV2` | `useSetAtomComponentState` |
`useSetAtomComponentState` |
| `useRecoilComponentFamilyValueV2` | `useAtomComponentFamilyValue` |
**`useAtomComponentFamilyStateValue`** |
| `useRecoilComponentFamilyStateV2` | `useAtomComponentFamilyState` |
`useAtomComponentFamilyState` |
| `useSetRecoilComponentFamilyStateV2` |
`useSetAtomComponentFamilyState` | `useSetAtomComponentFamilyState` |
| `useRecoilComponentSelectorValueV2` | `useAtomComponentSelectorValue`
| `useAtomComponentSelectorValue` |
| `useRecoilComponentFamilySelectorValueV2` |
`useAtomComponentFamilySelectorValue` |
`useAtomComponentFamilySelectorValue` |
| `useRecoilComponentStateCallbackStateV2` |
`useAtomComponentStateCallbackState` |
`useAtomComponentStateCallbackState` |
| `useRecoilComponentSelectorCallbackStateV2` |
`useAtomComponentSelectorCallbackState` |
`useAtomComponentSelectorCallbackState` |
| `useRecoilComponentFamilyStateCallbackStateV2` |
`useAtomComponentFamilyStateCallbackState` |
`useAtomComponentFamilyStateCallbackState` |
| `useRecoilComponentFamilySelectorCallbackStateV2` |
`useAtomComponentFamilySelectorCallbackState` |
`useAtomComponentFamilySelectorCallbackState` |

### Utilities renamed:

| Old Name (Recoil) | Final Name |
|---|---|
| `createStateV2` | **`createAtomState`** |
| `createFamilyStateV2` | **`createAtomFamilyState`** |
| `createSelectorV2` | **`createAtomSelector`** |
| `createFamilySelectorV2` | **`createAtomFamilySelector`** |
| `createWritableSelectorV2` | **`createAtomWritableSelector`** |
| `createWritableFamilySelectorV2` |
**`createAtomWritableFamilySelector`** |
| `createComponentStateV2` | **`createAtomComponentState`** |
| `createComponentFamilyStateV2` | **`createAtomComponentFamilyState`**
|
| `createComponentSelectorV2` | **`createAtomComponentSelector`** |
| `createComponentFamilySelectorV2` |
**`createAtomComponentFamilySelector`** |

## Details

- All definition files renamed to match new convention
- All import paths and usages updated across the entire `twenty-front`
package
- Jotai's native `useAtomValue` is aliased as `useJotaiAtomValue` in the
wrapper hook to avoid collision
- Legacy Recoil files in `state/utils/` and `component-state/utils/`
left untouched (separate naming scope)
- Typecheck passes cleanly
2026-02-25 01:55:46 +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
Raphaël Bosi 7da8450075 [FRONT COMPONENTS] Headless components (#18096)
## Description

- Add `isHeadless` field to `FrontComponent` entity so front components
can run without rendering UI in the command menu
- Introduce headless front component mounting logic:
`HeadlessFrontComponentMountRoot` at the application root,
`useMountHeadlessFrontComponent`, and `useUnmountHeadlessFrontComponent`
hooks to mount/unmount headless components
- Expand the SDK with new action components (`Action`, `ActionLink`,
`ActionOpenSidePanelPage`) and host communication functions
(`openSidePanelPage`, `unmountFrontComponent`)
- Move `CommandMenuPages` type to twenty-shared so the SDK can reference
it for side panel navigation

## Video QA



https://github.com/user-attachments/assets/4f9e3bb1-fcd1-42be-b3f4-a97e80c2add2
2026-02-20 14:14:42 +00: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
Charles Bochet 1a13258302 Keep migrating to jotai (#18064)
And we continue!
2026-02-19 12:10:02 +01:00
Baptiste Devessier 963f2de864 Translate page layout tab title (#17975)
> [!NOTE]
> The improvement will only fully work once all tabs get translated. 

## When using the front-end mocks


https://github.com/user-attachments/assets/cf7dc0fb-9438-4e18-841e-47558ff71474

## When loading page layout information from database


https://github.com/user-attachments/assets/d2c9d98b-97e2-4629-aa6c-53f3f3713733

## When editing dashboard


https://github.com/user-attachments/assets/c6ae3a7a-f05f-48ea-8b33-8f689e3f71f7

Closes
https://github.com/twentyhq/twenty/issues/17950#issuecomment-3902782952
2026-02-17 15:26:28 +00:00
PandaMan befbcef824 fix: prevent tab synchronization between different records (#17559)
Fixes issue where tabs were synchronized when opening two records of the
same type in show page and side panel.

The root cause was that tab instance IDs were only based on
`pageLayoutId`, causing all records using the same page layout to share
the same tab state.

This change includes the record ID in the tab instance ID, making tabs
unique per record while maintaining backward compatibility for cases
where no record ID is available.

Fixes #17522

---------

Co-authored-by: Eruis <github@eruis.example>
2026-02-13 13:04:07 +00:00
Charles Bochet b456f79167 Reduce leak between gql schema (#17878)
## Reduce type leakage between GraphQL schemas

### Why

Twenty runs two separate GraphQL schemas: **core** and **metadata**.
NestJS's `@nestjs/graphql` uses a global `TypeMetadataStorage` that
accumulates all decorated types across all modules. When each schema is
built, every registered type leaks into both schemas regardless of which
module it belongs to.

This means the core schema's generated TypeScript
(`generated/graphql.ts`) contained ~2,700 lines of types that only
belong to the metadata schema (and vice versa). This creates confusion
about type ownership, inflates generated code, and makes it harder to
reason about which API surface each schema actually exposes.

### How

**1. Patch `@nestjs/graphql` to support schema-scoped type resolution**

- **(Already done)** Added a `resolverSchemaScope` option to
`GqlModuleOptions`, allowing each schema to declare a scope (e.g.
`'metadata'`)
- `ResolversExplorerService` now filters resolvers by a
`RESOLVER_SCHEMA_SCOPE` metadata key, so each schema only sees its own
resolvers
- `GraphQLSchemaFactory` now performs a **reachability walk**
(`computeReachableTypes`) starting from scoped resolver return types and
arguments, only including types that are transitively referenced —
handling unions, interfaces, and prototype chains
- Type definition storage and orphaned reference registry are cleared
between schema builds to prevent cross-contamination

**2. Register `ClientConfig` as orphaned type in metadata schema**

Since `ClientConfig` is needed in the metadata schema but not directly
returned by a resolver, it's explicitly declared via
`buildSchemaOptions.orphanedTypes`.

**3. Regenerate frontend types and fix imports**

- `generated/graphql.ts` shrank by ~2,700 lines (types moved to where
they belong)
- `generated-metadata/graphql.ts` gained types like `ClientConfig` that
were previously missing
- ~500 frontend files updated to import from the correct generated file
2026-02-12 10:58:52 +01:00
Baptiste Devessier b250de216e Remove the code of old show pages (#17811)
Closes https://github.com/twentyhq/core-team-issues/issues/2213
2026-02-10 09:10:00 +00:00
Baptiste Devessier 617f634b6d Use backend types in Record Page Layouts' frontend (#17794) 2026-02-09 14:36:02 +00:00
Baptiste Devessier 5b701f5ba4 Never display broken relations in record page layouts (#17738)
We generate Field widgets for relations on-the-fly, when a record page
layout is first requested by the user. When the user changed their data
model and then returned to a record page layout, the Field widgets
weren't updated. **This PR ensures Field widgets are recomputed when
relations change.**

Future subjects:

- Now that we will fetch the configuration from the backend and start
storing updates, we will have to think about how we deal with these
generated relation Field widgets.

## Before


https://github.com/user-attachments/assets/99d53b19-b231-435f-b14f-4473ba269ad2

## After


https://github.com/user-attachments/assets/357d956d-8b3b-448c-a983-82569a7dd0a0

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-05 14:07:04 +00:00
Copilot 28763428f6 Differentiate edit mode behavior for record pages vs dashboards (#17550)
Temporary disable tabs edition for record page layouts


https://github.com/user-attachments/assets/c1f5d7fd-f125-4fb0-bf9c-96fadec14cd2

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Devessier <29370468+Devessier@users.noreply.github.com>
Co-authored-by: Baptiste Devessier <baptiste@devessier.fr>
2026-02-02 13:28:51 +00:00
Baptiste Devessier b15d092abd Record page layout edition frontend (#17519)
Hidden behind a new feature flag:
`IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED`


https://github.com/user-attachments/assets/112f5a8d-0dd0-4b9f-8825-9980db35fcbd
2026-01-29 11:13:09 +00:00
Baptiste Devessier f33b8e12f4 Fix error "No widget found in canvas layout" (#17512)
Fix https://github.com/twentyhq/twenty/issues/17507

The canvas layout mode is expected to render a single widget.
Previously, we threw an error when trying to render a canvas layout with
no widgets at all. This worked fine when we immediately rendered a
widget that used a single-widget canvas layout.

However, the active tab ID is shared across all page layouts with the
same ID, which doesn’t work well with conditional display. The available
tabs may depend on conditions such as the device displaying the page.
For example, when displaying a Note on the show page, the Note widget
appears on a separate tab. On mobile and in the side panel, however, it
is moved to the Home tab.

After that, if the user opens a Note in the side panel, the default
active tab might be the Note tab, which uses a _canvas_ layout mode and
would have no widgets at all when rendered in the side panel. This leads
to the error mentioned above.

The simple workaround is to wait one tick. An `Effect` component then
detects that the active tab doesn’t exist in the list of allowed tabs
and switches to another tab by default.

This feels more like a workaround than a proper solution, but I prefer
to fix it this way for now. We can later revisit this and design a
better separation for the selected tab ID state.

## Before


https://github.com/user-attachments/assets/500e332c-1623-48e5-b69b-5a4fa4e5e28d

## After


https://github.com/user-attachments/assets/b39dcf96-1852-42e4-a8cc-a79bf9036579
2026-01-28 11:03:42 +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
Abdul Rahman 2a8f834377 Integrate NavigationMenuItem with feature flag support (#17268)
## Implement Navigation Menu Items Frontend

Implements the frontend for navigation menu items, the new system
replacing favorites.

### Changes
- Added GraphQL fragments and queries for navigation menu items
- Added hooks for managing navigation menu items (create, update,
delete, sorting, filtering)
- Updated components to use navigation menu items instead of favorites
- Added test coverage for utility functions

### Migration Note
The favorites and navigation menu item modules currently exist in
parallel. The favorites code will be removed once all data has been
migrated to navigation menu items.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Replaces Favorites with feature-flagged `NavigationMenuItem` across
frontend and backend, while keeping Favorites as fallback until
migration completes.
> 
> - UI: new `navigation-menu-item` components (folders, orphan items,
drag provider/droppable, icons, skeleton), dispatcher components to
switch from Favorites, and updated “Add to favorites” action to create
`NavigationMenuItem` when `IS_NAVIGATION_MENU_ITEM_ENABLED`
> - DnD: shared `validateAndExtractFolderId` and droppable id utils
moved to `ui/layout/draggable-list`; favorites DnD updated to use shared
utils
> - GraphQL (client): add fragments, queries, mutations, hooks
(create/update/delete/find), and generated types; added
`RecordIdentifier` and `targetRecordIdentifier` on `NavigationMenuItem`
> - Prefetch: new prefetch state/effect for navigation menu items; skip
favorites prefetch when flag enabled
> - Backend: add DTOs (`NavigationMenuItem`, `RecordIdentifier`),
resolver `targetRecordIdentifier` field, service logic to fetch record
identifiers with permission-aware access and image signing,
`getRecordImageIdentifier` util, entity relation to `view`, and
migration adding FK on `viewId`
> - Feature flags & seeding: add `IS_NAVIGATION_MENU_ITEM_ENABLED` to
enums, dev seeder enables it; standard app seeds workspace navigation
menu items instead of favorites when flag on
> - Tests: add unit tests for sorting/labels/folder id and related utils
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
c99746f08b9f84fc8cec4fcc3a7d7afb8ea92db7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Aman Raj <92664006+araj00@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Paul Rastoin <45004772+prastoin@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-27 10:42:27 +00:00
nitin c02227472e Fix dashboard animations (#17389)
Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2026-01-23 10:36:13 +00:00
Baptiste Devessier 3ef789dab4 Fix blank page layout after navigation (#17340)
Until now, it wasn’t possible to navigate between page layouts.
Dashboards don’t contain links to other dashboards. With record page
layouts, however, a page layout can now contain a link to another page
layout. If the user opens a record in the side panel and then clicks a
link to another record, the current page layout is replaced with the
page layout for the clicked record.

In this scenario, the `PageLayoutRenderer` component is not remounted.
As a result, the `isInitialized` state was not reset to `false`, and the
corresponding initialization `useEffect` was not triggered again.

All page layout states are component states bound to
`PageLayoutComponentInstanceContext`. For example, after navigating to
another record, `pageLayoutPersistedComponentState` was actually
`undefined` because the context's `instanceId` had changed.

Replacing the `isInitialized` state with a component state fixes the bug
and is consistent with the existing pattern of using component states to
store everything related to page layouts.

## Before


https://github.com/user-attachments/assets/24217145-51e5-49ef-8180-de62a6acfe10

## After


https://github.com/user-attachments/assets/e0ffe107-8fae-4f3a-9016-72c85bc735f4
2026-01-22 16:52:56 +00:00
nitin 873749981b [Dashboards] fix dragging widget z index (#17371) 2026-01-22 16:23:20 +00:00
Baptiste Devessier fb2c9e12bc Fix a bunch of bugs on Record Page Layouts (#17342)
## Display task target and note target relations


https://github.com/user-attachments/assets/b291cc38-33b9-45b8-b685-e5890824176e

## Drop summary card in right drawer

### Before

<img width="1362" height="2160" alt="CleanShot 2026-01-22 at 14 27
09@2x"
src="https://github.com/user-attachments/assets/79f45d8f-976b-4999-8f62-5cb4b87b3ef6"
/>

### After

<img width="1362" height="2160" alt="CleanShot 2026-01-22 at 14 26
43@2x"
src="https://github.com/user-attachments/assets/fb67ddbb-0585-48bd-8ef6-c0139bba4062"
/>

## Add a tooltip to the see all action


https://github.com/user-attachments/assets/ab05cfab-8a6c-4caf-bfe9-698c8b7904e6

## Rename the Fields tab to Home

### Before

<img width="544" height="354" alt="CleanShot 2026-01-22 at 14 28 26@2x"
src="https://github.com/user-attachments/assets/62f7faa2-3a18-40af-8cdf-3fb9f7c7708c"
/>

### After

<img width="544" height="354" alt="CleanShot 2026-01-22 at 14 28 06@2x"
src="https://github.com/user-attachments/assets/76c21ec9-3723-4933-b34f-88b6403cbad5"
/>
2026-01-22 16:17:10 +00:00
Félix Malfait c737028dd6 Move tools/eslint-rules to packages/twenty-eslint-rules (#17203)
## Summary

Moves the custom ESLint rules from `tools/eslint-rules` to
`packages/twenty-eslint-rules` for better organization within the
monorepo packages structure.

## Changes

- Move `eslint-rules` from `tools/` to `packages/twenty-eslint-rules`
- Use `loadWorkspaceRules` from `@nx/eslint-plugin` to load custom rules
- Update all ESLint configs to use the `twenty/` rule prefix instead of
`@nx/workspace-`
- Update `project.json`, `jest.config.mjs` with new paths
- Update `package.json` workspaces and `nx.json` cache inputs
- Update Dockerfile reference

## Technical Details

The custom ESLint rules are now loaded using Nx's `loadWorkspaceRules`
utility which:
- Handles TypeScript transpilation automatically
- Allows loading workspace rules from any directory
- Provides a cleaner approach than the previous `@nx/workspace-`
convention

## Testing

- Verified all 17 custom ESLint rules load correctly from the new
location
- Verified linting works on dependent packages (twenty-front,
twenty-server, etc.)
2026-01-17 07:37:17 +01:00
Baptiste Devessier 5bcbe43596 Various layout fixes so that RPL v1 look the same as production version (#17195)
> [!WARNING]
> Most of the quick fixes will be dropped once we release the feature
and deprecate the old show pages code.

This PR fixes padding and alignment issues so that the new Record Page
Layout feature looks like the old show pages.

## This PR

<img width="3456" height="2160" alt="CleanShot 2026-01-16 at 17 24
40@2x"
src="https://github.com/user-attachments/assets/f3640553-2316-498c-8dd0-14b09ed913f1"
/>

<img width="3456" height="2160" alt="CleanShot 2026-01-16 at 17 27
14@2x"
src="https://github.com/user-attachments/assets/c4ccb28f-5629-4e68-83ad-863f21066962"
/>


## The production

<img width="3456" height="2160" alt="CleanShot 2026-01-16 at 17 25
11@2x"
src="https://github.com/user-attachments/assets/a91f7216-0b57-404b-9f9d-f6f45d4858d6"
/>

<img width="3456" height="2234" alt="CleanShot 2026-01-16 at 17 27
19@2x"
src="https://github.com/user-attachments/assets/aaf1ee6b-b323-4844-9f1a-a59807cdbe40"
/>
2026-01-16 17:06:34 +00:00
Abdullah. 5240a1818f feat: upgrade Storybook to version 9 (#17077)
Upgraded from 8.6.15 to 9.1.17 in two steps: 
- 8.6.15 -> 9.0.0 
- 9.0.0  -> 9.1.17

I had to disable `storybook-addon-cookie` since it is not supported for
Storybook 9. However, I do intend to upgrade to Storybook 10 when this
is merged, so we can replace the aforementioned add-on with this fork
specifically created to support Storybook 10 and above:
https://www.npmjs.com/package/@storybook-community/storybook-addon-cookie.

Additionally, once we upgrade to Version 10 successfully, I will start
looking into integrating the official Vitest add-on.
2026-01-11 13:54:41 +00:00
Baptiste Devessier dec2b44808 Generate Field widgets for relations (#17047)
To release version 1, we must ensure feature parity with the current
production version.

In the future, all widgets will be stored in the backend. For now, let's
compute Field widgets for relations at runtime.


https://github.com/user-attachments/assets/acffe2f9-0f9b-4eff-bb89-c41f7caf5441
2026-01-09 16:24:35 +00:00
Abdullah. 32efaee1bf fix: Remove incorrect background logic from PageLayoutGridLayout (#16945)
Removes the background color logic that was incorrectly added to
PageLayoutGridLayout in PR #16870. Grid layouts are only used for
dashboards where widgets have their own background colors set in
WidgetCard.tsx, so the container background was causing visual
mismatches in padding/gap areas. The background logic remains correctly
applied in PageLayoutVerticalListViewer and PageLayoutVerticalListEditor
where widgets need to inherit the container background.

---------

Co-authored-by: Devessier <baptiste@devessier.fr>
2026-01-06 10:19:34 +00:00
Abdullah. 18473e5c94 fix: use white background for widgets on mobile and in side panel (#16870)
Closes [2029](https://github.com/twentyhq/core-team-issues/issues/2029)

Widgets now use a white background on mobile and in the side panel,
while keeping gray in the side column. Background colors are set at the
parent container level (PageLayoutVerticalListViewer/Editor) so widgets
inherit the correct background, centralizing the background logic in the
container components.

Other variants (dashboard, record-page) specify their own background
color inside `WidgetCard.tsx` file, so we should not have any
regressions.

---------

Co-authored-by: Baptiste Devessier <baptiste@devessier.fr>
2026-01-05 17:39:50 +01:00
Paul Rastoin 4135a6473a [BREAKING_CHANGE_DASHBOARDS][DASHBOARD_CACHE_FLUSH_REQUIRED] Refactor page layout widget configuration type (#16671)
# Introduction
In this pull-request we're refactoring the page layout widget
configuration entity to be containing its discriminated key simplifying
underlying code and maintainability
- Made the configuration and title non nullable
- Introduced a generic predicate for the `widgetConfigurationType`
- Upgraded command to remove `graphType` and insert new
`configurationType` to existing entries
- Migrated frontend to new type system

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
Co-authored-by: Raphaël Bosi <71827178+bosiraphael@users.noreply.github.com>
2025-12-29 15:46:59 +01:00
Abdullah. 2b9728230a Correctly separate widgets in side-column mode. (#16804)
Had to close the other PR since I messed up re-basing somehow:
https://github.com/twentyhq/twenty/pull/16668/files.

Moved changes to this new PR in order to resolve comments from the
previous PR and also match the field-design to that on Figma.

---------

Co-authored-by: Baptiste Devessier <baptiste@devessier.fr>
2025-12-29 15:00:33 +01:00
Baptiste Devessier 9984981e82 Field widget edit relations (#16714)
- Let the user edit their relations
- Create a `useCurrentWidget` that returns the widget information in the
context of a rendered widget. Relies on a component instance context.


https://github.com/user-attachments/assets/e908364f-2d53-4adb-97a1-4d950f51976a

Follow up:

- Show pen button for all Field widgets
2025-12-19 21:21:00 +01:00
Raphaël Bosi 01ffca0cef [DASHBOARDS] Add the ability to click to create a widget (#16673)
## Video QA


https://github.com/user-attachments/assets/813a2040-6ee9-418c-b7da-1126c9720446
2025-12-18 14:37:22 +00:00
Félix Malfait 1088f7bbab feat: add lingui/no-unlocalized-strings ESLint rule and fix translations (#16610)
## Summary
This PR adds the `lingui/no-unlocalized-strings` ESLint rule to detect
untranslated strings and fixes translation issues across multiple
components.

## Changes

### ESLint Configuration (`eslint.config.react.mjs`)
- Added comprehensive `ignore` patterns for non-translatable strings
(CSS values, HTML attributes, technical identifiers)
- Added `ignoreNames` for props that don't need translation (className,
data-*, aria-*, etc.)
- Added `ignoreFunctions` for console methods, URL APIs, and other
non-user-facing functions
- Disabled rule for debug files, storybook, and test files

### Components Fixed (~19 files)
- Object record components (field inputs, pickers, merge dialogs)
- Settings components (accounts, admin panel)
- Serverless function components
- Record table and title cell components

## Status
🚧 **Work in Progress** - ~124 files remaining to fix

This PR is being submitted as draft to allow progressive fixing of
remaining translation issues.

## Testing
- Run `npx eslint "src/**/*.tsx"` in `packages/twenty-front` to check
remaining issues
2025-12-17 22:08:33 +01:00