# Introduction
In this pull-request we introduce a service dedicated to the
twenty-standard app installation, we will later be able to re-use
existing logic to be more generic and allow any app installation.
For the moment sticking to this usage
https://github.com/twentyhq/core-team-issues/issues/1995
## Encountered issues
- We decided not to migrate deprecated fields ( also they will become
custom field for any existing workspace having them in the future )
- duplicate criteria
- wrong search index declaration
- forgotten isSearchable
- Attachement seed
- Restored standardId
## Note
For the moment we're still searching through standardId for code that
run on both existing and new workspaces.
For code running on new workspace exclusively we're searching using
universalIdentifier
We will standardize universalIdentifier usage later when we've migratred
all the existing workspaces
## Workspace creation
Will handle workspace creation the same way in another PR
Related https://github.com/twentyhq/twenty/pull/15065
## TODO
- [ ] Double all frontend hardcoded queries to not refer to deprecated
fields especially attachments
Fixes#16636
Added useCloseDropdown() hook and set onEnter prop to
onEnter={closeDropDown()} using dropdownID
EDIT from @charlesBochet after refactoring:
- ObjectDropdownFilters are used in 3 places: Main Filter menu,
EditableChip, AdvancedFilters
- deprecate vectorSearch in view filter area, we are not using them, we
are doing a anyField filter now. While refactoring the points below, I
did not want to maintain vectorSearch as it was not used anymore
- stop confusing the dropdownId (which is an id to interact with a
specific dropdown) and componentInstanceIds (which is used to scope
component states) for EditableFilter case
- I haven't fixed the confusion for MainFilter case
- It was already handled for AdvancedFilter case
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
# Introduction
Creating dedicated folders and module for both `page-layout-tab` and
`page-layout-widget`
The addition diff with deletion is due to the module being added
## Summary
Fixes text overflow issues in the UI that were particularly visible with
longer translations (e.g., French).
## Changes
### RecordTableActionRow
- Added `white-space: nowrap` to prevent the 'Add New' text from
wrapping to multiple lines
- Removed the fixed `width: 100px` that was causing overflow issues
### ViewPickerDropdown
- Fixed flexbox layout to properly handle long view names
- Added `flex-shrink: 0` to the icon container and adornments to prevent
them from shrinking
- Added `min-width: 0` to the view name container for proper text
truncation
- Removed `display: inline-block` and `vertical-align: middle` which
don't work in flex containers
## Before
- 'Ajouter Nouveau' was displayed on two lines
- View names could push the count to a new line
- Icons could shrink when view names were long
## After
- Text stays on one line with proper ellipsis truncation
- Layout remains stable regardless of text length
- Icons maintain their size
## Summary
Move the Support and Documentation links from the bottom left navigation
drawer to the workspace switcher dropdown menu.
## Changes
- **Workspace Switcher**: Added Support (conditional) and Documentation
links before Log out
- **Settings Navigation**: Added Support and Documentation links in the
Other section
- **Support visibility**: Support link only appears when FrontChat is
configured (not waiting for script to load)
- **FrontChat loading**: Created `SupportChatEffect` component to ensure
FrontChat script loads at app startup for popup notifications
- **Bug fix**: Fixed settings navigation items without a path appearing
highlighted
- **Cleanup**: Removed unused `SupportDropdown`, `SupportButton`, and
`SupportButtonSkeletonLoader` components
- **Hidden**: Temporarily commented out Integrations page
## Screenshots
The Support and Documentation links now appear in:
1. Workspace switcher dropdown (top left)
2. Settings navigation (Other section)
## Summary
Adds Notion-style resizable panels for the navigation drawer (left
sidebar) and command menu (right panel).
## Behavior
- **Hover** at panel edge → resize cursor appears
- **Click** → collapse/close the panel
- **Drag** → resize the panel (5px movement threshold to distinguish
from click)
## Constraints
| Panel | Min | Max | Default | Collapse Threshold |
|-------|-----|-----|---------|-------------------|
| Navigation Drawer | 180px | 350px | 220px | 150px |
| Command Menu | 320px | 600px | 400px | 250px |
## Performance Optimizations
- **CSS variables** for smooth 60fps resize (no React re-renders during
drag)
- **Table resize observer disabled** during panel resize to prevent
expensive recalculations
- **React.memo wrapper** on page body to prevent unnecessary re-renders
## Architecture
- `useResizablePanel` hook following the same pattern as
`useResizeTableHeader`
- `ResizablePanelEdge` - resize handle positioned at panel edge
- `ResizablePanelGap` - resize handle in the gap between panels
- `cssVariableEffect` - Recoil effect to sync CSS variables with state
## Refactoring
- Split `recoil-effects.ts` into separate files in `utils/recoil/` (one
export per file)
- Persist panel widths to localStorage via existing `localStorageEffect`
## Summary
Fixes a bug where `BillingUsageService.billUsage()` only sent the first
event from the `billingEvents` array to Stripe, silently ignoring all
subsequent events.
## Bug Description
The `billUsage()` method accepts an array of `BillingUsageEvent[]` but
was only processing `billingEvents[0]`, causing:
- Customers to be undercharged for their usage
- Revenue loss due to unbilled events
- Incorrect usage tracking
## Fix
Changed the implementation to use `Promise.all()` to send all events in
the array concurrently to Stripe.
## Before
```typescript
await this.stripeBillingMeterEventService.sendBillingMeterEvent({
eventName: billingEvents[0].eventName, // Only first event
value: billingEvents[0].value,
stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
dimensions: billingEvents[0].dimensions,
});
```
## After
```typescript
await Promise.all(
billingEvents.map((event) =>
this.stripeBillingMeterEventService.sendBillingMeterEvent({
eventName: event.eventName,
value: event.value,
stripeCustomerId: workspaceStripeCustomer.stripeCustomerId,
dimensions: event.dimensions,
}),
),
);
```
This PR updates the `isNameAvailable` function in
`getRemoteTableLocalName` to use parameterized queries instead of string
interpolation when querying the information_schema.
**Changes:**
- Replaced template literal interpolation with PostgreSQL's `$1`, `$2`
placeholder syntax
- Parameters are now passed as a separate array argument to
`dataSource.query()`
This follows best practices for database queries.
## Summary
Fixes a database connection leak in `WorkspaceDataSourceService` where
`QueryRunner.release()` was not being called when schema operations
failed.
## Problem
The `createWorkspaceDBSchema` and `deleteWorkspaceDBSchema` methods use
TypeORM's QueryRunner but didn't wrap the operations in
try-catch-finally blocks. When schema operations fail (e.g., permission
denied, schema conflicts), the `QueryRunner.release()` method was never
called.
**Impact:** Failed schema operations leak database connections, which
can exhaust the connection pool and cause the application to hang or
crash under load.
## Solution
Wrap both methods in try-finally blocks to ensure
`queryRunner.release()` is always called, regardless of whether the
operation succeeds or fails.
## Changes
- `createWorkspaceDBSchema`: Wrapped in try-finally to ensure connection
release
- `deleteWorkspaceDBSchema`: Wrapped in try-finally to ensure connection
release
## Summary
Instead of throwing an error at server startup when LOCAL code
interpreter is configured in production, we now return a DisabledDriver
that only throws when the code interpreter is actually used.
## Changes
- Created `DisabledDriver` class that implements `CodeInterpreterDriver`
but throws an error only when `execute()` is called
- Added `DISABLED` to the `CodeInterpreterDriverType` enum
- Updated the factory to return a `DISABLED` driver config instead of
throwing when LOCAL is used in production
- Updated the module to handle the new `DISABLED` driver type
## Motivation
Many users don't need the code interpreter feature and want to deploy to
production without configuring E2B. Previously, the server would crash
at startup if `CODE_INTERPRETER_TYPE=LOCAL` was set in production.
**Before:** Server crashes at startup in production if
`CODE_INTERPRETER_TYPE=LOCAL`
**After:** Server starts fine. The error only occurs if someone actually
tries to **use** the code interpreter feature, at which point they get a
clear error message explaining how to configure E2B.
## Summary
This PR adds the `lingui/no-unlocalized-strings` ESLint rule to detect
untranslated strings and fixes translation issues across multiple
components.
## Changes
### ESLint Configuration (`eslint.config.react.mjs`)
- Added comprehensive `ignore` patterns for non-translatable strings
(CSS values, HTML attributes, technical identifiers)
- Added `ignoreNames` for props that don't need translation (className,
data-*, aria-*, etc.)
- Added `ignoreFunctions` for console methods, URL APIs, and other
non-user-facing functions
- Disabled rule for debug files, storybook, and test files
### Components Fixed (~19 files)
- Object record components (field inputs, pickers, merge dialogs)
- Settings components (accounts, admin panel)
- Serverless function components
- Record table and title cell components
## Status
🚧 **Work in Progress** - ~124 files remaining to fix
This PR is being submitted as draft to allow progressive fixing of
remaining translation issues.
## Testing
- Run `npx eslint "src/**/*.tsx"` in `packages/twenty-front` to check
remaining issues
Resolves [Code Scanning Alert
180](https://github.com/twentyhq/twenty/security/code-scanning/180).
- Normalize unexpected GraphQL errors in convertExceptionToGraphql to a
generic "Internal Server Error" instead of exposing exception.name
directly to clients.
- Only attach stack and response (original error message) in
development, so production responses don’t leak internal class names,
implementation details, or stack traces, while observability is
preserved via `ExceptionHandlerService`/Sentry.
- Keep behavior consistent with `convertHttpExceptionToGraphql`, which
also only exposes detailed response and stack information when `NODE_ENV
=== DEVELOPMENT`.
We checked for widget types by doing `configuration?.__typename ===
'LineChartConfiguration'` which made the code difficult to read.
In this PR, I introduce type guards for each widget type.
Note: the configuration type is `WidgetConfiguration |
FieldsConfiguration` for now but should be changed to
`WidgetConfiguration` when @Devessier adds FieldsConfiguration to the
backend type `WidgetConfiguration`.
Title: "feat: Add second, minute & hour resolution options to relative
date Filter action"
---
## Summary
This PR enables support for smaller time units — **Seconds, Minutes, and
Hours** — in the *Relative Date* filter used in workflows, rather than
being limited to days only.
---
## What Changed
This PR extends the relative date filter to include support for the
following units:
✔️ `SECOND`
✔️ `MINUTE`
✔️ `HOUR`
✔️ (Existing: `DAY`, `WEEK`, `MONTH`, etc.)
Changes include:
- Adding `SECOND`, `MINUTE`, and `HOUR` options to the internal relative
date unit enum/constant.
- Updating utility functions and parsers to correctly interpret and
evaluate these new units.
- Enhancing existing tests and adding new tests to cover second, minute,
and hour relative filters.
---
## Testing
New and updated tests include:
- Unit tests for serialization of relative filter values including
seconds, minutes, and hours.
- Workflow filter evaluation tests that verify minute/hour resolution
behaves correctly.
Tests are included in the changeset.
---
## Backward Compatibility
This change is fully backward compatible:
- All existing relative date filters using days or larger units behave
exactly as before.
- Adding finer units does not alter existing stored data or workflow
definitions.
---
## Issue Reference
Fixes: **twentyhq/twenty#15525**
<img width="1909" height="896" alt="image"
src="https://github.com/user-attachments/assets/328d03dc-ca0b-4c3f-84e5-58961c178398"
/>
---------
Co-authored-by: Guillim <guillim@users.noreply.github.com>
Co-authored-by: guillim <guigloo@msn.com>
**What this fixes:**
- Addresses a CodeQL security finding: the regex used to find variables
in workflow strings could be slow on malicious inputs (ReDoS).
- Two alerts: [Code Scanning
181](https://github.com/twentyhq/twenty/security/code-scanning/181) and
[Code Scanning
182](https://github.com/twentyhq/twenty/security/code-scanning/182)
**Context:**
- Our workflow system lets users insert variables like `{{user.name}}`
or `{{trigger.properties.after.name}}` into strings and JSON (HTTP
request bodies, record field values, etc.).
- The `variable-resolver.ts` module scans these strings and replaces
variables with actual values.
- Our validation (`isValidVariable`) already enforces that variables
contain no `{` or `}` inside them (only simple property paths like
`user.name`).
**The change:**
- Updated the regex from `/\{\{(.*?)\}\}/g` to `/\{\{([^{}]+)\}\}/g` to
match our validation pattern.
- This removes the ReDoS risk and aligns the resolver with the
validation contract.
**Why this is safe:**
- All supported workflow usage (simple variable paths) continues to
work.
- Both `match` and `replace` behave the same for valid variables.
- Only unsupported patterns with nested braces (e.g., `{{foo {bar}}}`)
would stop matching, which isn't part of our supported syntax anyway.
# Introduction
@bosiraphael has to introduce async validators and feature flag
contextual validator
In this way in this PR we make all entity validators asyncable
Also added an `additionalCacheDataMaps` to the low level args validators
# Closes Issue: Can't distinguish between fields with identical names
(#16285)
There was a UX bug in the workflow filter interface where **two
variables coming from different steps but sharing the same field name**
were displayed identically. This made it difficult for users to tell
them apart when used in a filter group, leading to confusion when
building workflows.
---
# Fix: Add Full Path Label Tooltip for Workflow Filter Field
- Adds a **tooltip/label showing the complete path** so users can
distinguish fields from different workflow steps even if they share the
same name.
## UX Improvements
<img width="495" height="288" alt="image"
src="https://github.com/user-attachments/assets/fa26f381-835b-4d14-bf73-f04b59c8d0b5"
/>
This is a fix for #15797
This pull request is to replace PR #16307 and to extend #16265
Just to repeat, this PR does the following ->
**Table Cell Button and Edit Button Improvements**
- Enhanced RecordTableCellButton to support a secondary action and icon,
enabling both the primary and secondary actions based on the selected
action mode.
- Updated RecordTableCellEditButton to determine the action mode for
actionable fields, and provide both copy and navigate actions as
primary/secondary buttons, with appropriate feedback.
## When primary function is to copy
<img width="1817" height="939" alt="image"
src="https://github.com/user-attachments/assets/7ec6c6aa-80d8-402b-a210-519163d39ef6"
/>
## When primary function is to open link
<img width="1784" height="942" alt="image"
src="https://github.com/user-attachments/assets/dfe0fcf1-ba72-4083-a5f9-7165a03db3df"
/>
Hey @etiennejouan, please have a look!
Thank you
---------
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
In this PR,
- current basic E2E tests are fixed, and some were added, covering some
basic scenarios
- some tests avec been commented out, until we decide whether they are
worth fixing
The next steps are
- evaluate the flakiness of the tests. Once they've proved not to be
flaky, we should add more tests + re-write the current ones not using
aria-label (cf @lucasbordeau indication).
- We will add them back to the development flow
## Description
3 steps depending on the widget width. From bigger to tighter space:
- Fully shown horizontal text
- Rotated text
- Rotated text with skipped ticks to avoid overlapping
Also created common files for all constants for bar and pie charts.
Since a lot of them are shared, they can be inherited from a common
file.
## Video QA
https://github.com/user-attachments/assets/fd58d412-1a8b-4bd6-a420-4c03767e98d5