Commit Graph

4779 Commits

Author SHA1 Message Date
Marie 8379e19587 [Apps] Small improvements (#17129)
- Fix undefined in breadcrumbs
<img width="783" height="220" alt="breadcrumbs_bad"
src="https://github.com/user-attachments/assets/557648da-f825-4bf6-b66f-2ac3992eeab1"
/>
- Make role required in app definition
2026-01-14 17:28:51 +00:00
Thomas Trompette 93aef30046 Add feature flag for sse (#17152)
As title
2026-01-14 14:20:45 +00:00
nitin a9e07d4f97 [Dashboards] disable chart drill-down and pointer cursor for relation group-by fields (#17150) 2026-01-14 14:15:33 +00:00
Lucas Bordeau 6b14cfaa89 Fixes two critical bugs for DATE type (#17143)
This PR fixes two critical bugs with the DATE type, following up the
recent refactor around dates and time zones :
https://github.com/twentyhq/twenty/pull/16544

There are a lot of related bugs in Sentry, this PR should fix all bugs
that are of the form :

`Cannot parse: 2026-02-04T00:00:00.000Z`

# `node-postgres` date type

The package `node-postgres`, used by TypeORM, returns by default a Date
object for the date OID type.

But we can change this behavior without patching anything.

See the documentation for `pg-types` :
https://github.com/brianc/node-pg-types

Our fix is to call `setTypeParser` from `pg` to have the postgres "date"
type returned as a string always.

```ts
export const setPgDateTypeParser = () => {
  types.setTypeParser(PG_DATE_TYPE_OID, (val: string) => val);
};
```

Then in server's main.ts : 

```ts
const bootstrap = async () => {
  setPgDateTypeParser();
```

## Are we safe with this very low-level fix ?

Since TypeORM bypasses a string value returned by `pg` we are safe with
this modification at a very low-level.

```ts
else if (columnMetadata.type === "date") {
  value = DateUtils.mixedDateToDateString(value)
}
```


https://github.com/typeorm/typeorm/blob/0ec4079cd3760dc49247a02c54415f16a2a51766/src/driver/postgres/PostgresDriver.ts#L838

```ts
/**
* Converts given value into date string in a "YYYY-MM-DD" format.
*/
static mixedDateToDateString(value: string | Date): string {
  if (value instanceof Date) {
      return (
          this.formatZerolessValue(value.getFullYear(), 4) +
          "-" +
          this.formatZerolessValue(value.getMonth() + 1) +
          "-" +
          this.formatZerolessValue(value.getDate())
      )
  }

  return value
}
```


https://github.com/typeorm/typeorm/blob/6f3788b83730463e3b787b2a98bb41695e13caf8/src/util/DateUtils.ts#L28

For reference the original type parser seems to be configured in
node-pg-types, on the 1182 OID, which is an array of date / 1082 OID,
this type parser calls another small library `postgres-date` which
creates a JS Date. I couldn't find a type parser explicitly on 1082 in
the stack TypeORM -> node-postgres -> node-pg-types -> postgres-date

```ts
register(1182, parseStringArray) // date[]
``` 


https://github.com/brianc/node-pg-types/blob/26bfe645a8ddc0c73830b1b8c63f2c4f8265b24f/lib/textParsers.js#L168C19-L168C45

```ts
 static parse (dateString) {
  return new PGDateParser(dateString).getJSDate()
}
```


https://github.com/bendrucker/postgres-date/blob/b3060560ed62c250f7800d29e4b68a9d5a0622bd/index.js#L285


# Calendar view mixing DATE and DATE_TIME

At the time of the refactor, DATE type wasn't properly tested with
calendar view, thus the drag and drop of a card with a calendar view on
a DATE field and not a DATE_TIME field, was not working, this is now
fixed.
2026-01-14 13:38:24 +00:00
Thomas Trompette ef8d7c18c1 Set back amount micros (#17124)
The amount to amount micros in UI breaks variable. Setting back amount
micros in UI with a hint

<img width="399" height="178" alt="Capture d’écran 2026-01-13 à 15 54
04"
src="https://github.com/user-attachments/assets/52f53a78-05a8-421d-80fe-f5cd0e8aad19"
/>
2026-01-14 14:18:28 +01:00
Félix Malfait 245bd510ae chore: cleanup repository root structure (#17147)
## Summary

This PR reduces clutter at the repository root to improve navigation on
GitHub. The README is now visible much sooner when browsing the repo.

## Changes

### Deleted from root
- `nx` wrapper script → use `npx nx` instead
- `render.yaml` → no longer used
- `jest.preset.js` → inlined `@nx/jest/preset` directly in each
package's jest.config
- `.prettierrc` → moved config to `package.json`
- `.prettierignore` → patterns already covered by `.gitignore`

### Moved/Consolidated
| From | To |
|------|-----|
| `Makefile` | `packages/twenty-docker/Makefile` (merged) |
| `crowdin-app.yml` | `.github/crowdin-app.yml` |
| `crowdin-docs.yml` | `.github/crowdin-docs.yml` |
| `.vale.ini` | `.github/vale.ini` |
| `tools/eslint-rules/` | `packages/twenty-eslint-rules/` |
| `eslint.config.react.mjs` |
`packages/twenty-front/eslint.config.react.mjs` |

## Result

Root items reduced from ~32 to ~22 (folders + files).

## Files updated

- GitHub workflow files updated to reference new crowdin config paths
- Jest configs updated to use `@nx/jest/preset` directly
- ESLint configs updated with new import paths
- `nx.json` updated with new paths
- `package.json` now includes prettier config and updated workspace
paths
- Dockerfile updated with new eslint-rules path
2026-01-14 12:56:30 +00:00
Thomas Trompette ec87b29286 Move query matching before publication (#17121)
- new channel EVENT_STREAM_CHANNEL based on event stream id
- on event, perform the matching and publish only to the right streams
- store a list of active streams per workspace
- store the user id along with the queries for each stream

Bonus:
- remove onSubscriptionMatch
2026-01-14 12:29:12 +00:00
github-actions[bot] 2845f7e666 i18n - translations (#17132)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-14 00:01:01 +01:00
Manikanth Martha 55cc7f809e feat(auth): Show Last used label on SSO sign-in method (#17093)
Fixes #17006 

## Changes
Added `lastAuthenticateWorkspaceSsoMethodState` Recoil atom to track the
last used SSO method, persisted in localStorage
Updated `SignInUpWithGoogle` component to display a "Last" pill badge
when Google was the last auth method
Updated `SignInUpWithMicrosoft` component to display a "Last" pill badge
when Microsoft was the last auth method
Updated `SignInUpWithSSO` component to display a "Last" pill badge when
SSO was the last auth method.


The state is saved after successful authentication redirect, ensuring it
persists across sessions

## Implementation Details
Uses existing `localStorageEffect` for persistence across browser
sessions
Leverages the existing Pill component from twenty-ui with blue accent
color
The label is positioned on the right border of the button using absolute
positioning
State is saved in the `useAuth` hook during Google/Microsoft sign-in and
in the SSO login component

<img width="684" height="608" alt="image"
src="https://github.com/user-attachments/assets/629a1599-aab0-44e4-b684-ae91a8e725fd"
/>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Highlights the most recently used authentication method and preserves
it across sessions.
> 
> - Introduces `AuthenticatedMethod` enum and
`lastAuthenticatedMethodState` (persisted via `localStorageEffect`) and
preserves it through `useAuth.clearSession`
> - Displays a "Last" pill via `LastUsedPill` on `SignInUpWithGoogle`,
`SignInUpWithMicrosoft`, `SignInUpWithSSO`, and
`SignInUpWithCredentials` when appropriate; adds
`StyledSSOButtonContainer` for badge positioning
> - Adds `useHasMultipleAuthMethods` to detect when to show the badge;
threads `isGlobalScope` to relevant components
> - Sets last-used method on click/submit in SSO and credentials flows
(`useSignInUp`, SSO button handlers)
> - Refactors `SignInUpGlobalScopeForm` to use `SignInUpWithCredentials`
and updates `SignInUp` title logic for global scope (e.g., "Welcome to
Twenty")
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
70d552760916e7d5a8c83a33437585ca376253fc. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2026-01-13 23:50:38 +01:00
Raphaël Bosi 869a0a7cf4 Hardcode workflow objects and dashboards to be last in the navigation drawer (#17123)
Closes https://github.com/twentyhq/core-team-issues/issues/2058

We settled on a simpler solution by just hardcoding the objects order
for now. We will change this once it's possible to reorder the workspace
favorites with drag and drop.
2026-01-13 16:24:14 +00:00
nitin e73aa80e73 [Dashboards] add primary axis select gap fill for bar and line charts (#17098)
closes https://github.com/twentyhq/core-team-issues/issues/2056


https://github.com/user-attachments/assets/44eb2704-9ea9-4f2b-8941-6dd5c12d6276
2026-01-13 10:25:58 +00:00
nitin 110cef2ccf fix rich text widget's side menu handle (#17113)
before - 



https://github.com/user-attachments/assets/283a1ed6-19e9-4a4d-ba4f-5bac7d4a23ef


after - 


https://github.com/user-attachments/assets/778a45af-fb59-4e21-aa53-290461c4d159
2026-01-13 10:00:38 +00:00
Abdullah. 2c8d3f02e1 feat: upgrade to Storybook version 10 (#17110)
Upgraded to Storybook 10. We still use `@storybook/test-runner` for
testing since it appears it'd require more work to move from Jest to
Vitest than I initially anticipated, but I completed this PR to fix
`storybook:serve:dev` - it takes time to load, but it works the way it
used to with Storybook 8.


https://github.com/user-attachments/assets/7afc32c6-4bcf-4b37-b83b-8d00d28dda15
2026-01-13 08:18:07 +00:00
github-actions[bot] 5b25ddd5b4 i18n - translations (#17108)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 19:22:48 +01:00
Lucas Bordeau 04a370e043 Implemented SSE subscription mechanism on the frontend (#17017)
This PR is a follow-up of https://github.com/twentyhq/twenty/pull/16966
and implements a new mechanism to handle SSE events.

It creates only one event stream per browser tab, then use mutations to
tell the backend which query to listen to, without re-mounting the event
stream connexion.

Then each event that comes from this unique subscription is then
dispatched in a new JavaScript CustomEvent, per queryId, on which
specific hooks add an event listener.

This PR introduces the generic tooling as well as the handling of update
events on table.
2026-01-12 18:58:46 +01:00
Thomas des Francs d7638a9075 Fix settings data model tables to take full width and align columns (#17104)
## Summary
- Updated Relations and Fields tables in the object detail settings page
to use flexible width (`1fr`) for the Name column instead of fixed
pixels
- Aligned column widths between both tables (`1fr 148px 148px 36px`) so
the App and Type/Data type columns line up

## Test plan
- [ ] Navigate to Settings > Data model > select any object (e.g.,
Companies)
- [ ] Verify the Relations table rows take the full available width
- [ ] Verify the Fields table rows take the full available width
- [ ] Verify the App and Type/Data type columns are aligned between both
tables
2026-01-12 18:58:29 +01:00
martmull bcc6b3cd21 Fix agent app setting section (#17105)
## Before

<img width="2616" height="2012" alt="image"
src="https://github.com/user-attachments/assets/40c8c12d-aa06-42d1-9cc8-4644dbf64318"
/>


## After

<img width="640" height="702" alt="image"
src="https://github.com/user-attachments/assets/25d924fb-82d1-4c95-9285-2b0bac68e250"
/>
2026-01-12 18:58:18 +01:00
github-actions[bot] 1c2fda30bd i18n - translations (#17106)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 18:58:01 +01:00
Thomas des Francs b951757220 fix: use theme-aware background color for billing credits progress bar (#17103)
## Summary
- Fixed the billing credits progress bar background color in dark mode
- The background was hardcoded to `BACKGROUND_LIGHT.tertiary`, causing
it to always display a light color regardless of the current theme
- Changed to use `theme.background.tertiary` to properly respect
dark/light mode

## Test plan
- [x] Navigate to Settings > Billing in dark mode
- [x] Verify the credits progress bar background matches the tertiary
background color (dark in dark mode)
- [x] Verify it still looks correct in light mode

Figma reference:
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=64812-242606&m=dev
2026-01-12 18:53:44 +01:00
Weiko c795b8c52a RLS FE implementation (#17062)
## Summary
This PR introduces row-level security (RLS) permissions for roles in the
frontend, allowing fine-grained access control at the record level.
Users can now define permission rules that determine which specific
records a role can access based on dynamic conditions and filters.
## What's Changed
Implemented UI for configuring record-level permissions on object
permissions screens
Added support for defining permission predicates using filter conditions
(similar to advanced filters)
Introduced variable picker for dynamic permission rules (e.g., "me"
context for user-specific access)
Built predicate conversion layer to sync UI state with backend
permission structure
Extended GraphQL schema with mutations for upserting row-level
permission predicates
Fixed handling of orphaned RLS groups to prevent data inconsistencies
Added enterprise key validation for RLS features
The implementation enables scenarios like "users can only see their own
records" or "users can access records associated with their team."

<img width="687" height="702" alt="Screenshot 2026-01-09 at 23 07 02"
src="https://github.com/user-attachments/assets/33fe736e-6cbf-40bd-b2eb-c8a90c8d21bc"
/>

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-12 17:39:17 +00:00
github-actions[bot] 493f0575ea i18n - translations (#17097)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-01-12 14:29:26 +01:00
Raphaël Bosi 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
github-actions[bot] 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
nitin 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 Bordeau 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
Baptiste Devessier 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
salmonumbrella 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
Arun 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
nitin 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 Waseem 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
Abdullah. 5240a1818f feat: upgrade Storybook to version 9 (#17077)
Upgraded from 8.6.15 to 9.1.17 in two steps: 
- 8.6.15 -> 9.0.0 
- 9.0.0  -> 9.1.17

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

Additionally, once we upgrade to Version 10 successfully, I will start
looking into integrating the official Vitest add-on.
2026-01-11 13:54:41 +00:00
martmull 936ec06fe8 Improve application ast 3 (#17061)
- fix should generate
- fix errors not displayed properly
2026-01-10 14:52:28 +00:00
Thomas Trompette 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
Match 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
Félix Malfait 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 Malfait 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
neo773 9b6eb8b80a fix onboarding for messaging (#16729)
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-09 20:17:04 +00:00
Baptiste Devessier 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 Rahman 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
github-actions[bot] 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 Devessier 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
Baptiste Devessier dec2b44808 Generate Field widgets for relations (#17047)
To release version 1, we must ensure feature parity with the current
production version.

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


https://github.com/user-attachments/assets/acffe2f9-0f9b-4eff-bb89-c41f7caf5441
2026-01-09 16:24:35 +00:00
Abdul Rahman 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
github-actions[bot] 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 Malfait 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
Lucas Bordeau 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
github-actions[bot] 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. 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 Devessier 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
nitin aa574bacea [Dashboards] use select option colors when grouping by SELECT/MULTI_SELECT fields (#16973)
closes https://github.com/twentyhq/core-team-issues/issues/2031


https://github.com/user-attachments/assets/16fbfefd-107c-45a3-979c-1f9adbb9d912
2026-01-08 17:36:56 +00:00