Commit Graph
9660 Commits
Author SHA1 Message Date
Raphaël BosiandGitHub 655f1eef5f [DASHBOARDS] Allow dashboards to be restored (#17042)
This PR introduces a few changes:
- Add three actions: see deleted dashboards, destroy dashboard and
restore dashboard
- Remove the soft delete and restore on all the page layout entities
- Cascade the destruction of a dashboard to a page layout

Video QA:


https://github.com/user-attachments/assets/ab993b11-dd9c-4e88-880c-92691a521cc2
2026-01-12 12:59:17 +00:00
MarieandGitHub 3ada8e5168 [Extensibility] Support relation fields (#17056)
Closes https://github.com/twentyhq/core-team-issues/issues/2043
2026-01-12 12:54:30 +00:00
Paul RastoinandGitHub 91b788ee09 [REQUIRES_FIELDS_CACHE_FLUSH]Fix field entity to flat field transpiler (#17096)
Following https://github.com/twentyhq/twenty/pull/16981

UniversalIdentifier is now required in the entity so no need to fallback
it
2026-01-12 12:49:07 +00:00
94fe385731 i18n - translations (#17094)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 13:23:13 +01:00
nitinandGitHub 342ae995d9 Add error boundary on widget renderer and minor widget seed fix (#17058)
closes https://github.com/twentyhq/twenty/issues/16896 and
https://github.com/twentyhq/core-team-issues/issues/2050

should error be Invalid Configuration or something else?
2026-01-12 12:02:58 +00:00
Lucas BordeauandGitHub 9b95d28cb3 Refactored table virtualization real index state (#17074)
This PR refactors the table virtualization real index main state that
was creating performance problems.

The problem was that we kept track of all the real rows even if we only
print 200 at a time in the application.

This caused a crash when some users with 10k+ rows on a table tried to
iterate over this state 10.000 times or more.

The trade-off is that now we keep all real indices in a Map, and each
virtual row uses a selector to go to this Map.

This way if we want to reset the full Map, we just have to overwrite the
base state that contains the map, and the 200 selectors will recompute.
This happens for example when we delete a row. This now has a limited
and negligible performance impact.
2026-01-12 11:41:59 +00:00
238e6d5cda Common api - chores (#17051)
Remove refacto-common TODO

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 11:37:29 +00:00
Baptiste DevessierandGitHub 7735a0fc7d Add missing RPL configuration for note tabs (#17092)
## Before

<img width="3456" height="2160" alt="CleanShot 2026-01-12 at 12 03
52@2x"
src="https://github.com/user-attachments/assets/3c7c28f7-b38a-40e2-b8d6-ba6385f823ee"
/>

## After


https://github.com/user-attachments/assets/16db3823-8b7d-4403-9901-75ee109680af
2026-01-12 11:26:58 +00:00
94e5d93e60 Enable editing for calendar event custom fields (#17063)
## Summary
- Enable editing for custom calendar event fields while keeping standard
fields read-only
- Load calendar event fields dynamically so custom field values are
editable everywhere they appear
- Preserve calendar event participants rendering

## Testing
- npx nx run twenty-front:lint:diff-with-main --skip-nx-cache
--output-style=stream
- npx jest --config packages/twenty-front/jest.config.mjs
--runTestsByPath
packages/twenty-front/src/modules/activities/calendar/hooks/__tests__/useCalendarEvents.test.tsx

## Notes
- Full nx lint/test are very slow locally after barrel generation; CI
should run the full suite

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 10:21:42 +00:00
martmullandGitHub ead846d57f Fix logs (#17090)
as title
2026-01-12 10:11:51 +00:00
d5acc24bb7 fix: removed scrollbar, elipsified overflow text supporting tooltip (#17078)
fixes #15152 

Added CSS to ellipsify overflowing text with tooltip support, consistent
with existing dropdown implementations such as the address dropdown for
long country names.
This approach resolves the issue locally without modifying global
components, avoiding the limitations of previous attempts.

<img width="655" height="508" alt="Screenshot 2026-01-11 at 4 09 45 PM"
src="https://github.com/user-attachments/assets/3e11f6c2-3f13-4c1a-91da-59fc1a34e9dd"
/>


Before :

<img width="547" height="496" alt="Screenshot 2026-01-11 at 4 09 11 PM"
src="https://github.com/user-attachments/assets/43181d93-0603-4338-bb6e-688cffac91c9"
/>

After :

<img width="578" height="527" alt="Screenshot 2026-01-11 at 4 08 28 PM"
src="https://github.com/user-attachments/assets/0f277f3b-eeff-4866-99d9-6b31309c02af"
/>

---------

Co-authored-by: Arun kumar <arunkumar@Aruns-MacBook-Air.local>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 10:09:48 +00:00
Paul RastoinandGitHub a6f371a42a Identify standard field do deploy until IS_WORKSPACE_CREATION_V2_ENABLED is enabled in prod (#16981)
# Introduction

fixes https://github.com/twentyhq/twenty/issues/16905

Do not merge until `IS_WORKSPACE_CREATION_V2_ENABLED` has been activated
by default, and so sync metadata has been deprecated by doing so. As the
sync metadata will attempt to insert `null` `applicationId` and
`universalIdentifier` values while creating a workspace

In this PR we're introducing a new `SyncableEntityRequired` which
enforces the non nullable `applicationId` and `universalIdentifier` on
extending entity

In this PR we also migrate the field metadata entity to extend the
required

## Identification upgrade command
This command will search for workspace field metadata entities that
aren't associated to an applicationId, dispatch them to either the
workspace-custom `applicationId` or the twenty-standard `applicationId`.
For the standard entities it will also set their universal identifier
based on the `STANDARD_OBJECTS` const hashmap

## Typeorm migration
As the non nullable `applicationId` and `universalIdentifier`migration
won't pass in the first we've been using the save point and upgrade
command migration fallback pattern

## Tests
Tested the command on a prod extract locally

Both `twenty-eng` and `twenty-for-twenty` have unexpected standard
objects
Please note that we will deprecate the `isCustom` and `standardId` col
later in the future

### Twenty-eng
```ts
[Nest] 98971  - 01/01/2026, 3:18:00 PM     LOG [IdentifyStandardEntitiesCommand] Successfully validated 600/600 field metadata update(s) for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee (309 custom, 291 standard)
[Nest] 98971  - 01/01/2026, 3:18:00 PM    WARN [IdentifyStandardEntitiesCommand] Found 35 warning(s) while processing field metadata for workspace 9870323e-22c3-4d14-9b7f-5bdc84f7d6ee. These fields will become custom.
```

### Twenty for twenty

### Just created workspace
2026-01-12 09:59:01 +00:00
46e5420d20 dashboard workspace standard seeds (#16962)
# Introduction

In this pull request we're introducing new standard page layout, tabs
and widget ( 1 page layout, 1 tab and 8 widgets ) and also a new
opportunity field

Also now prefilling new records, 6 opportunities and a dashboard.

## Standard declaration
### New workspace creation
Relies on existing standard declaration builder

### Backfill command
We've been hacking through the standard builder in order to extract only
the standard page layout entities, updated their entity dependencies to
match the workspace ids so the validation passes


## Remark
- Refactored the `PageLayoutWidget` configuration type to be dynamically
typed through a generic discriminated union

---------

Co-authored-by: prastoin <paul@twenty.com>
2026-01-12 09:34:15 +00:00
Ayesha WaseemandGitHub 89af749b94 fix: hide "Add new" button for workspace member relations (#17080)
**Description**

Fixes the "Add new" button appearing in relation picker dropdowns for
workspace member relations (e.g., Account Owner on companies). Workspace
members cannot be created from relation pickers, so this button should
not appear.

**Changes Made**

- Modified RelationManyToOneFieldInput.tsx to conditionally pass the
onCreate prop to SingleRecordPicker only when
createNewRecordAndOpenRightDrawer is defined.
- Moved the conditional check to the JSX level for clarity.

**Technical Details**

The useAddNewRecordAndOpenRightDrawer hook already returns undefined for
workspace member relations, but the component was still passing a
handler function to SingleRecordPicker, causing the "Add new" button to
appear. The fix ensures that when createNewRecordAndOpenRightDrawer is
undefined, onCreate is also undefined, which prevents
SingleRecordPickerMenuItemsWithSearch from rendering the button.

Testing

- Verified that the "Add new" button no longer appears in the Account
Owner dropdown for companies.
- Confirmed that the "Add new" button still appears for other relation
fields where it's appropriate (e.g., People, Opportunities).
- Tested that existing functionality for selecting workspace members
from the dropdown still works correctly.

Fixes #17060
2026-01-12 09:08:45 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
3d54647839 Bump @typescript-eslint/eslint-plugin from 8.39.0 to 8.52.0 (#17087)
Bumps
[@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin)
from 8.39.0 to 8.52.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/typescript-eslint/typescript-eslint/releases"><code>@​typescript-eslint/eslint-plugin</code>'s
releases</a>.</em></p>
<blockquote>
<h2>v8.52.0</h2>
<h2>8.52.0 (2026-01-05)</h2>
<h3>🚀 Features</h3>
<ul>
<li><strong>eslint-plugin-internal:</strong>
[no-multiple-lines-of-errors] add rule (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11899">#11899</a>)</li>
<li><strong>typescript-estree:</strong> add tseslint.com redirects for
CLI outputs (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11895">#11895</a>)</li>
</ul>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> [no-useless-default-assignment]
handle conditional initializer (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11908">#11908</a>)</li>
<li><strong>eslint-plugin:</strong> [no-base-to-string] detect @<a
href="https://github.com/toPrimitive"><code>@​toPrimitive</code></a> and
valueOf (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11901">#11901</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Josh Goldberg </li>
<li>Ulrich Stark</li>
</ul>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
<h2>v8.51.0</h2>
<h2>8.51.0 (2025-12-29)</h2>
<h3>🚀 Features</h3>
<ul>
<li><strong>eslint-plugin:</strong> expose rule name via RuleModule
interface (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11719">#11719</a>)</li>
<li><strong>eslint-plugin:</strong> [no-useless-default-assignment] fix
some cases to optional syntax (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11871">#11871</a>)</li>
<li><strong>eslint-plugin:</strong> add namespace to plugin meta (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11885">#11885</a>)</li>
<li><strong>tsconfig-utils:</strong> more informative error on parsing
failures (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11888">#11888</a>)</li>
</ul>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> fix crash and false positives in
<code>no-useless-default-assignment</code> (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11845">#11845</a>)</li>
<li><strong>eslint-plugin:</strong> remove fixable from
no-dynamic-delete rule (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11876">#11876</a>)</li>
<li><strong>eslint-plugin:</strong> bump ts-api-utils to 2.2.0 (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11881">#11881</a>)</li>
<li><strong>eslint-plugin:</strong> [prefer-optional-chain] handle
MemberExpression in final chain position (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11835">#11835</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Josh Goldberg </li>
<li>Kirk Waiblinger <a
href="https://github.com/kirkwaiblinger"><code>@​kirkwaiblinger</code></a></li>
<li>mdm317</li>
<li>Ulrich Stark</li>
<li>Yannick Decat <a
href="https://github.com/mho22"><code>@​mho22</code></a></li>
<li>Yukihiro Hasegawa <a
href="https://github.com/y-hsgw"><code>@​y-hsgw</code></a></li>
</ul>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
<h2>v8.50.1</h2>
<h2>8.50.1 (2025-12-22)</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md"><code>@​typescript-eslint/eslint-plugin</code>'s
changelog</a>.</em></p>
<blockquote>
<h2>8.52.0 (2026-01-05)</h2>
<h3>🚀 Features</h3>
<ul>
<li><strong>eslint-plugin-internal:</strong>
[no-multiple-lines-of-errors] add rule (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11899">#11899</a>)</li>
</ul>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> [no-base-to-string] detect @<a
href="https://github.com/toPrimitive"><code>@​toPrimitive</code></a> and
valueOf (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11901">#11901</a>)</li>
<li><strong>eslint-plugin:</strong> [no-useless-default-assignment]
handle conditional initializer (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11908">#11908</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Josh Goldberg </li>
<li>Ulrich Stark</li>
</ul>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
<h2>8.51.0 (2025-12-29)</h2>
<h3>🚀 Features</h3>
<ul>
<li><strong>eslint-plugin:</strong> add namespace to plugin meta (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11885">#11885</a>)</li>
<li><strong>eslint-plugin:</strong> [no-useless-default-assignment] fix
some cases to optional syntax (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11871">#11871</a>)</li>
</ul>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> [prefer-optional-chain] handle
MemberExpression in final chain position (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11835">#11835</a>)</li>
<li><strong>eslint-plugin:</strong> bump ts-api-utils to 2.2.0 (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11881">#11881</a>)</li>
<li><strong>eslint-plugin:</strong> remove fixable from
no-dynamic-delete rule (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11876">#11876</a>)</li>
<li><strong>eslint-plugin:</strong> fix crash and false positives in
<code>no-useless-default-assignment</code> (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11845">#11845</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<ul>
<li>Josh Goldberg </li>
<li>Kirk Waiblinger <a
href="https://github.com/kirkwaiblinger"><code>@​kirkwaiblinger</code></a></li>
<li>mdm317</li>
<li>Ulrich Stark</li>
<li>Yannick Decat <a
href="https://github.com/mho22"><code>@​mho22</code></a></li>
</ul>
<p>You can read about our <a
href="https://typescript-eslint.io/users/versioning">versioning
strategy</a> and <a
href="https://typescript-eslint.io/users/releases">releases</a> on our
website.</p>
<h2>8.50.1 (2025-12-22)</h2>
<h3>🩹 Fixes</h3>
<ul>
<li><strong>eslint-plugin:</strong> [no-unnecessary-type-assertion]
correct handling of undefined vs. void (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11826">#11826</a>)</li>
<li><strong>eslint-plugin:</strong> [method-signature-style] ignore
methods that return <code>this</code> (<a
href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/11813">#11813</a>)</li>
</ul>
<h3>❤️ Thank You</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/9ddd5712687140a68352978fb76428de53ab789e"><code>9ddd571</code></a>
chore(release): publish 8.52.0</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/6b467b0533b78777fa01128cdeeab1b5326a4550"><code>6b467b0</code></a>
docs: add blog post on revamping the ban-types rule (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11873">#11873</a>)</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/309a38ed83994738323efd78fc31137136a7681a"><code>309a38e</code></a>
fix(eslint-plugin): [no-base-to-string] detect @<a
href="https://github.com/toPrimitive"><code>@​toPrimitive</code></a> and
valueOf (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11">#11</a>...</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/cf79108b6405972fb73f5991e913e1b36de8a67f"><code>cf79108</code></a>
fix(eslint-plugin): [no-useless-default-assignment] handle conditional
initia...</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/a166cea2d00fedd0762ecb87d95bc1f1cf93d528"><code>a166cea</code></a>
feat(eslint-plugin-internal): [no-multiple-lines-of-errors] add rule (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11899">#11899</a>)</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/d1b44c02a86d366139c61ac80c0eb1c63668be7f"><code>d1b44c0</code></a>
chore(deps): update nx monorepo to v22.3.3 (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11848">#11848</a>)</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/95c7c730c254ef5e51843e2f3280977eec53f5b8"><code>95c7c73</code></a>
chore: update deps to latest minor/patch (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11921">#11921</a>)</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/45a7d2bf60afd214046ff76e7feda516b3d7bdb2"><code>45a7d2b</code></a>
chore(typescript-estree): use <code>iterateComments()</code> from
ts-api-utils v2.3 (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11">#11</a>...</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/e4c57f5996a9a3aed8a8c2b02712a9ce37db4928"><code>e4c57f5</code></a>
chore(release): publish 8.51.0</li>
<li><a
href="https://github.com/typescript-eslint/typescript-eslint/commit/c7b698b3821946d4bdeb51239d3b3572e5434893"><code>c7b698b</code></a>
feat(eslint-plugin): add namespace to plugin meta (<a
href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin/issues/11885">#11885</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.52.0/packages/eslint-plugin">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by [GitHub Actions](<a
href="https://www.npmjs.com/~GitHub">https://www.npmjs.com/~GitHub</a>
Actions), a new releaser for
<code>@​typescript-eslint/eslint-plugin</code> since your current
version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@typescript-eslint/eslint-plugin&package-manager=npm_and_yarn&previous-version=8.39.0&new-version=8.52.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 08:39:24 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
f8d355ce35 Bump react-router-dom from 6.26.0 to 6.30.3 (#17086)
Bumps
[react-router-dom](https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom)
from 6.26.0 to 6.30.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/releases">react-router-dom's
releases</a>.</em></p>
<blockquote>
<h2>react-router-dom-v5-compat@6.4.0-pre.15</h2>
<h3>Patch Changes</h3>
<ul>
<li>Updated dependencies
<ul>
<li>react-router@6.4.0-pre.15</li>
<li>react-router-dom@6.4.0-pre.15</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/remix-run/react-router/blob/main/CHANGELOG.md">react-router-dom's
changelog</a>.</em></p>
<blockquote>
<h2>v6.30.3</h2>
<p>Date: 2026-01-07</p>
<h3>Security Notice</h3>
<p>This release addresses 1 security vulnerability:</p>
<ul>
<li><a
href="https://github.com/remix-run/react-router/security/advisories/GHSA-2w69-qvjg-hvjx">XSS
via Open Redirects</a></li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>Validate redirect locations (<a
href="https://redirect.github.com/remix-run/react-router/pull/14707">#14707</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/remix-run/react-router/compare/react-router@6.30.2...react-router@6.30.3"><code>v6.30.2...v6.30.3</code></a></p>
<h2>v6.30.2</h2>
<p>Date: 2025-11-13</p>
<h3>Security Notice</h3>
<p>This release addresses 1 security vulnerability:</p>
<ul>
<li><a
href="https://github.com/remix-run/react-router/security/advisories/GHSA-9jcx-v3wj-wh4m">Unexpected
external redirect via untrusted paths</a></li>
</ul>
<h3>Patch Changes</h3>
<ul>
<li>Normalize double-slashes in <code>resolvePath</code> (<a
href="https://redirect.github.com/remix-run/react-router/pull/14537">#14537</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/remix-run/react-router/compare/react-router@6.30.1...react-router@6.30.2"><code>v6.30.1...v6.30.2</code></a></p>
<h2>v6.30.1</h2>
<p>Date: 2025-05-20</p>
<h3>Patch Changes</h3>
<ul>
<li>Partially revert optimization added in <code>6.29.0</code> to reduce
calls to <code>matchRoutes</code> because it surfaced other issues (<a
href="https://redirect.github.com/remix-run/react-router/pull/13623">#13623</a>)</li>
<li>Stop logging invalid warning when <code>v7_relativeSplatPath</code>
is set to <code>false</code> (<a
href="https://redirect.github.com/remix-run/react-router/pull/13502">#13502</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/remix-run/react-router/compare/react-router@6.30.0...react-router@6.30.1"><code>v6.30.0...v6.30.1</code></a></p>
<h2>v6.30.0</h2>
<p>Date: 2025-02-27</p>
<h3>Minor Changes</h3>
<ul>
<li>Add <code>fetcherKey</code> as a parameter to
<code>patchRoutesOnNavigation</code> (<a
href="https://redirect.github.com/remix-run/react-router/pull/13109">#13109</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/remix-run/react-router/commit/c662ca366a414bf42624dd6cd20a7c414b2602e3"><code>c662ca3</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14713">#14713</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/98ad6912daec8df0d911f786f18006048efd7ade"><code>98ad691</code></a>
chore: Update version for release (pre-v6) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14710">#14710</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/26b5d4581fb2829dc7eaeaad413de4735173a6eb"><code>26b5d45</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14541">#14541</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/919f8a86b95f0c8956e3820743503d5609f572cd"><code>919f8a8</code></a>
chore: Update version for release (pre-v6) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/14540">#14540</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/3f2400e9a7e255953afef3d29126db2efb6c08ab"><code>3f2400e</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13647">#13647</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/25a264d87bce0bd5f0170e99a3dcad3a61a5f080"><code>25a264d</code></a>
chore: Update version for release (pre-v6) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13638">#13638</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/e4ba5224c911e070b1eabd12cff2aa581270dfb3"><code>e4ba522</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13128">#13128</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/f0bc784ce8951cc5ed67bf6d48d9c132b9bdc621"><code>f0bc784</code></a>
chore: Update version for release (pre-v6) (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/13111">#13111</a>)</li>
<li><a
href="https://github.com/remix-run/react-router/commit/d9ed8241d677de006a9bfe808d32fe4582184dad"><code>d9ed824</code></a>
Fix up changelogs</li>
<li><a
href="https://github.com/remix-run/react-router/commit/cc8b8cebe241c1464424e1a66d1f3e3bfa5bdd4d"><code>cc8b8ce</code></a>
chore: Update version for release (<a
href="https://github.com/remix-run/react-router/tree/HEAD/packages/react-router-dom/issues/12911">#12911</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/remix-run/react-router/commits/react-router-dom@6.30.3/packages/react-router-dom">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by [GitHub Actions](<a
href="https://www.npmjs.com/~GitHub">https://www.npmjs.com/~GitHub</a>
Actions), a new releaser for react-router-dom since your current
version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=react-router-dom&package-manager=npm_and_yarn&previous-version=6.26.0&new-version=6.30.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 08:27:15 +00:00
878e040907 i18n - docs translations (#17070)
Created by Github action

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Enhances Apps documentation across multiple locales by clarifying
object base fields behavior.
> 
> - Adds a `Note` in localized `apps.mdx` pages (ar, cs, de, it, ro, ru,
tr) stating that standard base fields (e.g., `name`, `createdAt`,
`updatedAt`, `createdBy`, `position`, `deletedAt`) are created
automatically and should not be included in `fields` when using
`defineObject()`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
87a5ecd0b6. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: github-actions <github-actions@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2026-01-12 08:11:42 +00:00
Abdullah.andGitHub 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
Félix MalfaitandGitHub 57363c2127 Fix orderBy columns missing from SELECT in DISTINCT subquery (#17079)
## Description

Fixes a bug where queries with relation field + scalar field ordering
would fail with:
```
column distinctAlias.person_position does not exist
```

## Root Cause

When a GraphQL query orders by columns that are **not in the selected
fields**, TypeORM's DISTINCT subquery fails because it expects those
columns in the inner SELECT with alias format (e.g., `person_position`).

The issue only manifests when:
1. A filter is applied (triggers DISTINCT path in TypeORM)
2. OrderBy includes columns NOT in the GraphQL selection
3. Example: query selects only `id`, but orders by `position`

## The Fix

`addRelationOrderColumnsToBuilder` now accepts `columnsToSelect` and
adds orderBy columns via `addSelect()` only if they're **NOT** already
in the selected columns:

- **Relation orderBy columns**: Always added (never in columnsToSelect)
- **Main entity orderBy columns**: Added only when not already selected

This ensures all orderBy columns are present in TypeORM's inner SELECT
for the DISTINCT subquery.

## Test Plan

Added integration test for the exact failing scenario:
- Filter with `neq` (triggers DISTINCT path)
- Multiple orderBy: relation field + scalar field  
- Minimal field selection (only `id`, not `position`)

## Related

Regression introduced in #17021 which added nested sort support.
2026-01-11 14:19:05 +01:00
20f62e05f5 fix(search): add support for searching by additional emails, phones, and secondary links (#17034)
## Summary
- Add `additionalEmails` (EMAILS type) to tsvector search expression
- Add `additionalPhones` (PHONES type) to tsvector search expression  
- Add `secondaryLinks` (LINKS type) to tsvector search expression

This enables searching for people/companies by their secondary contact
information, not just primary values.

## Test plan
- [x] Unit tests for all three composite field types (16 tests passing)
- [x] Integration tests for searching by secondary email, work email,
partial domain
- [x] Integration tests for searching by additional phone numbers
- [x] Integration test for searching by secondary link URL
- [x] Lint passes

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-10 15:24:46 +00:00
martmullandGitHub 936ec06fe8 Improve application ast 3 (#17061)
- fix should generate
- fix errors not displayed properly
2026-01-10 14:52:28 +00:00
Thomas TrompetteandGitHub 3acc87a620 [SSE] Add backend for SSE subscriptions (#17022)
- moved a few gql types to twenty shared to re-use in server
- added a new endpoint, onEventSubscription that expect a streamId to
create a connection
- two new endpoints to store queries in Redis
- updated the existing batch channel to directly use object record type
2026-01-10 14:44:02 +00:00
neo773andGitHub 87fb25c703 IMAP edge cases (#17065)
Fixes IMAP edge case. We had a maximum call stack reached crash if the
array was very large for some folders. Plus some minor perf improvement.


https://twenty-v7.sentry.io/issues/6997180505/events/652c69da1be944aab1c87ac2e6a06c30/
2026-01-10 14:26:07 +00:00
MatchandGitHub 9e22c74b2d Fix sort direction toggle when clicking on existing sort (#17046)
Closes #17032

  Summary

When a sort is already applied to a column, clicking "Sort" from the
column header dropdown now toggles the sort direction (ASC → DESC or
DESC → ASC) instead of doing nothing.

  Problem

Previously, clicking "Sort" on a column that already had a sort applied
would always try to create a new sort with ASC direction. Since the
upsertRecordSort function updates an existing sort with the same field,
this effectively did nothing when the sort was already ASC—which felt
unintuitive.

  Solution

  Modified useHandleToggleColumnSort to:
  - Check if a sort already exists for the clicked field
  - If it exists, toggle the direction
- If it doesn't exist, create a new sort with ASC direction (existing
behavior)

---

Contribution by Gittensor, see my contribution statistics at
https://gittensor.io/miners/details?githubId=132382032
2026-01-10 14:04:26 +00:00
d4d5f57347 i18n - docs translations (#17064)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-10 14:36:59 +01:00
Félix MalfaitandGitHub a8331dc43e feat: add case-insensitive sorting for text fields (#17023)
## Context

Text fields were being sorted case-sensitively on the backend (e.g.,
'Apple', 'apple', 'Banana' would sort as 'Apple', 'Banana', 'apple').
This resulted in unexpected sorting behavior that differed between the
frontend Apollo cache sorting and backend database sorting.

## Changes

### Backend (packages/twenty-server)

- **`graphql-query-order.parser.ts`**:
- Added `shouldUseCaseInsensitiveOrder()` helper that returns `true` for
TEXT, SELECT, and MULTI_SELECT fields
- Added `buildOrderByColumnExpression()` method that wraps column
expressions with `LOWER()` for case-insensitive sorting
- Updated `parse()` and `parseObjectRecordOrderByForScalarField()` to
use the new helpers
- Updated `parseObjectRecordOrderByForRelationField()` to apply LOWER()
to nested text fields

- **`parse-composite-field-for-order.util.ts`**:
- Added `shouldUseCaseInsensitiveOrder()` helper for composite subfields
- Updated composite field parsing to apply `LOWER()` to subfields of
type TEXT (e.g., `name.firstName`, `name.lastName`)

### Frontend (packages/twenty-front)

- **`sort.ts`**:
- Updated `sortAsc()` to use case-insensitive comparison
(`toLowerCase()`) for string values
- `sortDesc()` automatically benefits from this since it delegates to
`sortAsc()`
  - Ensures Apollo cache sorting matches backend behavior

## Example

Before:
```sql
ORDER BY "person"."name" ASC
```
Result: ['Apple', 'Banana', 'apple', 'cherry']

After:
```sql
ORDER BY LOWER("person"."name") ASC
```
Result: ['apple', 'Apple', 'Banana', 'cherry']

## Testing

- Manual testing of sorting on People and Companies views
- Verified frontend cache sorting matches backend results
2026-01-10 14:05:56 +01:00
Félix MalfaitandGitHub 1a5675d63e feat: add sorting on relation fields (Many-to-One) (#17021)
## Summary

This PR enables sorting records by fields of related objects. For
example, sorting **People by their Company's name**.

### Before
Only scalar and composite fields could be sorted. Relation fields showed
in the sort dropdown but produced errors.

### After
Many-to-One relation fields can now be sorted using the related object's
**label identifier field** (e.g., Company's `name`).

---

## Changes

### Frontend
- Added `RELATION` to sortable field types (restricted to `MANY_TO_ONE`
relations)
- New `getOrderByForRelationField()` generates nested orderBy structures
using the related object's label identifier
- Updated `turnSortsIntoOrderBy()` to handle relation fields by looking
up related object metadata

### Backend
- Extended `GraphqlQueryOrderFieldParser.parse()` to detect nested
relation ordering like `{ company: { name: 'AscNullsLast' } }`
- Returns `ParseOrderByResult` containing both `orderBy` conditions and
`relationJoins` info
- Added LEFT JOINs for relation ordering in `applyOrderToBuilder()`
- Added `addRelationOrderColumnsToBuilder()` for TypeORM DISTINCT
compatibility

### Tests
- Added unit tests for `filterSortableFieldMetadataItems`,
`getOrderByForRelationField`, and `turnSortsIntoOrderBy`
- Added integration tests covering ascending/descending order and
composite label identifiers

---

## TypeORM Bug Workaround

We encountered a significant TypeORM limitation when implementing this
feature. When using `getMany()` with `ORDER BY` on joined relation
columns, TypeORM generates a DISTINCT subquery that has specific
requirements:

### Issue 1: Alias Parsing
TypeORM's `orderBy()` method fails with **"alias not found"** when using
quoted SQL identifiers like `"company"."name"`. TypeORM internally
expects unquoted property paths (e.g., `company.name`) for its alias
resolution mechanism.

### Issue 2: setFindOptions Clears addSelect
`setFindOptions({ select })` **clears any previously added `addSelect()`
columns**. This caused `"column distinctAlias.company_name does not
exist"` errors because the relation columns needed for ORDER BY were
being removed.

### Solution
We split the logic into two methods:
1. `applyOrderToBuilder()` - adds JOINs and ORDER BY (before
`setFindOptions`)
2. `addRelationOrderColumnsToBuilder()` - adds relation columns for
SELECT (AFTER `setFindOptions`)

This ensures the relation columns are present in the final SQL query's
SELECT clause with the proper underscore aliases (`company_name`) that
TypeORM's DISTINCT subquery expects.

**Related TypeORM issue**:
https://github.com/typeorm/typeorm/issues/9921

---

## Screenshots/Demo

_Add screenshots if applicable_
2026-01-10 11:02:16 +01:00
5a33b36b85 i18n - docs translations (#17059)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-10 10:41:34 +01:00
9b6eb8b80a fix onboarding for messaging (#16729)
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-09 20:17:04 +00:00
EtienneandGitHub f3d89ca9b9 Fix cleaning command (#17040)
Previous behavior:

Used billingSubscription.updatedAt (when the subscription record was
last modified)
Problem: updatedAt changes for ANY update, not just status changes,
making it unreliable for tracking when payment problems started

Current behavior:

Uses currentPeriodStart when subscription status is Unpaid or Canceled
Why it works: WORKSPACE_INACTIVE_DAYS_BEFORE_SOFT_DELETION is shorter
than the minimum billing interval (1 month). Then if a workspace is
unpaid for the entire current billing period, it will always exceed the
deletion threshold before the next period starts

Ideal fix:
Track workspace.suspendedAt explicitly, giving you the exact timestamp
of when payment problems began, regardless of billing periods.
2026-01-09 18:11:41 +00:00
Baptiste DevessierandGitHub 50eb639304 Center lock icon when widget isn't accessible (#17055)
## Before

<img width="1348" height="770" alt="CleanShot 2026-01-09 at 18 11 43@2x"
src="https://github.com/user-attachments/assets/43758ada-09af-4c67-ba53-77f026f53e56"
/>

## After

<img width="1310" height="756" alt="CleanShot 2026-01-09 at 18 11 16@2x"
src="https://github.com/user-attachments/assets/12fc84b2-0654-410c-bb77-b499ad17ba22"
/>
2026-01-09 17:22:39 +00:00
Abdul RahmanGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
151731c05d If else node followup changes (#16974)
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-01-09 17:20:58 +00:00
d655061901 i18n - translations (#17057)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 18:32:15 +01:00
Baptiste DevessierandGitHub b906b4353c feat: drop empty states and instead render nothing (#17049)
Dropping the empty state as currently seen in production.

## Before

<img width="3738" height="2442" alt="CleanShot 2026-01-09 at 16 09
37@2x"
src="https://github.com/user-attachments/assets/ed6e2132-4a07-4673-ab59-dea37e9949e9"
/>

## After


https://github.com/user-attachments/assets/32566a17-d5b6-4d62-80d5-144ba0050276
2026-01-09 16:55:17 +00:00
Félix MalfaitandGitHub 9a2f18660f Set canonical url for docs (#17052)
As per title
2026-01-09 18:03:27 +01:00
neo773andGitHub a0b2aa207f Fix messaging 404 handling (#17041)
`MessageImportExceptionHandlerService.handleSyncCursorErrorException()`
was calling `messageChannelSyncStatusService.markAsFailed()`
instead of

`messageChannelSyncStatusService.resetAndMarkAsMessagesListFetchPending()`

Also adds a new command `MessagingTriggerMessageListFetchCommand` for
faster local development speed
2026-01-09 16:35:12 +00:00
Baptiste DevessierandGitHub 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
b1c821b0e3 Implement hide empty groups for grouped table view (#16494)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2026-01-09 17:31:22 +01:00
308973d7ca i18n - docs translations (#17036)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 17:26:06 +01:00
109c47af68 i18n - translations (#17050)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 16:21:33 +01:00
Félix MalfaitandGitHub 67ae17961e Fix MS Office preview for private/local URLs (#17044)
## Summary

Fixes #16900 - MS Office documents (doc, docx, ppt, pptx, xls, xlsx,
odt) cannot be previewed when hosted on local/private networks.

## Problem

Microsoft's Office Online viewer (`view.officeapps.live.com`) requires
documents to be publicly accessible from the internet. For self-hosted
Twenty instances or local development, files are not reachable by
Microsoft's servers, causing the viewer to fail with "An error
occurred".

## Solution

Detect private/local URLs upfront and show a helpful message with a
download button instead of letting the viewer fail silently.

**Detected private URLs:**
- `localhost`, `127.0.0.1`, `[::1]`
- Private IP ranges: `10.x.x.x`, `172.16-31.x.x`, `192.168.x.x`
- Local domain patterns: `.local`, `.localhost`, `.internal`

## Alternatives Explored (that don't work)

We investigated more sophisticated detection approaches:

1. **postMessage events** - Microsoft's viewer doesn't send any error
messages we can listen to
2. **Fetching the embed URL** - Blocked by CORS (Microsoft doesn't set
`Access-Control-Allow-Origin`)
3. **Reading iframe content** - Cross-origin restrictions prevent
JavaScript access

The URL-based detection is the most reliable approach for catching the
common cases where preview will definitely fail.

## Testing

1. Upload an Office file (docx, pptx, xlsx) on a local Twenty instance
2. Try to preview it
3. Should see "This file cannot be previewed because it is hosted
locally" with a Download button
2026-01-09 14:58:34 +00:00
martmullandGitHub 3509838a3a Improve application ast 2 (#17045)
fix some issues with cli tools
2026-01-09 14:54:13 +00:00
52e859e5a7 i18n - translations (#17048)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 15:38:08 +01:00
d7b7e9def1 Cascade delete Task targets when tasks deleted - logic + migration command (#17019)
Co-authored-by: prastoin <paul@twenty.com>
2026-01-09 14:10:40 +00:00
Lucas BordeauandGitHub 2fb099e198 Made the code more resilient to stale value prop in date filter (#17038)
Fixes : https://github.com/twentyhq/twenty/issues/17035

There was a bad pattern which risked introduce this bug in
`turnRecordFilterIntoRecordGqlOperationFilter` after recent refactor of
date logic and date filters, which didn't create any bug during dev time
because it wasn't tested with value combinations that existed before the
refactor.

Code has been re-organized to make it resilient to any wrong value
combination.

Also fixed a small bug that appeared during QA with `DATE` filter type,
which was blocking the save button from disappearing after a save.
2026-01-09 14:09:57 +00:00
martmullandGitHub 40eef5c464 Improve application ast (#17016)
# Summary

- Introduces a new, flexible folder structure for Twenty SDK
applications using file suffix-based entity detection
- Adds defineApp, defineFunction, defineObject, and defineRole helper
functions with built-in validation
- Refactors manifest loading to use jiti runtime evaluation for
TypeScript config files
- Separates validation logic into dedicated module with comprehensive
error reporting

  # New Application Folder Structure

Applications now use a convention-over-configuration approach where
entities are detected by their file suffix, allowing flexible
organization within the src/app/ folder.

  # Required Structure

    my-app/
    ├── package.json
    ├── yarn.lock
    └── src/
        ├── app/
│ └── application.config.ts # Required - main application configuration
└── utils/ # Optional - handler implementations & utilities

  # Entity Detection by File Suffix

    - *.object.ts - Custom object definitions
    - *.function.ts - Serverless function definitions
    - *.role.ts - Role definitions

  # Supported Folder Organizations

  ## Traditional (by type):
    src/app/
    ├── application.config.ts
    ├── objects/
    │   └── postCard.object.ts
    ├── functions/
    │   └── createPostCard.function.ts
    └── roles/
        └── admin.role.ts

  ## Feature-based:
    src/app/
    ├── application.config.ts
    └── post-card/
        ├── postCard.object.ts
        ├── createPostCard.function.ts
        └── postCardAdmin.role.ts

  ## Flat:
    src/app/
    ├── application.config.ts
    ├── postCard.object.ts
    ├── createPostCard.function.ts
    └── admin.role.ts

  # New Helper Functions

  ## defineApp(config)

    import { defineApp } from 'twenty-sdk';

    export default defineApp({
      universalIdentifier: '4ec0391d-...',
      displayName: 'My App',
      description: 'App description',
      icon: 'IconWorld',
    });

  ## defineObject(config)

    import { defineObject, FieldType } from 'twenty-sdk';

    export default defineObject({
      universalIdentifier: '54b589ca-...',
      nameSingular: 'postCard',
      namePlural: 'postCards',
      labelSingular: 'Post Card',
      labelPlural: 'Post Cards',
      icon: 'IconMail',
      fields: [
        {
          universalIdentifier: '58a0a314-...',
          type: FieldType.TEXT,
          name: 'content',
          label: 'Content',
        },
      ],
    });

  ## defineFunction(config)

    import { defineFunction } from 'twenty-sdk';
    import { myHandler } from '../utils/my-handler';

    export default defineFunction({
      universalIdentifier: 'e56d363b-...',
      name: 'My Function',
      handler: myHandler,
      triggers: [
        {
          universalIdentifier: 'c9f84c8d-...',
          type: 'route',
          path: '/my-route',
          httpMethod: 'POST',
        },
      ],
    });

  ## defineRole(config)

    import { defineRole, PermissionFlag } from 'twenty-sdk';

    export default defineRole({
      universalIdentifier: 'b648f87b-...',
      label: 'App User',
      objectPermissions: [
        {
          objectNameSingular: 'postCard',
          canReadObjectRecords: true,
        },
      ],
      permissionFlags: [PermissionFlag.UPLOAD_FILE],
    });

  # Test plan

    - Verify npx twenty app sync works with new folder structure
    - Verify npx twenty app dev works with new folder structure
    - Verify validation errors display correctly for invalid configs
- Verify all three folder organization styles work (traditional,
feature-based, flat)
    - Run existing E2E tests to ensure backward compatibility
2026-01-09 13:06:30 +00:00
defc988d7f i18n - translations (#17037)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 11:50:09 +01:00
Abdullah.andGitHub 2bb3b41e62 feat: improve the design of the fields widget (#17003)
Closes [2005](https://github.com/twentyhq/core-team-issues/issues/2005).

This is how it looks like and I have a feeling that it matches the Figma
design. I am not sure if we need to remove more padding as mentioned in
the issue since removing it takes it away from the Figma design. Please
review and let me know.

<img width="329" height="807" alt="image"
src="https://github.com/user-attachments/assets/1d9051e4-81fc-4c43-9aa8-54857bbd8f8f"
/>

<br />
<br />

Figma design itself:

<img width="912" height="1052" alt="image"
src="https://github.com/user-attachments/assets/4174a4a3-22af-4afc-8632-a0838ec5af08"
/>

In terms of data that we receive, I believe it would be handled by
Fields Configuration coming from the Backend, so General and Other are
decided at that layer, unless I am missing something.
2026-01-09 10:27:10 +00:00
Baptiste DevessierandGitHub 8fc0bb3ed7 Use canvas layout for all advanced RPL widgets (#17028)
## Before

<img width="3456" height="2160" alt="CleanShot 2026-01-08 at 18 46
32@2x"
src="https://github.com/user-attachments/assets/50e5f82f-b8e4-40d9-b5d9-4faf193cc2fd"
/>


## After

<img width="3456" height="2160" alt="CleanShot 2026-01-08 at 18 46
59@2x"
src="https://github.com/user-attachments/assets/badf46ff-b4c1-471c-a815-24673759fcac"
/>
2026-01-09 08:42:52 +00:00
020ab1f63a i18n - docs translations (#17029)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-09 09:25:07 +01:00