Commit Graph
8185 Commits
Author SHA1 Message Date
aac032e517 i18n - translations (#17986)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-17 11:14:14 +01:00
Paul RastoinandGitHub 5544b5dcfe Fix and refactor all metadata relation (#17978)
# Introduction
The initial motivation was that in the workspace migration create action
some universal foreign key aggregators weren't correctly deleted before
returned due to constant missconfiguration
<img width="2300" height="972" alt="image"
src="https://github.com/user-attachments/assets/9401eb02-2bb2-4e69-9c5f-9a354ff61079"
/>
It also meant that under the hood some optimistic behavior wasn't
correctly rendered for some aggregators

## Solution
Refactored the `ALL_METADATA_RELATIONS` as follows:

This way we can infer the FK and transpile it to a universalFK, also the
aggregators are one to one instead of one versus all available
Making the only manual configuration to be defined the `foreignKey` and
`inverseOneToManyProperty`

```
┌──────────────────────────────────────┐      ┌─────────────────────────────────────────────┐
│  ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY│      │      ALL_ONE_TO_MANY_METADATA_RELATIONS     │
│──────────────────────────────────────│      │─────────────────────────────────────────────│
│  Derived from: Entity types          │      │  Derived from: Entity types                 │
│                                      │      │                                             │
│  Provides:                           │      │  Provides:                                  │
│   • foreignKey                       │      │   • metadataName                            │
│                                      │      │   • flatEntityForeignKeyAggregator          │
│  Standalone low-level primitive      │      │   • universalFlatEntityForeignKeyAggregator │
└──────────────┬───────────────────────┘      └──────────────┬──────────────────────────────┘
               │                                             │
               │ foreignKey type +                           │ inverseOneToManyProperty
               │ universalForeignKey derivation              │ keys (type constraint)
               │                                             │
               ▼                                             ▼
       ┌───────────────────────────────────────────────────────────────┐
       │              ALL_MANY_TO_ONE_METADATA_RELATIONS              │
       │───────────────────────────────────────────────────────────────│
       │  Derived from:                                               │
       │   • Entity types (metadataName, isNullable)                  │
       │   • ALL_MANY_TO_ONE_METADATA_FOREIGN_KEY (FK → universalFK)  │
       │   • ALL_ONE_TO_MANY_METADATA_RELATIONS (inverse keys)        │
       │                                                              │
       │  Provides:                                                   │
       │   • metadataName                                             │
       │   • foreignKey (replicated from FK constant)                 │
       │   • inverseOneToManyProperty                                 │
       │   • isNullable                                               │
       │   • universalForeignKey                                      │
       └──────────────────────────┬────────────────────────────────────┘
                                  │
               ┌──────────────────┼──────────────────┐
               │                  │                  │
               ▼                  ▼                  ▼
   ┌───────────────────┐ ┌────────────────┐ ┌──────────────────────┐
   │  Type consumers   │ │  Atomic utils  │ │  Optimistic utils    │
   │───────────────────│ │────────────────│ │──────────────────────│
   │ • JoinColumn      │ │ • resolve-*    │ │ • add/delete flat    │
   │ • RelatedNames    │ │ • get-*        │ │   entity maps        │
   │ • UniversalFlat   │ │                │ │ • add/delete         │
   │   EntityFrom      │ │                │ │   universal flat     │
   │                   │ │                │ │   entity maps        │
   └───────────────────┘ └────────────────┘ │                      │
                                            │  (bridge via         │
                                            │   inverseOneToMany   │
                                            │   Property →         │
                                            │   ONE_TO_MANY for    │
                                            │   aggregator lookup) │
                                            └──────────────────────┘
```

### Previously
```
┌─────────────────────────────────────────────────────────────────────┐
│                       ALL_METADATA_RELATIONS                       │
│─────────────────────────────────────────────────────────────────────│
│  Derived from: Entity types                                        │
│                                                                    │
│  Structure: { [metadataName]: { manyToOne: {...}, oneToMany: {...},│
│               serializedRelations?: {...} } }                      │
│                                                                    │
│  manyToOne provides:                                               │
│   • metadataName                                                   │
│   • foreignKey                                                     │
│   • flatEntityForeignKeyAggregator (nullable, often wrong/null)    │
│   • isNullable                                                     │
│                                                                    │
│  oneToMany provides:                                               │
│   • metadataName                                                   │
│                                                                    │
│  Monolithic single source of truth                                 │
└──────────────────────────┬──────────────────────────────────────────┘
                           │
                           │ manyToOne entries transformed via
                           │ ToUniversalMetadataManyToOneRelationConfiguration
                           │
                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│                  ALL_UNIVERSAL_METADATA_RELATIONS                   │
│─────────────────────────────────────────────────────────────────────│
│  Derived from: ALL_METADATA_RELATIONS (type-level transform)       │
│                                                                    │
│  Structure: { [metadataName]: { manyToOne: {...}, oneToMany: {...} │
│  } }                                                               │
│                                                                    │
│  manyToOne provides:                                               │
│   • metadataName                                                   │
│   • foreignKey                                                     │
│   • universalForeignKey (derived: FK → replace Id → UniversalId)   │
│   • universalFlatEntityForeignKeyAggregator (derived from          │
│     flatEntityForeignKeyAggregator → replace Ids → UniversalIds)   │
│   • isNullable                                                     │
│                                                                    │
│  oneToMany: passthrough from ALL_METADATA_RELATIONS                │
│                                                                    │
│  Duplicated monolith with universal key transforms                 │
└──────────────────────────┬──────────────────────────────────────────┘
                           │
        ┌──────────────────┼──────────────────────┐
        │                  │                      │
        ▼                  ▼                      ▼
┌───────────────┐ ┌────────────────────┐ ┌──────────────────────┐
│ Type consumers│ │   Atomic utils     │ │  Optimistic utils    │
│───────────────│ │────────────────────│ │──────────────────────│
│ • JoinColumn  │ │ • resolve-entity-  │ │ • add/delete flat    │
│ • RelatedNames│ │   relation-univ-id │ │   entity maps        │
│ • Universal   │ │   (ALL_METADATA_   │ │   (ALL_METADATA_     │
│   FlatEntity  │ │    RELATIONS       │ │    RELATIONS         │
│   From        │ │    .manyToOne)     │ │    .manyToOne)       │
│               │ │                    │ │                      │
│ Mixed usage   │ │ • resolve-univ-    │ │ • add/delete univ    │
│ of both       │ │   relation-ids     │ │   flat entity maps   │
│ constants     │ │   (ALL_UNIVERSAL_  │ │   (ALL_UNIVERSAL_    │
│               │ │    METADATA_REL    │ │    METADATA_REL      │
│               │ │    .manyToOne)     │ │    .manyToOne)       │
│               │ │                    │ │                      │
│               │ │ • resolve-univ-    │ │ universalFlatEntity  │
│               │ │   update-rel-ids   │ │ ForeignKeyAggregator │
│               │ │   (ALL_UNIVERSAL_  │ │ read directly from   │
│               │ │    METADATA_REL    │ │ the constant         │
│               │ │    .manyToOne)     │ │                      │
│               │ │                    │ │                      │
│               │ │ • regex hack:      │ │                      │
│               │ │   foreignKey       │ │                      │
│               │ │   .replace(/Id$/,  │ │                      │
│               │ │   'UniversalId')   │ │                      │
└───────────────┘ └────────────────────┘ └──────────────────────┘
```
2026-02-17 11:13:54 +01:00
8244610bdc i18n - translations (#17983)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-17 11:05:36 +01:00
e3db73ef46 Change condition for multi-workspace check (#17938)
When deploying with
```
IS_WORKSPACE_CREATION_LIMITED_TO_SERVER_ADMINS=true
IS_MULTIWORKSPACE_ENABLED=true
```
The first workspace can be created successfully. However, any attempt to
create additional workspaces as admin fails with the error: `Workspace
creation is restricted to admins` because `canAccessFullAdminPanel` is
**false**

If these flags are set to false during the initial deployment and
restarting the Docker container, workspace creation works normally.

Problem is caused by `canAccessFullAdminPanel`

---------

Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-02-17 09:29:59 +01:00
7523143f12 i18n - docs translations (#17981)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-17 09:29:37 +01:00
nitinandGitHub cfc4e0e343 [DASHBOARDS] Add split multi-value fields setting for charts (#17907)
closes https://github.com/twentyhq/twenty/issues/17890



https://github.com/user-attachments/assets/dbf2ebe6-c2da-44d0-846e-d7fa9fac5f43
2026-02-17 09:29:17 +01:00
martmullandGitHub c3d565f266 Add default fields on object manifest (#17977)
as title

<img width="830" height="227" alt="image"
src="https://github.com/user-attachments/assets/8cbf4a14-5d1d-496f-a146-f31079e6e602"
/>
2026-02-16 16:50:46 +01:00
Paul RastoinandGitHub 2b7b05de2e [OBJECT_MANIFEST_BREAKING_CHANGE] Sync returns workspace migration (#17918)
# Introduction
In this PR we start returning a workspace migration post sync so it can
committed and provided within the tarball

## Universal aggregators utils
Created two utils
### deleteUniversalFlatEntityForeignKeyAggregators
Used when building a universal create action, a newly created actions
should not contain any aggregated foreign key so they won't be codegen
in the workspace migration but also they are overriden at uninversal to
flat transpilation anw

### resetUniversalFlatEntityForeignKeyAggregators
Used before validating a new flat entity creation, some validator will
consume the fk aggregator in order to validate integrity, but of
optimstically provided it can result to errors. To avoid caller
responsability we override them here

## create-field-action refactor
Refactored the universal and flat field create action to be following
the base actions in order to ease typing
Also it was tailored to handle unlimited amount of flat field metadata
in the same actions whereas in the reality we were always only sending
at max 2 ( for relation fields )

Note: relation field has to be provided at the same as if not optimistic
would fail to retrieve circular universal identifiers

## ObjectManifest
Now always expect a `labelIdentifierFieldMetadataUniversalIdentifier`

## Integration test
Created an integration test that creates an app, sync a first manifest
and a second implying update workspace migration action generation
2026-02-16 15:00:24 +01:00
4b3c58e013 i18n - docs translations (#17972)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-16 13:51:12 +01:00
Félix MalfaitGitHubCursorclaude[bot] <41898282+claude[bot]@users.noreply.github.com>
c775d65952 feat: configure standard views and migrate attachment seeds to FILES field (#17958)
## Summary

- Add default visible view fields for `timelineActivity`, `attachment`,
`noteTarget`, `taskTarget`, and `workspaceMember` objects so they
display useful columns out of the box
- Standardize morph relation field labels to "Target" with
`IconArrowUpRight` for consistency across all pivot/junction tables
- Mark deprecated fields (`fullPath`, `fileCategory`,
`linkedRecordCachedName`, `linkedRecordId`, `linkedObjectMetadataId`) as
`isSystem` to hide them from the UI column picker
- Fix morph field deduplication logic (`pickMorphGroupSurvivor`) to
prefer active, non-system fields over auto-generated system fields from
custom objects
- Migrate attachment seeds from legacy `fullPath`/`fileCategory` to the
new `FILES` field type, creating proper `FileEntity` records in
`core.file` via `fileStorageService.writeFile()`
- Restore `customDomain` in the user query fragment


<img width="825" height="754" alt="Screenshot 2026-02-15 at 15 44 27"
src="https://github.com/user-attachments/assets/9596a3dd-8d3a-43c0-925a-0adef9ee68a8"
/>
<img width="736" height="731" alt="Screenshot 2026-02-15 at 15 44 13"
src="https://github.com/user-attachments/assets/cd1a66c5-731d-43e6-bbc3-703cbeda1652"
/>
<img width="722" height="757" alt="Screenshot 2026-02-15 at 15 44 03"
src="https://github.com/user-attachments/assets/b5210546-6a40-4940-8e4f-874818a614fb"
/>
<img width="907" height="757" alt="Screenshot 2026-02-15 at 15 43 52"
src="https://github.com/user-attachments/assets/ead5b9a8-1989-4d68-9640-583da6233711"
/>
<img width="1002" height="731" alt="Screenshot 2026-02-15 at 15 43 38"
src="https://github.com/user-attachments/assets/38accb8c-f5d5-4bfc-b245-06389849810b"
/>




<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches migration/upgrade commands that write to core metadata tables
and adjust field/view definitions, plus changes dev seeding to create
`core.file` records; mistakes could affect UI visibility or seed
integrity across workspaces.
> 
> **Overview**
> Adds a new `upgrade:1-18:backfill-standard-views-and-field-metadata`
command that, per workspace, marks specific fields as `isSystem`,
normalizes morph-relation field `label`/`icon` to
`Target`/`IconArrowUpRight`, and backfills missing standard
`view`/`viewField` rows for `attachment`, `noteTarget`, `taskTarget`,
`timelineActivity`, and `workspaceMember`, followed by cache
invalidation + metadata version bump.
> 
> Refactors morph-relation deduplication to pick a single survivor per
`morphId` using a new `pickMorphGroupSurvivor` rule (prefer active +
non-system, then smallest id), with new unit tests.
> 
> Updates standard metadata generators and snapshots to reflect the new
system flags and default view fields, and rewrites attachment dev
seeding to populate the new `file` (FILES field) JSON and create
corresponding `core.file` entries via `FileStorageService.writeFile`
with workspace-scoped file IDs.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b1939bbf6f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
2026-02-16 13:34:56 +01:00
b80146c890 i18n - docs translations (#17967)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-16 12:11:24 +01:00
5604cdbb4b i18n - translations (#17966)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-16 11:07:14 +01:00
martmullandGitHub da064d5e88 Support define is tool logic function (#17926)
- supports isTool and timeout settings in defineLogicFunction in apps
and in setting tabs definition
- compute for all toolInputSchema for logic funciton, in settings and in
code steps

<img width="991" height="802" alt="image"
src="https://github.com/user-attachments/assets/05dc1221-cac9-45a3-87b0-3b13161446fd"
/>
2026-02-16 10:43:29 +01:00
f694bb99b3 fix: restore customDomain field in getCurrentUser query fragment (#17949)
## Summary
- The `customDomain` field was accidentally removed from the
`currentWorkspace` GraphQL query fragment in #16016 (Nov 2025), when
`workspaceCustomApplication { id }` was added in its place rather than
alongside it.
- This caused the custom domain settings page to never display the
configured domain value, the reload/delete buttons, or the DNS records —
since `currentWorkspace.customDomain` was always `undefined`.
- Restores the missing field in the query fragment.

## Test plan
- [ ] Navigate to Settings > Domains on a workspace with a custom domain
configured
- [ ] Verify the custom domain value appears in the input field
- [ ] Verify the Reload and Delete buttons are visible
- [ ] Verify DNS records are displayed


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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-16 06:58:22 +01:00
8190cd5fbf [FRONT COMPONENTS] Allow style librairies in remote dom (#17936)
https://github.com/user-attachments/assets/ce1b2b06-872f-41d0-844a-61db91696624

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-02-15 23:50:57 +01:00
b901bdec40 i18n - translations (#17945)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-15 23:50:35 +01:00
Abdullah.andGitHub b1d3ec665a fix: qs arrayLimit bypass in comma parsing allows denial of service (#17947)
Resolves [Dependabot Alert
454](https://github.com/twentyhq/twenty/security/dependabot/454) and
[Dependabot Alert
455](https://github.com/twentyhq/twenty/security/dependabot/455).

`zapier-platform-cli` leaves in one entry of qs locked at version
`6.5.x`, so the alert might not close automatically. However, the PR
fixes any occurrences in the server itself.
2026-02-15 19:52:23 +00:00
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
0876197c8d i18n - translations (#17935)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-14 10:54:52 +01:00
2072d5f720 i18n - docs translations (#17939)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-14 00:03:59 +01:00
neo773andGitHub d54b713264 Respect Gmail retry-after in messaging throttle (#17850)
Gmail 429/403 rate-limit responses include an explicit retry-after
timestamp, usually ~15 minutes out.

The exponential backoff starts at 1 minute, so the channel burns through
all 5 retry attempts before the window actually closes and gets marked
as permanently failed.

Adds throttleRetryAfter to the message channel and uses max(backoff,
retryAfter) in isThrottled().
2026-02-13 18:20:37 +01:00
neo773GitHubClaude Opus 4.6cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
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
ebfaff0a53 i18n - translations (#17932)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 18:19:38 +01:00
martmullandGitHub c3d8404112 Update cli tool versions (#17933)
as title
2026-02-13 18:03:13 +01:00
a95a286c59 Revert export twenty UI (#17929)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 17:55:04 +01:00
WeikoandGitHub c173f01601 Create record page layout after custom object creation (#17923)
## Context
Creating a new object should now also create its record page layout,
tabs and widgets, including fields widget with its associated views/view
fields.
Custom objects record page layout fields widgets don't have section per
default

Note: I had to enable some widget creation through the custom API but we
should now implement proper validation (which should be minimal since
there is usually only the configuration type in the configuration
(except for FIELDS widget which contains a viewId)

Next step: Create view field should also create a viewField for the
FIELDS_WIDGET view (we should also add in the FIELDS widget
configuration a newFieldDefaults which will contain default visibility
and position to apply to the new view field)

The feature is still gated behind an env variable (this was necessary
for workspace creation, not so much here in this case but I prefer to
keep the same path for consistence)
2026-02-13 16:16:47 +00:00
kpdevGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
cda70a70ca fix: replace react-tooltip with AppTooltip and refactor MenuItemAvatar (#17846)
This PR addresses TODO comments and improves code quality:

### 1. PullRequestItem.tsx
- Replaced `react-tooltip` with `twenty-ui` `AppTooltip` component
- Removed TODO comment
- Uses internal component library for consistency

### 2. MenuItemAvatar.tsx  
- Refactored to use `MenuItem` internally, eliminating code duplication
- Removed about 63 lines of duplicate code
- Removed TODO comment as the merge is now complete

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-02-13 16:12:16 +00:00
a48b69d1e5 i18n - docs translations (#17930)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 17:33:48 +01:00
Charles BochetandGitHub 4817c86bf0 Enhance stories for front component in sdk (#17925)
<img width="3838" height="2014" alt="image"
src="https://github.com/user-attachments/assets/87f4d4ba-7b39-4c44-b863-d8bfa6c4fd8a"
/>
2026-02-13 17:16:03 +01:00
martmullandGitHub 0befb021d0 Add scripts to publish cli tools (#17914)
- moves workspace:* dependencies to dev-dependencies to avoid spreading
them in npm releases
- remove fix on rollup.external
- remove prepublishOnly and postpublish scripts
- set bundle packages to private
- add release-dump-version that update package.json version before
releasing to npm
- add release-verify-build that check no externalized twenty package
exists in `dist` before releasing to npm
- works with new release github action here ->
https://github.com/twentyhq/twenty-infra/pull/397
2026-02-13 15:43:32 +00:00
e7b3f65c0c i18n - translations (#17920)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 16:53:53 +01:00
Thomas TrompetteandGitHub 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 BochetandGitHub 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
nitinandGitHub 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
5cc0c03262 i18n - translations (#17915)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 15:01:26 +01:00
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
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 DevessierandGitHub 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
CopilotGitHubcopilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>DevessierBaptiste Devessier
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
216a7331f8 Speed up twenty-emails build by replacing vite-plugin-dts with tsgo (#17857)
## Summary

- Removed `vite-plugin-dts` (which used `tsc` internally) from the Vite
build and replaced DTS generation with `tsgo` as a sequential post-build
step — **~0.7s vs 1-10s**.
- Disabled `reportCompressedSize` to skip gzip computation for 64 output
files.
- Converted the build target to an explicit `nx:run-commands` executor
with sequential `vite build` → `tsgo` commands.

The `twenty-emails:build` step goes from ~22s to ~7s under load. 

## Test plan

- [x] `nx build twenty-emails` produces both JS (64 files) and DTS (74
files) correctly
- [x] `dist/index.d.ts` exports match the source `src/index.ts`
- [x] Full `nx build twenty-server` succeeds end-to-end
- [ ] CI build passes


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

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 10:39:26 +00:00
975c64bf3d i18n - translations (#17911)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 11:20:56 +01:00
Paul RastoinandGitHub b34f7bcb33 Refactor metadata events to contain scalarEntity (#17908)
# Introduction
Avoid sending flat entity that contains server specific properties such
as foreignKey aggregators and universal properties by transpiling from
flat entity to scalar flat entity

A scalar flat entity is the exact match with the entities columns

Following https://github.com/twentyhq/twenty/pull/17622
2026-02-13 10:01:54 +00:00
14e8c869be i18n - translations (#17905)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-02-13 10:54:25 +01:00
Félix MalfaitGitHubCursorcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
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
MarieandGitHub 5c3c2e08a6 Some fixes (#17904) 2026-02-13 09:23:14 +00:00
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
EtienneandGitHub 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
MarieandGitHub 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
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
Paul RastoinandGitHub f6b7ab2251 Scalar and universal flat entity transpilers (#17891)
# Introduction

## Use `flatEntityTranspilers.toScalarFlatEntity` in create action
handler

**Changes:**
- Modified
`BaseWorkspaceMigrationRunnerActionHandlerService.insertFlatEntitiesInRepository()`
to transform flat entities using `toScalarFlatEntity()` before database
insertion

**What it does:**
Strips out TypeORM relation objects and metadata-only properties,
ensuring only scalar values (primitives, IDs, dates) are inserted into
the database.

**Benefits:**
- **Type Safety:** Prevents accidental insertion of nested objects that
TypeORM can't persist
- **Consistency:** All 17+ create action handlers automatically benefit
from proper data transformation
- **Single Source of Truth:** Centralized logic for what constitutes a
database-insertable entity
- **Prevents Errors:** Uses entity configuration schema to ensure only
valid properties are included

## Usage
```ts
  protected async insertFlatEntitiesInRepository({
    flatEntities,
    queryRunner,
  }: {
    queryRunner: QueryRunner;
    flatEntities: MetadataFlatEntity<TMetadataName>[];
  }) {
    const metadataEntity =
      ALL_METADATA_ENTITY_BY_METADATA_NAME[this.metadataName];
    const repository = queryRunner.manager.getRepository(metadataEntity);
    const scalarFlatEntities = flatEntities.map((flatEntity) =>
      flatEntityTranspilers.toScalarFlatEntity({
        flatEntity,
        metadataName: this.metadataName,
      }),
    );

    await repository.insert(scalarFlatEntities);
  }
```

## Upcoming refactor
About to completely split the
`packages/twenty-server/src/engine/workspace-manager/workspace-migration/workspace-migration-runner/interfaces/workspace-migration-runner-action-handler-service.interface.ts`
into three dedicated boilerplate one for each action type `create`
`delete` `update` will provide a better interfacing and typing + will
allow not requiring the user to provide the metadata execute handler as
required
2026-02-12 17:06:55 +00:00