Commit Graph

5327 Commits

Author SHA1 Message Date
Félix Malfait 4b6c8d52e5 Improve type safety and remove unnecessary store operations (#18622)
## Summary
This PR improves type safety across the codebase by replacing generic
`any` types with proper TypeScript types, removes unnecessary record
store operations, and adds TODO comments for future refactoring of
useEffect hooks.

## Key Changes

### Type Safety Improvements
- **SettingsAgentTurnDetail.tsx**: Replaced `any` type annotations with
proper `AgentMessage` type from generated GraphQL types
- **useCreateManyRecords.ts**: Added `RecordGqlNode` type for better
type safety when handling mutation responses
- **useLazyFindOneRecord.ts**: Replaced generic `Record<string, any>`
with `Record<string, RecordGqlNode>` for improved type checking

### Removed Unnecessary Operations
- **EventCardCalendarEvent.tsx**: Removed unused
`useUpsertRecordsInStore` hook and its associated useEffect that was
upserting calendar event records to the store
- **EventCardMessage.tsx**: Removed unused `useUpsertRecordsInStore`
hook and its associated useEffect that was upserting message records to
the store

### Conditional Query Execution
- **useLoadCurrentUser.ts**: Made the `FindAllCoreViewsDocument` query
conditional - only executes when `isOnAWorkspace` is true, preventing
unnecessary queries for users not on a workspace

### Documentation
- Added TODO comments in multiple files (`useAgentChatData.ts`,
`useWorkspaceFromInviteHash.ts`, `useGetPublicWorkspaceDataByDomain.ts`,
`useFindManyRecords.ts`, `useSingleRecordPickerPerformSearch.ts`)
referencing PR #18584 for future refactoring of useEffect hooks to avoid
unnecessary re-renders

## Implementation Details
- The removal of store upsert operations suggests these records are
already being managed elsewhere or the operations were redundant
- Type improvements maintain backward compatibility while providing
better IDE support and compile-time checking
- Conditional query execution reduces unnecessary network requests and
improves performance for non-workspace users

https://claude.ai/code/session_01YQErkoHotMvM6VL3JkWAqV

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 17:14:56 +01:00
Félix Malfait b470cb21a1 Upgrade Apollo Client to v4 and refactor error handling (#18584)
## Summary
This PR upgrades Apollo Client from v3.10.0 to v4 and refactors error
handling patterns across the codebase to use a new centralized
`useSnackBarOnQueryError` hook.

## Key Changes

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

## Notable Implementation Details

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

https://claude.ai/code/session_019WGZ6Rd7sEHuBg9sTrXRqJ

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-13 14:59:46 +01:00
Baptiste Devessier 0641e07ca6 Bring back relations notes tasks targets (#18600)
## Demo when view isn't defined (front-end mock)


https://github.com/user-attachments/assets/2414076b-a96e-49ef-af02-c72a8e0e80de

## Demo when view is defined


https://github.com/user-attachments/assets/a94487a3-68ec-4d5f-8b33-d6b7242455d4
2026-03-13 10:57:33 +00:00
Thomas Trompette dfd28f5b4a Separate create draft cases op (#18613)
Bug: When creating a draft from an activated workflow version, the draft
row was inserted into the database without steps and trigger, then
updated with them in a separate operation. The SSE create-one event
fired on the INSERT, causing the frontend to refetch the draft before
the UPDATE — resulting in steps: null and trigger: null, which crashed
the step editor.

Fix: Reorder the operations so steps are duplicated first, then either
insert a new draft or update an existing one with steps and trigger
already populated. The row never exists in the database without complete
data.
2026-03-13 10:43:20 +00:00
Baptiste Devessier 262f9f5fe1 Re-fetch conditional display property in the frontend (#18601) 2026-03-13 08:32:53 +00:00
Copilot a3c392ce8b Reset selected widget when exiting record page layout edit mode (#18603)
## Before


https://github.com/user-attachments/assets/b9720898-3433-488b-b784-1fa78e4e68f7

## After


https://github.com/user-attachments/assets/8f3fdde5-773d-44c4-a0f5-cca683736782

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Devessier <29370468+Devessier@users.noreply.github.com>
2026-03-12 17:55:01 +00:00
Charles Bochet ab13020e2b Fix wrong uuid error on field metadata (#18598)
## Summary
- Same fix as #18590 but applied to `FieldMetadataDTO`
- Changed `universalIdentifier` from `UUID` to `String` type since field
metadata universal identifiers are not necessarily valid UUIDs
- Removed `universalIdentifier` from `FieldFilter` (was using
`UUIDFilterComparison`)
- Updated generated SDK and frontend types accordingly
2026-03-12 18:51:42 +01:00
Weiko 3f420c84d7 Fix Flow tab missing for workflow run (#18602)
## Context
Conditional tab rendering was recently introduced for system objects
that now have record page layouts. However Workflow run is a system
object and has a specific "Flow" tab that was not displayed anymore

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

## After
<img width="1299" height="802" alt="Screenshot 2026-03-12 at 18 09 35"
src="https://github.com/user-attachments/assets/35e1e356-e995-43a2-9207-adc0f67cc426"
/>
2026-03-12 17:25:12 +00:00
github-actions[bot] 0ef4741473 i18n - translations (#18595)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-12 18:17:42 +01:00
Baptiste Devessier 2a6fcfcfb3 Side Panel Sub Page Framework® (#18579)
Replace hard-coded implementations for sub pages in the side panel with
a proper framework
2026-03-12 15:17:29 +00:00
martmull 5bfa4c5c39 Fix wrong uuid error (#18590)
as title

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-12 16:12:30 +01:00
github-actions[bot] 1685d066be i18n - translations (#18591)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-12 15:55:51 +01:00
Thomas Trompette 6a3281a18d Bug fix batches (#18588)
- clear sse state on logout
- fix no record not selectable through keyboard
- fix book a call design
- fix error notif design
2026-03-12 15:55:30 +01:00
Charles Bochet 0897575fd0 Fix flaky return-to-path e2e tests (#18580)
## Summary

Fixes flaky `return-to-path` e2e tests that were failing intermittently
in CI merge queue runs.

**Root cause:** In the multi-workspace environment used by CI
(`IS_MULTIWORKSPACE_ENABLED=true`), navigating to
`localhost:3001/settings/accounts` triggers a full page redirect to
`app.localhost:3001/welcome` via `useRedirectToDefaultDomain`. This
redirect is a hard navigation (not a React Router transition), which
clears all in-memory Jotai state — including the `returnToPathState`
atom that stores the path the user should be redirected to after login.
After the redirect, the app has no memory of the intended destination
and falls back to `/objects/companies`.

**Fix:** Before performing the cross-domain redirect in
`useRedirectToDefaultDomain`, read the `returnToPath` from the Jotai
store and pass it as a URL search parameter. On the new page load,
`useInitializeQueryParamState` picks it up from the URL and re-hydrates
the Jotai atom, preserving the return-to-path across the full page
reload.

## Test plan

- [x] Verified locally against production build (`serve -s build`) with
`IS_MULTIWORKSPACE_ENABLED=true` — 33/33 consecutive passes of
`return-to-path.spec.ts`
- [x] Lint passes (`npx nx lint:diff-with-main twenty-front`)
2026-03-12 15:29:35 +01:00
github-actions[bot] 501fcc737f i18n - translations (#18586)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-12 15:18:16 +01:00
Raphaël Bosi c9deab4373 [COMMAND MENU ITEMS] Remove standard front components (#18581)
All standard command menu items will link to an engine component instead
of standard front components.
2026-03-12 15:18:00 +01:00
Marie c1da7be6d7 Billing for self-hosts (#18075)
## Summary

Implements enterprise licensing and per-seat billing for self-hosted
environments, with Stripe as the single source of truth for subscription
data.

### Components

- **twenty-website** hosts the private key to sign `ENTERPRISE_KEY` and
`ENTERPRISE_VALIDITY_TOKEN`. It communicates with Stripe to emit the
daily `ENTERPRISE_VALIDITY_TOKEN` if the subscription is active, based
on the user's Stripe subscription ID stored in `ENTERPRISE_KEY`.
- **Stripe** is the single source of truth for subscription data
(status, seats, billing).
- **The client** (twenty-server + DB + workers) saves `ENTERPRISE_KEY`
in the `keyValuePair` table (or `.env` if
`IS_CONFIG_VARIABLES_IN_DB_ENABLED` is false) and the daily-renewed
`ENTERPRISE_VALIDITY_TOKEN` in the `appToken` table.
`ENTERPRISE_VALIDITY_TOKEN` is verified client-side using a public key
to grant access to enterprise features (RLS, SSO, audit logs, etc.).

### Flow

1. When requesting an upgrade to an enterprise plan (from **Enterprise**
in settings), the user is shown a modal to choose monthly/yearly
billing, then redirected to Stripe to enter payment details. After
checkout, they land on twenty-website where they are exposed to their
`ENTERPRISE_KEY`, which they paste in the UI. It is saved in the
`keyValuePair` table. On activation, a first `ENTERPRISE_VALIDITY_TOKEN`
with 30-day validity is stored in the `appToken` table.

2. **Every day**, a cron job runs and does two things:
- **Refreshes the validity token**: communicates with twenty-website to
get a new `ENTERPRISE_VALIDITY_TOKEN` with 30-day validity if the Stripe
subscription is still active. If the subscription is in cancellation,
the emitted token has a validity equal to the cancellation date. If it's
no longer valid, the token is not replaced. The cron only needs to run
every 30 days in practice, but runs daily so it's resilient to
occasional failures.
- **Reports seat count**: counts active (non-soft-deleted)
`UserWorkspace` entries and sends the count to twenty-website, which
updates the Stripe subscription quantity with proration. Seats are also
reported on first activation. If the subscription is canceled or
scheduled for cancellation, the seat update is skipped.

3. `ENTERPRISE_VALIDITY_TOKEN` is verified server-side via a public key
to grant access to enterprise features.

### Key concepts

Three distinct checks are exposed as GraphQL fields on `Workspace`:

| Field | Meaning |
|---|---|
| `hasValidEnterpriseKey` | Has any valid enterprise key (signed JWT
**or** legacy plain string) |
| `hasValidSignedEnterpriseKey` | `ENTERPRISE_KEY` is a properly signed
JWT (billing portal makes sense) |
| `hasValidEnterpriseValidityToken` | `ENTERPRISE_VALIDITY_TOKEN` is
present and not expired (expiration depends on signed token payload, not
on "expiresAt" on appToken table which is only indicative) |

Feature access is gated by `isValid()` =
`hasValidEnterpriseValidityToken || hasValidEnterpriseKey` (to support
both new and legacy keys during transition). After transition isValid()
= hasValidEnterpriseValidityToken

### Frontend states

The Enterprise settings page handles multiple states:
- **No key**: show "Get Enterprise" with checkout modal
- **Orphaned validity token** (token valid but no signed key): prompt
user to set a valid enterprise key
- **Active/trialing but no validity token**: show subscription status
with a "Reload validity token" action
- **Active/trialing**: show full subscription info, billing portal
access, cancel option
- **Cancellation scheduled**: show cancellation date, billing portal
- **Canceled**: show billing history link and option to start a new
subscription
- **Past due / Incomplete**: prompt to update payment or restart

### Temporary retro-compatibility: legacy plain-text keys

Previously, enterprise features were gated by a simple check: any
non-empty string in `ENTERPRISE_KEY` granted access. With this PR, we
transition to a controlled system relying on signed JWTs.

To avoid breaking existing self-hosted users:
- **Legacy plain-text keys still grant access** to enterprise features.
`hasValidEnterpriseKey` returns `true` for both signed JWTs and plain
strings, and `isValid()` checks `hasValidEnterpriseKey` as a fallback
when no validity token is present.
- **A deprecation banner** is shown at the top of the app when
`hasValidEnterpriseKey` is `true` but `hasValidSignedEnterpriseKey` is
`false`, informing the user that their key format is deprecated and they
should activate a new signed key.
- **No billing portal or subscription management** is available for
legacy keys since there is no Stripe subscription to manage.

This retro-compatibility will be removed in a future version. At that
point, `isValid()` will only check `hasValidEnterpriseValidityToken`.

### Edge cases

- **Air-gapped / production environments**: for self-hosted clients that
block external traffic (or for our own production), provide a long-lived
`ENTERPRISE_VALIDITY_TOKEN` (e.g. 99 years) directly in the `appToken`
table, with no `ENTERPRISE_KEY`. The daily cron will skip the refresh
(no enterprise key to authenticate with), but the pre-seeded validity
token will be used to grant feature access. No billing or seat reporting
occurs in this mode.
- **`IS_CONFIG_VARIABLES_IN_DB_ENABLED` is false**: if the user tries to
activate an enterprise key but DB config writes are disabled, the
backend returns a clear error asking them to add `ENTERPRISE_KEY` to
their `.env` file manually.
- **Canceled subscriptions**: the `/seats` endpoint skips Stripe updates
for canceled or cancellation-scheduled subscriptions to avoid Stripe API
errors.

### How to test
- launch twenty-website on a different url (eg localhost:1002)
- add ENTERPRISE_API_URL=http://localhost:3002/api/enterprise (or else)
in your server .env
- ask me for twenty-website's .env file content (STRIPE_SECRET_KEY;
STRIPE_ENTERPRISE_MONTHLY_PRICE_ID;STRIPE_ENTERPRISE_YEARLY_PRICE_ID;
ENTERPRISE_JWT_PRIVATE_KEY; ENTERPRISE_JWT_PUBLIC_KEY;
NEXT_PUBLIC_WEBSITE_URL)
- visit Admin panel / enterprise
2026-03-12 15:07:53 +01:00
Weiko c59f420d21 Hide tabs for system objects (#18583)
<img width="1286" height="793" alt="Screenshot 2026-03-12 at 13 57 16"
src="https://github.com/user-attachments/assets/bebfd23f-3172-424a-95ee-ba95358a6196"
/>
2026-03-12 14:46:15 +01:00
Lucas Bordeau cb3e32df86 Fix AI demo workspace skill (#18575)
This PR fixes what allows to have a working demo workspace skill.

- Skill updated many times into something that works
- Fixed infinite loop in AI chat by memoizing ai-sdk output
- Finished navigateToView implementation
- Increased MAX_STEPS to 300 so the chat don't quit in the middle of a
long running skill
- Added CreateManyRelationFields
2026-03-12 13:19:01 +01:00
Hamza Faidi db5b4d9c6c fix: replace unsafe JSON.parse casts with parseJson in filter dropdowns (#18513)
## Problem

Four filter dropdown components were calling `JSON.parse(filter.value)
as string[]` to parse stored filter state. This throws a `SyntaxError`
if the value is malformed (truncated URL, stale localStorage, migration
artifact), crashing the entire dropdown with no recovery.

## Solution

Replace with the existing `parseJson<string[]>` utility from
`twenty-shared`, which wraps `JSON.parse` in a try/catch and returns
`null` on failure. The `?? []` fallback gracefully degrades to an empty
selection instead of crashing.

All four files had an explicit `// TODO: replace by a safe parse`
marking this as a known issue.

## Testing


No new tests — `parseJson` is already tested in `twenty-shared`. No new
logic introduced.

## issue link 
#18514
2026-03-12 13:15:22 +01:00
Charles Bochet 660536d6bb Fix onboarding flow: workspace creation modal and invite team skip (#18577)
## Summary

- **Fix create-profile modal not showing after workspace creation**:
After activating a workspace, `CreateWorkspace.onSubmit` called
`refreshObjectMetadataItems()` which only updated the
`objectMetadataItemsState` atom but never marked the metadata store as
ready (`metadataStoreState` stayed at `'empty'`). Since `MetadataGater`
excludes `CreateWorkspace` but not `CreateProfile` from its loading
check, navigating to `/create/profile` triggered the skeleton loader
instead of the modal. The fix adds the full metadata pipeline after
refresh — `updateDraft('objectMetadataItems')` + `applyChanges()` for
objects, and `fetchAndLoadIndexViews()` for views — so
`isAppMetadataReady` is `true` before navigation.

- **Fix invite-team "Skip" not persisting to server**: Clicking "Skip"
on the invite-team page called `setNextOnboardingStatus()` which only
updated the local Jotai atom. The early return for empty emails bypassed
`sendInvitation`, so the server never cleared the
`ONBOARDING_INVITE_TEAM_PENDING` user var. On page refresh,
`GetCurrentUser` returned `INVITE_TEAM` and the user was stuck. The fix
removes the early return so `sendInvitation({ emails: [] })` always runs
— the server handles empty arrays fine and clears the pending flag.
2026-03-12 13:15:05 +01:00
Raphaël Bosi e8f8189167 [COMMAND MENU ITEMS] Add engine component key (#18554)
## PR Description

In the process of migrating all the existing commands to the backend, we
stumbled across a couple of problems that made us reconsider the full
migration. This PR introduces a way for command menu items to bypass
front components and to directly reference a frontend component from
twenty front.

It:
- Introduces a `engineFrontComponentKey` field on `CommandMenuItem` as
an alternative to `frontComponentId` and `workflowVersionId`, allowing
command menu items to reference frontend components by key directly
rather than requiring a FrontComponent entity
- Updates the DB constraint to allow exactly one of `workflowVersionId`,
`frontComponentId`, or `engineFrontComponentKey`

### All standard command menu items from the frontend which use
`standardFrontComponentKey`

These are all commands that execute a GraphQL query or a mutation.
Two mains concerned have been raised that made us go with this
(temporary) architecture instead:
- If those commands are part of the standard application, they can only
alter objects from that application and not custom objects.
- We would need to implement a way to trigger optimistic rendering from
the front components, which might take some time to implement.

List:
- Create new record
- Delete (single record)
- Delete records (multiple)
- Restore record
- Restore records (multiple)
- Permanently destroy record
- Permanently destroy records (multiple)
- Add to favorites
- Remove from favorites
- Merge records
- Duplicate Dashboard
- Save Dashboard
- Save Page Layout
- Activate Workflow
- Deactivate Workflow
- Discard Draft (workflow)
- Test Workflow
- Tidy up workflow
- Duplicate Workflow
- Stop (workflow run)
- Use as draft (workflow version)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-12 13:14:45 +01:00
github-actions[bot] 38664249cf i18n - translations (#18576)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-12 11:24:07 +01:00
Baptiste Devessier 69542898a1 Display a single Add a Section button (#18563)
- Display a single Add a Section button at the end of the list
- Move other buttons to the section's dropdown menu


https://github.com/user-attachments/assets/b51d8846-635a-477a-9205-bf3266cfcff4
2026-03-12 10:01:48 +00:00
Hamza Faidi 2eac82c207 fix(front): stabilize downloadFile unit test and return promise chain (#18484)
# Description

## What this PR fixes
This PR fixes a flaky/skipped unit test for
[downloadFile](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
and aligns the test with the actual implementation.

## Changes made
Updated
[downloadFile](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
test to validate file-saver behavior instead of DOM anchor creation.
Mocked
[saveAs](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
from file-saver and asserted it is called with the fetched blob and
filename.
Added proper async assertions for:
successful file download
failed fetch path ([status !==
200](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html))
rejecting with Failed downloading file
Updated
[downloadFile](vscode-file://vscode-app/Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/code/electron-browser/workbench/workbench.html)
implementation to return the fetch promise chain so callers/tests can
await it reliably.

## Related Issue
Closes #18485
2026-03-12 09:00:50 +01:00
Abdul Rahman 102b49f919 Fix new navbar item position after reordering existing items (#18516)
Closes [#2296](https://github.com/twentyhq/core-team-issues/issues/2296)
2026-03-11 20:35:15 +00:00
Thomas Trompette 2af3121c51 Fix dashboard creation + role permission page design (#18565)
1. **Creating a new dashboard crashes with "Tab not found"** and widgets
can't be added after the crash is prevented.

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

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


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

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

After
<img width="573" height="266" alt="Capture d’écran 2026-03-11 à 14 25
55"
src="https://github.com/user-attachments/assets/c34f9993-51e1-4108-a7e6-f434f558edfd"
/>
2026-03-11 17:57:54 +00:00
Thomas Trompette a024a04e01 Fix breadcrumb infinite loop (#18561)
`RecordTableNoRecordGroupScrollToPreviousRecordEffect` uses
`useAtomState(lastShowPageRecordIdState)` to read the atom value and
check whether to trigger an effect. Inside `run()`, it calls
`setLastShowPageRecordId(null)` to reset the atom, then`
triggerInitialRecordTableDataLoad()` which fires many `store.set()`
calls on other atoms.

These high-frequency store updates cause the component to re-render
before Jotai's internal useReducer dispatch (propagating the null value)
is processed by React. The result: useAtomState returns a stale non-null
value on every subsequent render, even though the Jotai store already
holds null. The effect re-runs, sees the stale non-null value, calls
`run()` again, creating an infinite loop.

This is a Jotai v2 edge case where useAtom's rendered value desyncs from
the actual store value under high-frequency concurrent updates.

### The fix

Read lastShowPageRecordId directly from the Jotai store via
`store.get()` inside the effect instead of relying on the rendered value
from useAtomState. This guarantees the effect always sees the true store
value and correctly skips when the atom is null.
2026-03-11 18:26:02 +01:00
github-actions[bot] 21de221420 i18n - translations (#18557)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-11 15:57:19 +01:00
Thomas Trompette b346f4fb59 Add common loader (#18556)
To avoid white screens on reload, building a shared skeleton.

Before

https://github.com/user-attachments/assets/42bd0667-141d-4df4-9072-4077192cc71d

After

https://github.com/user-attachments/assets/e6031a72-2e25-47e3-a873-b89aaddfbd3a
2026-03-11 14:56:49 +01:00
nitin 2c5af2654d Separate code pathways for IS_COMMAND_MENU_ITEM_ENABLED flag (#18542) 2026-03-11 13:30:22 +00:00
github-actions[bot] 744ef3aa9d i18n - translations (#18555)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-11 14:21:20 +01:00
Weiko 00c3cd1051 Add system view fallback (#18536)
## Context
The goal is to add a "See records" button in all objects that would
redirect to that view (this will be done in a later PR). See screenshot
below.
<img width="665" height="312" alt="Screenshot 2026-03-10 at 15 54 36"
src="https://github.com/user-attachments/assets/6e23a75b-cff0-4d93-bce8-b5481b05c6f6"
/>

## Implementation
- If a view does not exist on an object, there is a **temporary**
fallback where the frontend creates the missing view as a custom view
when going over the object index page
- System objects are now surfaced but we don't want their records to be
editable, they will be readonly (mostly, all fields will be non-editable
except for their custom fields).
- We can't create a new record of a system object, some actions are also
hidden.
- The backend now rejects if you are trying to delete the last view of
an object
2026-03-11 13:48:02 +01:00
github-actions[bot] 99f885306e i18n - translations (#18553)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-11 13:44:13 +01:00
Abdul Rahman 413d1124bb Fix navigation drag drop indicator position (#18515)
Closes [#2295](https://github.com/twentyhq/core-team-issues/issues/2295)

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2026-03-11 13:35:09 +01:00
Baptiste Devessier ab5fb1f658 Replace newFieldDefaultConfiguration with newFieldDefaultVisibility (#18539)
https://github.com/user-attachments/assets/365092cb-0fe1-44f7-9ae6-c6fc5edb98b2

---------

Co-authored-by: Weiko <corentin@twenty.com>
2026-03-11 12:14:30 +00:00
Abdul Rahman e4e7137660 Navigate to page when clicking nav item in edit mode (#18526)
Closes [#2298](https://github.com/twentyhq/core-team-issues/issues/2298)
2026-03-11 10:59:22 +00:00
Félix Malfait 7fb8cc1c39 Improve apps settings UI and remove unused tarball upload code (#18549)
## Summary
- Improves the Developer Tab in Settings > Applications: adds
source-type badges (Dev / Npm / Internal), better empty state with `yarn
twenty app:dev` CLI command, renames sections to "Create & Develop" and
"Your Apps"
- Simplifies the Distribution Tab: only shows marketplace section for
npm-sourced apps, removes the manual `isListed` toggle (now managed
automatically by the catalog sync cron)
- Removes dead frontend code: `installApplication` mutation (unused —
installs go through `installMarketplaceApp`), `uploadAppTarball`
mutation/hook, and `SettingsUploadTarballModal`

## Test plan
- [ ] Navigate to Settings > Applications > Developer tab: verify badges
show correctly, empty state shows CLI command
- [ ] Create/view a LOCAL app registration: verify Distribution tab does
NOT show marketplace section
- [ ] Create/view an NPM app registration: verify Distribution tab shows
marketplace section with Featured toggle
- [ ] Verify no references to upload tarball or install application
remain in the UI


Made with [Cursor](https://cursor.com)
2026-03-11 11:40:00 +01:00
Thomas Trompette 1d95670252 Fix form field select + form field number (#18538)
Before
<img width="398" height="138" alt="Capture d’écran 2026-03-10 à 16 23
19"
src="https://github.com/user-attachments/assets/c28c0a7f-6911-4c77-a45c-42a79073a92a"
/>

After
<img width="398" height="138" alt="Capture d’écran 2026-03-10 à 16 32
56"
src="https://github.com/user-attachments/assets/b93d2fe9-5928-4803-8d5e-30a0a9eeb28f"
/>

Addition:
- hover on forget password
- settings field width
2026-03-11 08:58:51 +00:00
Thomas des Francs 0fe7e9d5fe small ai chat fix (#18547)
Summary
- capture the updated page structure in a new Playwright YAML artifact
to document the small-ai-chat-fix workstream
- store the generated snapshot under
`.playwright-cli/page-2026-03-09T13-12-30-691Z.yml` for reference

Testing
- Not run (not requested)
2026-03-10 19:27:34 +00:00
Raphaël Bosi 2de022afcf Add standard command menu items (#18527)
## Add standard command menu items

### Summary

This PR introduces standard command menu items, migrating hardcoded
command menu actions to the backend command menu item architecture
powered by front components. It adds a new `twenty-standard-application`
package that defines, builds, and registers front components as standard
command menu items, gated behind the `IS_COMMAND_MENU_ITEM_ENABLED`
feature flag.

### Description

- **New `twenty-standard-application` package**: Contains front
component definitions with an esbuild-based build pipeline that
generates minified `.mjs` bundles and a manifest with checksums.
- **Server-side registration**: New constants register all items with
metadata (labels, icons, positions, availability types, conditional
expressions). A `StandardFrontComponentUploadService` uploads built
components to file storage.
- **`FALLBACK` availability type**: New enum value for command menu
items that appear as fallback options (e.g., "Search Records" fallback).
- **`CommandMenuContextApi` refactor**
- **Conditional availability enhancements**: New array-based helper
functions for evaluating multi-record conditions.
- **Frontend wiring** (twenty-front):
`useCommandMenuItemFrontComponentCommands`

## Next steps

Only simple commands have been implemented for now:
- **Navigation (9)** -- `CommandLink`: go-to-companies,
go-to-dashboards, go-to-notes, go-to-opportunities, go-to-people,
go-to-runs, go-to-settings, go-to-tasks, go-to-workflows
- **Side panel (4)** -- `CommandOpenSidePanelPage`: ask-ai,
search-records, search-records-fallback, view-previous-ai-chats

We still have to implement front components for all the following
commands:
All have placeholder `execute` logic (`async () => {}`) with a `// TODO:
implement execute logic` comment:

**Record (22)**
- `add-to-favorites`, `remove-from-favorites`
- `create-new-record`, `create-new-view`
- `delete-single-record`, `delete-multiple-records`
- `destroy-single-record`, `destroy-multiple-records`
- `restore-single-record`, `restore-multiple-records`
- `export-from-record-index`, `export-from-record-show`,
`export-multiple-records`, `export-note-to-pdf`, `export-view`
- `hide-deleted-records`, `see-deleted-records`
- `import-records`, `merge-multiple-records`, `update-multiple-records`
- `navigate-to-next-record`, `navigate-to-previous-record`

**Page layout (3)** -- `cancel-record-page-layout`,
`edit-record-page-layout`, `save-record-page-layout`

**Dashboard (4)** -- `cancel-dashboard-layout`, `duplicate-dashboard`,
`edit-dashboard-layout`, `save-dashboard-layout`

**Workflow (10)** -- `activate-workflow`, `add-node-workflow`,
`deactivate-workflow`, `discard-draft-workflow`, `duplicate-workflow`,
`see-active-version-workflow`, `see-runs-workflow`,
`see-versions-workflow`, `test-workflow`, `tidy-up-workflow`

**Workflow version (4)** -- `see-runs-workflow-version`,
`see-versions-workflow-version`, `see-workflow-workflow-version`,
`use-as-draft-workflow-version`

**Workflow run (3)** -- `see-version-workflow-run`,
`see-workflow-workflow-run`, `stop-workflow-run`
2026-03-10 17:36:41 +00:00
kpdev 25d9f2fcce fix: respect number format in currency input (#18469)
Fixed #18355 

Currency fields ignored the workspace number format when editing:
display showed e.g. 5 982,77 € (French style) but the input forced US
style (5,982.77) and rejected comma as decimal.
Fix: CurrencyInput now uses useNumberFormat() and passes the correct
thousandsSeparator and radix to the IMask input so edit mode matches the
chosen format (comma/space, dot/comma, etc.).
Files: CurrencyInput.tsx (use format for mask), new
CurrencyInput.test.tsx .

---------

Co-authored-by: root <root@dragon.second>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2026-03-10 16:59:31 +00:00
Thomas Trompette 6e628bb751 Fix add more tab bottom separator (#18529)
Adding a full height prop

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

After
<img width="409" height="139" alt="Capture d’écran 2026-03-10 à 14 06
33"
src="https://github.com/user-attachments/assets/1d3551fe-0b4b-4bbf-88e4-fd466c9bb704"
/>
2026-03-10 18:08:51 +01:00
Arun 40a8d18d38 feat : Added "Quarter" as a time unity to filter on date (#18289)
fixes #16674 

Simply added the Quarter functionality to the existing filter code with
months amount multiplied by 3.

<img width="1258" height="760" alt="Screenshot 2026-02-27 at 11 59
26 AM"
src="https://github.com/user-attachments/assets/30648259-2b72-480a-b8fa-55ed88d9ebf3"
/>

---------

Co-authored-by: Arun kumar <arunkumar@Aruns-MacBook-Air.local>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2026-03-10 16:42:10 +00:00
neo773 7b9939b43e fix: validate input before formatting in MultiItemFieldInput (#18334)
Reorder validateInput to run before formatInput to prevent
parsePhoneNumber from throwing INVALID_COUNTRY on bad input.

Fixes TWENTY-FRONT-5RQ
/closes https://github.com/twentyhq/twenty/issues/17670

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-10 15:39:21 +00:00
github-actions[bot] ec1f08bc3b i18n - translations (#18537)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-10 16:35:05 +01:00
neo773 dd58eb6814 Fix linaria css regressions (#18492)
before
<img width="310" height="60" alt="SCR-20260309-ctul"
src="https://github.com/user-attachments/assets/7141d495-b8f2-4fd6-bf3b-36bb2b11d1aa"
/>

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

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

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


before



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


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

before

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


after (fixed missing border on :active state)

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

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-03-10 16:26:53 +01:00
Baptiste Devessier 926dd545f4 Create fake hidden fields group (#18525)
## Demo


https://github.com/user-attachments/assets/43f31c43-fe37-4553-ad42-fc97a948d6ea

## Ungrouped fields

<img width="3456" height="2160" alt="CleanShot 2026-03-10 at 13 52
57@2x"
src="https://github.com/user-attachments/assets/13d1db63-59ac-4e2b-8950-fccf430176c4"
/>
2026-03-10 16:26:35 +01:00
Thomas Trompette 8e003aa6cf Fix permission settings page (#18535)
<img width="589" height="651" alt="Capture d’écran 2026-03-10 à 15 59
37"
src="https://github.com/user-attachments/assets/6c4cf5e6-a5cc-4306-a0ae-322addad340f"
/>
2026-03-10 16:26:21 +01:00
github-actions[bot] 6399e11220 i18n - translations (#18532)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-03-10 15:13:56 +01:00