Commit Graph

4339 Commits

Author SHA1 Message Date
Félix Malfait 6f251a6f8e Add @mention support in AI Chat input (#17943)
## Summary
- Add `@mention` support to the AI Chat text input by replacing the
plain textarea with a minimal Tiptap editor and building a shared
`mention` module with reusable Tiptap extensions (`MentionTag`,
`MentionSuggestion`), search hook (`useMentionSearch`), and suggestion
menu — all shared with the existing BlockNote-based Notes mentions to
avoid code duplication
- Mentions are serialized as
`[[record:objectName:recordId:displayName]]` markdown (the format
already understood by the backend and rendered in chat messages), and
displayed using the existing `RecordLink` chip component for visual
consistency
- Fix images in chat messages overflowing their container by
constraining to `max-width: 100%`
- Fix web_search tool display showing literal `{query}` instead of the
actual query (ICU single-quote escaping issue in Lingui `t` tagged
templates)

## Test plan
- [ ] Open AI Chat, type `@` and verify the suggestion menu appears with
searchable records
- [ ] Select a mention from the dropdown (via click or keyboard
Enter/ArrowUp/Down) and verify the record chip renders inline
- [ ] Send a message containing a mention and verify it appears
correctly in the conversation as a clickable `RecordLink`
- [ ] Verify Enter sends the message when the suggestion menu is closed,
and selects a mention when the menu is open
- [ ] Verify images in AI chat responses are constrained to the
container width
- [ ] Verify the web_search tool step shows the actual search query
(e.g. "Searched the web for Salesforce") instead of `{query}`
- [ ] Verify Notes @mentions still work as before


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 14:37:33 +01:00
neo773 84afbb4d2c feat: add draft email workflow action (#17793)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-13 18:20:20 +01:00
Thomas Trompette 5184491c59 Fix event stream infinite loops (#17919)
Event stream resolver was now configured for metadata scope but client
was still created on core.
So endpoints could not be found.
2026-02-13 16:53:39 +01:00
Charles Bochet f17cc4d190 Improve building of twenty-sdk (#17913)
## Split twenty-sdk build into separate Node and browser targets

The SDK was bundling Node.js code (CLI, SDK API) and browser code (UI
components, front-component renderer) through a single Vite config. This
caused incorrect externalization — Node builtins leaked into browser
bundles and browser-specific chunking logic applied to CLI output.

This PR splits the build into `vite.config.node.ts` and
`vite.config.browser.ts` so each target gets the right externals and
output format.

Also includes a few housekeeping renames:
- `front-component` export path → `front-component-renderer` (matches
what it actually is)
- `front-component-common` merged into `front-component-api` (was a
needless extra module)
2026-02-13 15:58:19 +01:00
nitin 463ce43442 [FRONT COMPONENT] Add Front component token generation (#17855)
closes https://github.com/twentyhq/core-team-issues/issues/2180


https://github.com/user-attachments/assets/a898455d-eb1c-4d22-b585-785e98fc38a7
2026-02-13 14:18:09 +00:00
acee3 e2b9bc935f Add mentions feature to objects in notes (#16373)
Issue #15755 

### Context
As shown in the issue, users should be able to @ objects and have it be
linked to their associated page.

### Changes Made
- Updated the BlockNote schema to include the newly created
MentionInlineContent that displays an object using a RecordChip
- Added the UI for the menu that appears to select the requested object
(similar to this example:
https://www.blocknotejs.org/examples/ui-components/suggestion-menus-slash-menu-component)
- Added a hook to retrieve the data for the UI
- Added the @ trigger to the block editor

### Result 

https://github.com/user-attachments/assets/87dae6a2-ad7a-4642-80b2-8b1751feae24

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 13:12:37 +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
Baptiste Devessier 83b800a077 Drag and drop fields of Fields widgets (#17910)
https://github.com/user-attachments/assets/97fad3f3-8654-4216-b58c-b7411119c8ce
2026-02-13 11:41:25 +00:00
Copilot d08c098065 Hide delete button for record page layout widgets (#17892)
## Before


https://github.com/user-attachments/assets/ea04e8cc-a445-498d-b0d0-d3230a9eeec8

## After


https://github.com/user-attachments/assets/c88aead2-2d3a-42ec-8829-7595a4faa116

---------

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-13 11:19:06 +00:00
Félix Malfait 21c51ec251 Improve AI agent chat, tool display, and workflow agent management (#17876)
## Summary

- **Fix token renewal endpoint**: Use `/metadata` instead of `/graphql`
for token renewal in agent chat, fixing auth issues
- **Improve tool display**: Add `load_skills` support, show formatted
tool names (underscores → spaces) with finish/loading states, display
tool icons during loading, and support custom loading messages from tool
input
- **Refactor workflow agent management**: Replace direct
`AgentRepository` access with `AgentService` for create/delete/find
operations in workflow steps, improving encapsulation and consistency
- **Simplify Apollo client usage**: Remove explicit Apollo client
override in `useGetToolIndex`, add `AgentChatProvider` to
`AppRouterProviders`
- **Fix load-skill tool**: Change parameter type from `string` to `json`
for proper schema parsing
- **Update agent-chat-streaming**: Use `AgentService` for agent
resolution and tool registration instead of direct repository queries

## Test plan

- [ ] Verify AI agent chat works end-to-end (send message, receive
response)
- [ ] Verify tool steps display correctly with icons and proper messages
during loading and after completion
- [ ] Verify workflow AI agent step creation and deletion works
correctly
- [ ] Verify workflow version cloning preserves agent configuration
- [ ] Verify token renewal works when tokens expire during agent chat


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-13 09:27:38 +00:00
Marie 5c3c2e08a6 Some fixes (#17904) 2026-02-13 09:23:14 +00:00
Tan Le fdb5d2fbcd Feat 17408 : Add remove option for object permissions rule (#17601)
This PR aims to fix: #17408 

Main modification includes adding a new column for dropdown in the
object permission rule table (containing options for editing and
removal). Removal logic is implemented using existing pattern with hook
```useResetObjectPermission``` (relies on existing hooks
```useUpsertFieldPermissionInDraftRole``` and
```useUpsertObjectPermissionInDraftRole```).

Feel free to suggest any necessary changes. Functionality (unrestricted
access is allowed when permission removal is applied) is already tested.

Demo video:
https://drive.google.com/file/d/1M4RYHw-JEhDdJksKkL3MY_VyXAV3aS9I/view?usp=sharing

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-02-13 09:16:36 +00:00
Etienne 5c2c588885 Files - Migrate attachments in activities (#17808)
As attachment files have migrated from fullPath to file files field,
need to migrate richText logic to fit to new attachment file handling +
data migration
2026-02-13 09:11:23 +00:00
Marie 90a30263ac [Apps] Content + permission tabs for marketplace and installed apps (#17888)
In this PR
- Content tab for marketplace apps and installed apps: complies with
[figma](https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=34845-126856);
addition of field section showing fields added to standard objects;
initiative: arrow opens a sub-table of fields rows. (suggested because
1/ for marketplace apps we cannot redirect to the actual object page in
settings since the object does not exist yet in the workspace 2/ since
we dont have an quick "go back to application page" option, it can be
annoying to be redirected to a different setting page when we just want
to look at the content of the app objects)
- Permission tab for marketplace apps and installed apps
- left to do - settings tab (in another PR)

There are breaking changes but it's behind a feature flag not exposed
(access to marketplace) so not problematic


marketplace apps

https://github.com/user-attachments/assets/4c660101-50fc-47ce-b90a-8d6f17db5e74

installed apps

https://github.com/user-attachments/assets/c9229ee1-e75f-4cad-8766-758b2c5b37b4
2026-02-12 17:38:53 +00:00
Abdullah. 13c2234856 feat: emit metadata events for schema changes with actor context for webhooks (#17622)
## Summary

This PR adds **metadata eventing**: when schema metadata
(objectMetadata, fieldMetadata, view, viewField, etc.) is created,
updated, or deleted, we now emit events that can trigger webhooks and
future audit logs. It also adds **actor context** (`userId`,
`workspaceMemberId`) to those events so subscribers can attribute
changes to a user or API key.

## What changed

### 1. Metadata eventing (first commit)

- **MetadataEventEmitter**  
New service that emits batch events after successful workspace
migrations. Event names follow `metadata.{entity}.{action}` (e.g.
`metadata.objectMetadata.created`, `metadata.fieldMetadata.updated`).
- **MetadataEventsToDbListener**  
Listens for metadata events and enqueues webhook delivery via
`CallWebhookJobsForMetadataJob`.
- **Event types** (twenty-shared)  
`MetadataEventAction`, `MetadataEventBatch`, and record event types for
create/update/delete.
- **WorkspaceMigrationValidateBuildAndRunService**  
Calls the metadata event emitter after running migrations so all
metadata changes (from any module) emit events from a single place.
- **Create events**  
Sourced from the create action payload (`flatEntity` /
`flatFieldMetadatas`) because `fromToAllFlatEntityMaps` does not provide
a before/after diff for creates. Update/delete events still use the
fromToAllFlatEntityMaps comparison.

### 2. Actor context (second commit)

- **MetadataEventEmitter**  
Accepts optional `actorContext` (`userId`, `workspaceMemberId`) and
includes it on emitted batch events.
- **WorkspaceMigrationValidateBuildAndRunService**  
Passes `actorContext` from the request into the metadata event emitter.
- **Metadata resolvers & services**  
All metadata modules resolve `@AuthUser({ allowUndefined: true })` and
`@AuthUserWorkspaceId()` and pass `userId` and `workspaceMemberId`
through to the migration/event pipeline. Both are optional so
API-key–authenticated requests (no user) still emit events without a
user identity.
  
Shared some questions on Discord about the PR.

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: prastoin <paul@twenty.com>
2026-02-12 17:14:25 +00:00
Charles Bochet d5a8cc2085 Migrate more to Jotai (#17903)
Here we go again
2026-02-12 18:13:31 +01:00
Charles Bochet 310d13fd17 Migrate twenty ui to jotai (#17900)
## Remove Recoil from twenty-ui

Completely removes the `recoil` dependency from `twenty-ui` by
converting all atoms, hooks, and providers to Jotai equivalents.

### twenty-ui
- `createState` now returns a Jotai `PrimitiveAtom` instead of a Recoil
atom
- `iconsState`, `IconsProvider`, `useIcons` converted to Jotai
(`useSetAtom`, `useAtomValue`)
- `RecoilRootDecorator` now uses Jotai `Provider` (name kept for compat)
- Deleted unused `invalidAvatarUrlsState` (Avatar already uses
`invalidAvatarUrlsAtomV2`)
- Removed `recoil` from `package.json`

### twenty-front
- Created local Recoil `createState` at
`@/ui/utilities/state/utils/createState` for ~112 state files still on
Recoil
- Updated all imports accordingly
- Removed `iconsState` from Recoil snapshot preservation in `useAuth`
(lives in Jotai store now)
2026-02-12 16:43:34 +01:00
Charles Bochet d2f8352cb8 Start Jotai Migration (#17893)
## Recoil → Jotai progressive migration: infrastructure +
ChipFieldDisplay

### Benchmark

In the beginning, there was no hope:
<img width="1180" height="948" alt="image"
src="https://github.com/user-attachments/assets/f8635991-52e6-4958-8240-6ba7214132b2"
/>

Then the hope was reborn
<img width="2070" height="948" alt="image"
src="https://github.com/user-attachments/assets/be1182b9-1c8d-4fdc-ab4c-1484ad74449d"
/>



### Approach

We introduce a **V2 state management layer** backed by Jotai that
mirrors the existing Recoil API, enabling component-by-component
migration without a big-bang rewrite.

#### V2 API (Jotai-backed, Recoil-ergonomic)

- `createStateV2` / `createFamilyStateV2` — drop-in replacements for
`createState` / `createFamilyState`, returning wrapper types over Jotai
atoms
- `useRecoilValueV2`, `useRecoilStateV2`, `useFamilyRecoilValueV2`, etc.
— thin wrappers around Jotai's `useAtomValue` / `useAtom` / `useSetAtom`
- A shared `jotaiStore` (via `createStore()`) passed to a
`<JotaiProvider>` wrapping `<RecoilRoot>`, also accessible imperatively
for dual-writes

#### Dual-write bridge for progressive migration

For state shared between migrated and non-migrated components, we use
**dual-write**: writers update both the Recoil atom and the Jotai V2
atom (via `jotaiStore.set()`). This avoids sync components or extra
subscriptions.

Write sites updated: `useUpsertRecordsInStore`, `useSetRecordTableData`,
`ListenRecordUpdatesEffect`, `RecordShowEffect`,
`useLoadRecordIndexStates`, `useUpdateObjectViewOptions`.

#### First migration: ChipFieldDisplay render path

- `useChipFieldDisplay` → reads `recordStoreFamilyStateV2` via
`useFamilyRecoilValueV2` (was `useRecoilValue(recordStoreFamilyState)`)
- `RecordChip` → reads `recordIndexOpenRecordInStateV2` via
`useRecoilValueV2` (was `useRecoilValue(recordIndexOpenRecordInState)`)
- `Avatar` (twenty-ui) and event handlers (`useOpenRecordInCommandMenu`)
left on Recoil — not on the render path / in a different package

#### Pattern for migrating additional state

1. Create V2 atom: `createStateV2` or `createFamilyStateV2`
2. Add `jotaiStore.set(v2Atom, value)` at each write site
3. Switch readers to `useRecoilValueV2(v2Atom)`
4. Once all readers are migrated, remove the Recoil atom and dual-writes

#### Why not jotai-recoil-adapter?

Evaluated
[jotai-recoil-adapter](https://github.com/clockelliptic/jotai-recoil-adapter)
— not production-ready (21 open issues, no React 19, forces providerless
mode, missing types). We built a purpose-built thin layer instead.
2026-02-12 16:05:38 +01:00
Thomas Trompette 748e614f6c Workflow bug fixes (#17886)
Fixes https://github.com/twentyhq/private-issues/issues/418 
Currency filtering was not properly managed. Since this is a select, we
were doing 'USD' == [USD]. Replacing by contains as for other select
<img width="952" height="552" alt="Capture d’écran 2026-02-12 à 11 08
42"
src="https://github.com/user-attachments/assets/6945f376-c62b-44a3-9d85-dfcb82f5c478"
/>

Fixes https://github.com/twentyhq/twenty/issues/17611
If-else branches not executed has to be marked as skipped. Otherwise,
the iterator will never start the next iteration. It will wait for some
not started nodes.
<img width="673" height="559" alt="Capture d’écran 2026-02-12 à 10 56
45"
src="https://github.com/user-attachments/assets/2b5396d7-a546-43df-a689-39f2686855ec"
/>
2026-02-12 13:27:36 +00:00
nitin c48ccbca99 Fix widget and front component queries hitting wrong GraphQL endpoint (#17889) 2026-02-12 12:38:06 +01:00
Etienne eb52976e91 File v2 - Backfill mimeType and size - command (#17875) 2026-02-12 10:49:10 +00:00
martmull a4ed043d43 Logic function refactorization (#17861)
As title
2026-02-12 11:40:49 +01: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
Abdul Rahman 3fb2352c78 Navbar customization followup (#17848)
Addresses review comments from the [first navbar customization
PR](https://github.com/twentyhq/twenty/pull/17728)

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
2026-02-12 02:35:43 +00:00
Weiko 6aca1dd013 Introducing view field group syncable entity (#17867)
## Context
Introduces a new viewFieldGroup entity that allows grouping view fields
into sections (e.g. "General", "Additional", "Other") within a view.

The page layout fields widget needs a way to organize fields into
sections. Today, views have no concept of field grouping. This PR
introduces the viewFieldGroup entity which sits between a view and its
viewFields, enabling section-based organization.

<img width="401" height="724" alt="Layout - V2 (customize visibility)"
src="https://github.com/user-attachments/assets/6376e2ab-44db-42bf-9d2c-758f56f6b548"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-02-11 22:02:58 +01:00
Thomas Trompette ed66fbd71b Fix event stream does not exists error (#17873)
[Event stream does not
exists](https://twenty-v7.sentry.io/issues/7238297246/events/441b3c0465cf475a8349c7dec40cae2a/?environment=prod&environment=prod-eu&project=4507072499810304&query=is%3Aunresolved%20%21issue.type%3A%5Bperformance_consecutive_db_queries%2Cperformance_consecutive_http%2Cperformance_file_io_main_thread%2Cperformance_db_main_thread%2Cperformance_n_plus_one_db_queries%2Cperformance_n_plus_one_api_calls%2Cperformance_p95_endpoint_regression%2Cperformance_slow_db_query%2Cperformance_render_blocking_asset_span%2Cperformance_uncompressed_assets%2Cperformance_http_overhead%2Cperformance_large_http_payload%5D%20timesSeen%3A%3E10&referrer=previous-event&sort=date)

Error happens when we are trying to add a query to a non-existing event
stream. In some cases, this is legit. Stream has expired and needs to be
re-created. Then we try to add the query again.

But it should happen only once per tab, and not often. We have a lot of
errors in sentry for each users.

Potential root cause: a race condition between the event stream creation
and the addition of queries:
- event stream id is created in frontend state + creation query is sent
- event stream id is in state so query can be added
- addQuery happens before the stream is actually created in redis. So an
error is returned
- the error makes the event stream re-generated by frontend 
- => the flow starts again until the event stream is actually created
BEFORE the first query is added

Fix: a new state saying if event stream is ready
- event stream id is created in frontend state BUT ready state is falsy
so query is not added yet
- on stream creation on backend side, an initial event is sent, so the
frontend knows the stream is ready
- addQuery can be triggered safely
2026-02-11 20:24:03 +01:00
Félix Malfait 5b4fed1afe Fix redirect to deleted workspace subdomain after workspace deletion (#17865)
## Summary
- After deleting a workspace, the app was incorrectly redirecting to the
deleted workspace's subdomain (e.g. `myworkspace.ourapp.com/sign-in-up`)
because `signOut()` only performs a client-side React Router navigation
which stays on the current domain.
- Added an explicit `redirectToDefaultDomain()` call after sign out in
the workspace deletion flow, which does a hard browser redirect to the
base domain (e.g. `app.ourapp.com`).

## Test plan
- [ ] Delete a workspace in a multi-workspace environment
- [ ] Verify the browser redirects to the base domain (`app.ourapp.com`)
instead of staying on the deleted workspace's subdomain
- [ ] Verify normal sign-out (without workspace deletion) still works as
expected

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 18:25:27 +01:00
Félix Malfait e757a1418d Fix hardcoded colors in 2FA verification screen for dark mode (#17868)
## Summary
- The dash separator and blinking caret in the sign-in 2FA OTP input had
hardcoded `black` and `white` background colors, making them invisible
in dark mode (black on black / white on white).
- Replaced with theme-aware colors (`theme.font.color.light` for the
dash, `theme.font.color.primary` for the caret) to match the existing
settings 2FA component.

## Test plan
- [ ] Open the 2FA verification screen in dark mode and verify the dash
between digit groups is visible
- [ ] Verify the blinking caret is visible in dark mode
- [ ] Confirm both still look correct in light mode

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 18:23:42 +01:00
Etienne 2f298307f9 Handle 413 with user friendly message (#17870)
Add friendly message for 413 errors. Currently, 413 errors originate
from the nginx server.
2026-02-11 17:03:22 +00:00
Abdul Rahman 0902579fbe Feat: Navbar customization (#17728)
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
2026-02-11 15:33:51 +00:00
Etienne d0c1841f0f File - Migrate avatarUrl > avatarFile on person (data migration + logic) + Attachment data migration (#17752)
- Migration command
    - Check IS_FILES_FIELD_MIGRATED:false
    - Check or create avatarFile field
    - Fetch all people with avatarUrl
           - Move (Copy/move) file in storage
           - Create core.file record
           - Update person record
           
    - bonus : attachment migration  : fullPath > file (same logic)
   
- BE logic
    - Add avatarFile field on person

- FE logic 
   - Adapt logic to upload on/display avatarFile data

The whole imageIdentifier logic will be done later
2026-02-11 15:07:05 +00:00
Félix Malfait 2237273869 Fix spurious logouts by deduplicating concurrent token renewals (#17858)
## Summary

- When returning to the app after idle (or after a deploy), the expired
access token causes multiple simultaneous GraphQL queries to fail with
`UNAUTHENTICATED`. Previously, each failure independently triggered its
own `renewToken` call with the same refresh token. If **any single**
renewal failed (e.g. server briefly slow after a deploy), the `catch`
handler would nuke the session and redirect to sign-in — even if another
concurrent renewal had already succeeded and written valid tokens.
- This adds a shared `renewalPromise` so that only the first
`UNAUTHENTICATED` error triggers a server-side renewal. All concurrent
callers await the same promise and replay their operations once it
resolves. This eliminates redundant refresh token rotation on the server
and removes the race condition where a straggling failure could log out
an already-renewed session.

## Test plan

- [ ] Log in, wait >30 minutes (or manually expire the access token),
then interact with the app — should silently renew without redirect to
sign-in
- [ ] Open browser DevTools Network tab, trigger the above scenario, and
verify only **one** `renewToken` mutation is sent (instead of N)
- [ ] With server temporarily stopped, verify that a genuine renewal
failure still correctly redirects to sign-in (single
`onUnauthenticatedError` call)
- [ ] Open multiple browser tabs, let access tokens expire, interact in
one tab — other tabs should also recover gracefully on their next
request


Made with [Cursor](https://cursor.com)

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-11 12:28:52 +00:00
Charles Bochet 9e21e55db4 Prevent leak between /metadata and /graphql GQL schemas (#17845)
## Fix resolver schema leaking between `/metadata` and `/graphql`
endpoints

### Summary
- Patch `@nestjs/graphql` to support a `resolverSchemaScope` option that
filters resolvers at both schema generation and runtime, preventing
cross-endpoint leaking
- Introduce `@CoreResolver()` and `@MetadataResolver()` decorators to
explicitly scope each resolver to its endpoint
- Move most resolvers (auth, billing, workspace, user, etc.) to the
metadata schema where the frontend expects them; only workflow and
timeline calendar/messaging resolvers remain on `/graphql`
- Fix frontend `SSEQuerySubscribeEffect` to use the default (metadata)
Apollo client instead of the core client

### Problem
NestJS GraphQL's module-based resolver discovery traverses transitive
imports, causing resolvers from `/metadata` modules to leak into the
`/graphql` schema and vice versa. This made the schemas unpredictable
and tightly coupled to module import order.

### Approach
- Added `resolverSchemaScope` to `GqlModuleOptions` via a patch on
`@nestjs/graphql`, filtering in both `filterResolvers()` (runtime
binding) and `getAllCtors()` (schema generation)
- Each resolver is explicitly decorated with `@CoreResolver()` or
`@MetadataResolver()`
- Organized decorator, constant, and type files under `graphql-config/`
following project conventions


Core GQL Schema: (see: no more fields!)
<img width="827" height="894" alt="image"
src="https://github.com/user-attachments/assets/668f3f0f-485e-43f0-92be-4345aeccacb6"
/>

Metadata GQL Schema (see no more getTimelineCalendarEventsFromCompany)
<img width="827" height="894" alt="image"
src="https://github.com/user-attachments/assets/443913db-e5fe-4161-b0e7-4a971cc80a71"
/>
2026-02-11 10:05:24 +00:00
Rémi Delassus 859241d237 Fix merge records page accumulating duplicate morph items (#17705)
## Why
When opening **Merge records** repeatedly, morph items for the same
command-menu page were appended instead of replaced. This could produce
duplicated IDs (e.g. `[A,B,B,A]`) in the merge flow and extra duplicate
tabs in the UI.

## What
- Update `useCommandMenuUpdateNavigationMorphItemsByPage` to replace
page morph items instead of appending existing ones.
- Add regression tests covering:
  - replacing existing morph items for the same page
  - keeping only the latest payload when called twice for the same page

## Notes
I could not run the full workspace tests locally in this environment
because of existing test/build setup issues unrelated to this change
(missing `packages/twenty-front/tsconfig.spec.json` and
`temporal-polyfill` resolution in dependent tasks).

Co-authored-by: remi <remi@labox-apps.com>
2026-02-11 09:55:19 +00:00
Félix Malfait b4d957306e fix: show user-friendly error message when duplicate invite is sent (#17827)
Fixes #17822

Generated with [Claude Code](https://claude.ai/code)

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-11 00:06:42 +01:00
nitin e995e84621 [DASHBOARDS] chat agent improvements + new validation layer (#17722)
https://github.com/user-attachments/assets/09550210-76c5-4a40-83b6-9ab785ca10c3



https://github.com/user-attachments/assets/352427fc-0a2a-4f1b-86e9-db99daea0018

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2026-02-10 13:43:36 +00:00
BOHEUS 382746dd52 Clarify forms usage (#17772)
Fixes https://github.com/twentyhq/core-team-issues/issues/1704
2026-02-10 12:35:37 +01:00
Weiko 202a130ac8 revert releasing RLS (#17809) (#17832) 2026-02-10 11:48:59 +01:00
Thomas des Francs 24c6d3fef3 Fix row-level permissions 'Where' left spacing (#17831)
<img width="634" height="289" alt="image"
src="https://github.com/user-attachments/assets/c8fe85e1-ecac-4b57-be36-6c4a5e426c60"
/>
2026-02-10 11:48:32 +01:00
Thomas des Francs 3f202c5c6a Fix downgrade to Pro CTA icon and wording (#17829)
## Summary
- Fixes the downgrade CTA icon for `Switch to Pro` from an up arrow to a
down arrow.
- Fixes wording generation so no `undefined` suffix is concatenated in
downgrade/plan-switch confirmation copy.

## Before

<img width="717" height="535" alt="image"
src="https://github.com/user-attachments/assets/f934d130-c9fa-46bb-b677-88edf64bc623"
/>

<img width="508" height="325" alt="image"
src="https://github.com/user-attachments/assets/4c776922-a169-4543-b791-fcefc093fa7f"
/>

## Testing
- Not run locally in this environment.
2026-02-10 09:41:48 +00: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
Lakshay Manchanda 2d42b0a726 - Added accomodation of mobile navigation bar in command menu (#17419)
Fix for #16743 

Added styles to accommodate for mobile navigation bar for better
visibility and better access of the command menu buttons.

## CommandMenuAskAIPage.tsx (Not shown in the issue)
### Before
<img width="1100" height="1792" alt="screenshot-2026-01-24_17-22-45"
src="https://github.com/user-attachments/assets/8a337ffe-9dfc-4e52-b744-622cc6989ae4"
/>

### After 
Since the component here already had some padding on it the mobile
navigation bar offset was lesser than it is in other places.
<img width="1092" height="1778" alt="screenshot-2026-01-24_17-28-33"
src="https://github.com/user-attachments/assets/00a217f1-d98e-4303-bdc1-df112d71a553"
/>


## CommandMenuWorkflowEditStep.tsx
### Before
As mentioned in the issue

### After
<img width="755" height="1061" alt="image"
src="https://github.com/user-attachments/assets/487d0b20-f544-4e85-99d5-eb5add4b2cb4"
/>

## CommandMenuWorkflowRunViewStep.tsx
### Before
As shown in the issue

### After
<img width="1102" height="1784" alt="screenshot-2026-01-24_17-19-31"
src="https://github.com/user-attachments/assets/a95773e3-5f61-46d0-93cb-e678e087a42f"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-02-09 23:48:45 +01:00
Baptiste Devessier 8c70a875f8 fix: set a margin even for empty side-column widgets (#17806)
| | Read | Edit |
|--------|--------|--------|
| **Before** | <img width="762" height="2144" alt="CleanShot 2026-02-09
at 16 07 06@2x"
src="https://github.com/user-attachments/assets/d93b5928-2c7b-438a-b16a-d17a434276fc"
/> | <img width="762" height="2144" alt="CleanShot 2026-02-09 at 16 07
01@2x"
src="https://github.com/user-attachments/assets/c5fb94db-947d-4832-9bc2-7942faa290eb"
/> |
| **After** | <img width="762" height="2144" alt="CleanShot 2026-02-09
at 16 06 33@2x"
src="https://github.com/user-attachments/assets/761352f3-cf18-4f41-98f0-fb0b4367f486"
/> | <img width="762" height="2144" alt="CleanShot 2026-02-09 at 16 06
41@2x"
src="https://github.com/user-attachments/assets/d1780671-1043-4087-860c-020343fcda87"
/> |


Closes https://github.com/twentyhq/core-team-issues/issues/2193
2026-02-09 22:59:00 +01:00
neo773 268cc40d80 Show accounts with pending message channel configuration (#17770) 2026-02-09 22:29:27 +01:00
Marie 11fd1a41f3 [Fix] fix timelineActivities on notes and tasks (#17814)
[Fixes
sentry](https://twenty-v7.sentry.io/issues/7238708876/?environment=prod&environment=prod-eu&project=4507072499810304&query=Field%20metadata%20for%20field&referrer=issue-stream&sort=date):
_Field metadata for field "targetTargetPersonId" is missing in object
metadata timelineActivity_

Regression caused by migration of note and task targets - fields were
renamed from personId to targetPersonId, impacting the event names,
while we still expected them in their previous shape.

---------

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <FelixMalfait@users.noreply.github.com>
2026-02-09 20:47:43 +00:00
Weiko 05eca08ad2 releasing RLS (#17809)
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2026-02-09 21:56:41 +01:00
Abdullah. ef1464db73 Improve AI-chat design to match the one provided in Figma (#17816)
Fixed colors, gaps, component nesting, alignment to match Figma.
2026-02-09 18:28:25 +00:00
Raphaël Bosi f51291704d [FRONT COMPONENTS] Retrieve the front components from the backend (#17813)
- Pass the auth token to worker
- Fetch the file from the rest API with the auth token
- Create the blob url
- Update the stories to pass a fake token which will be ignored

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2026-02-09 19:10:29 +01:00
Weiko 4ae375308f Revert "Releasing RLS"
This reverts commit c01853c349.
2026-02-09 16:52:58 +01:00
Weiko c01853c349 Releasing RLS 2026-02-09 16:52:12 +01:00