Closes#16792
## Problem
When editing a currency field’s default value (for example, changing
from **USD** to **UYU**), the **Save** button remained disabled.
However, if the format setting was changed first (**short → full →
short**), the Save button would then work correctly for currency
changes.
## Root Cause
The form was using **React Hook Form’s `values` mode**, which did not
properly track dirty state for the `defaultValue` and `settings` fields.
## Solution
Switched to the **`defaultValues` + `reset()`** pattern:
- Initialize the form with `defaultValues` (using placeholder values)
- Call `reset()` when `fieldMetadataItem` loads
This correctly tracks dirty state by comparing against the most recent
`reset` values.
## Note
A similar pattern is used in:
- `useWebhookForm`
- `useImapSmtpCaldavConnectionForm`
Those hooks call `reset()` via query callbacks. In this case, `reset()`
is called inside a `useEffect` because the data comes from synchronous
Recoil state rather than an async query.
Found two solutions to the problem, created commits for both. I feel the
useEffect pattern makes more sense here since it's cleaner in terms of
code.
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Disable Deactivate option for all standard fields
#16706
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Prevents deactivation UI for standard system fields on the field edit
page.
>
> - Introduces `canFieldBeDeactivated` to flag standard fields
(`createdAt`, `createdBy`, `deletedAt`, `updatedAt`)
> - Hides the "Danger zone" (deactivate/activate/delete controls) when
`!isLabelIdentifier && !readonly && !canFieldBeDeactivated`
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b309815700555c8e0f28324936e4ddd313a24fb6. 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.malfait@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
# Introduction
This has been fixed on main already 1 hour ago, this PR now only passes
the field application id instead of the object applicationId that could
be different for example when creating a custom field on a standard
object
For the moment not introducing any logic around application integrity
directly and still relying on the isCustom and standardId definition
This will have to be refactored once we deprecate the standardId
## Summary
This PR enforces the use of `@/` alias for imports instead of relative
parent imports (`../`).
## Changes
### ESLint Configuration
- Added `no-restricted-imports` pattern in `eslint.config.react.mjs` to
block `../*` imports with the message "Relative parent imports are not
allowed. Use @/ alias instead."
- Removed the non-working `import/no-relative-parent-imports` rule
(doesn't work properly in ESLint flat config)
### VS Code Settings
- Added `javascript.preferences.importModuleSpecifier: non-relative` to
`.vscode/settings.json` (TypeScript setting was already there)
### Code Fixes
- Fixed **941 relative parent imports** across **706 files** in
`packages/twenty-front`
- All `../` imports converted to use `@/` alias
## Why
- Consistent import style across the codebase
- Easier to move files without breaking imports
- Better IDE support for auto-imports
- Clearer understanding of where imports come from
## 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
Fixes Issue: #15797
This PR adds a configurable click behavior setting for Phone, Email, and
Links field types, allowing users to customize what happens when
clicking on these fields.
A new option (**Click Behaviour**) to configure the default behaviour
for onClick of data is added in the settings page (Settings → Data Model
→ Object → Field Edit) for Phone, Email and Links data types.
Users can now choose between two actions:
- **Copy to clipboard**: Copies the value to clipboard with a success
toast message
- **Open as link**: Opens the value as a link (tel:, mailto:, or
http/https)
The default behaviour is persisted for all these three types(phone- Copy
to clipboard, email & links: open link) to maintain backward
compatibility.
**Screenshots :**
<img width="2084" height="1736" alt="image"
src="https://github.com/user-attachments/assets/eb5d129c-e3e0-4334-b426-eb38d8a4840c"
/>
<img width="1474" height="1428" alt="image"
src="https://github.com/user-attachments/assets/487f4e44-6151-4254-bc5c-5398be5fc087"
/>
<img width="1594" height="1398" alt="image"
src="https://github.com/user-attachments/assets/abdbc213-7223-4d57-809e-4d55c90cda80"
/>
---------
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Closes [1918](https://github.com/twentyhq/core-team-issues/issues/1918).
- For the first point in the issue, we just show the deactivated entries
along with the deactivated text.
---
- For the second point, we show a banner and control the
enabled/disabled state of save button depending on whether we're
allowing the user to create table with the typed name.
- For example, we do not want to allow the user to create a table with
reserved name, so we disable the save button without showing a banner.
- Similarly, we do not want the user to create a table with a name that
already exists in the database. In this case, we show a banner and we
also disable the save button.
- Finally, we do not want to allow the user to create a table where
singular and plural name are the same. Therefore, we disable the save
button for names like `works`.
---
- For the third point, if we add the delete button, it logically means
that we allow the user to delete a custom object/field even it has not
been deactivated yet, so did that.
- Upon deleting the object/field, if we wait for the metadata to refetch
before we navigate, this is what we see because the path does not exist
any longer after deletion and we're waiting for refetch on the path
until we navigate away.
https://github.com/user-attachments/assets/dbe0569c-db88-4285-851f-22551b1ca81e
- To avoid this page from appearing, I replaced awaiting refetch to not
awaiting refetch and redirecting while the refetch happens in the
background.
- Therefore, when we delete something, there is a slight delay for when
it is actually cleared out from the list, but the Not Found view does
not appear on the screen.
https://github.com/user-attachments/assets/47f49579-ce51-4d6a-b857-72046247bb4b
- I tried optimistically removing the object/field from the metadata,
but it leads to some issues (crashes the app) and I have not been able
to find a solution for it yet.
- Therefore, instead of getting stuck at perfection and blocking myself,
I stopped getting into the issue further and created this PR by ensuring
that the desired functionality works.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Display deactivated objects/fields by default, add delete actions with
confirmation, and unify metadata name computation (auto-suffix reserved
keywords) across front/back with conflict checks in object creation.
>
> - **Frontend (Settings/Data Model)**:
> - **Visibility/UX**: Show `Deactivated` labels for objects/fields;
filters default to include inactive (`showDeactivated`/`showInactive`
true); replace field action dropdown with chevron link.
> - **Delete flows**: Add delete buttons for custom objects/fields with
confirmation modals and background refetch to avoid Not Found flashes.
> - **Creation/Edit validation**: Add name conflict detection banner in
`SettingsDataModelObjectAboutForm` and disable Save on conflicts;
simplify `metadataLabelSchema` to use computed name; form fields
validate on change and sync API names.
> - **Shared (twenty-shared/metadata)**:
> - Add `computeMetadataNameFromLabel` util (slugify+camelCase) and
`RESERVED_METADATA_NAME_KEYWORDS`; auto-append `Custom` to reserved
names; export constants/utilities.
> - **Backend**:
> - Migrate to shared `computeMetadataNameFromLabel`; update validators
to use shared reserved keywords with new messages; allow deletion of
active custom fields/objects (keep standard guards); adjust
services/decorators accordingly.
> - **Tests/Stories**:
> - Update unit/integration snapshots for new reserved-name messages and
behaviors; add missing i18n/router decorators in stories.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5b126155606f6dbc8f7f91e2192cffb7bd2ebd2c. 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.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
# Introduction
Two things:
- Enforcing non nullable workspace custom application Id for any
workspace
- Fixing front non editable data models following
https://github.com/twentyhq/twenty/pull/15911 that associate any custom
entities to an applicationId. The front was putting everything as
readonly when under an app ( we will have to handle the twenty standard
application in the future too )
## Fallback
### Migration
The non nullable migration will fail when released, that's why it's
being swallowed and re-run in an upgrade command post workspace custom
application creation for those that miss one. Allowing the migration to
pass in the end
The typeorm migration still need to exists for any new workspaces
### GetCurrentUser
In order to dynamically display isReadOnly in data model settings we're
fetching the workspaceCustomApplicationId through the `getCurrentUser`
If not fallback this endpoint would throw until we're handling existing
workspaces that do not have a custom workspace application
The fallback should be removed post release
## 🐛 Issues Fixed
### 1. Role Editing Not Working for New Agents
When creating a new agent and then creating a role for it, the role
permissions appeared as non-editable. This was caused by:
- In create mode, `agentId = ''` (empty string from `useParams`)
- Empty string is **falsy** but `isDefined('')` returns **true**
- This caused incorrect behavior in role exclusivity checks and API
calls
### 2. Missing Role Data Loading
The agent form wasn't loading role data needed for permission editing
because it was missing the `SettingsRolesQueryEffect` component.
### 3. Navigation Conflicts
The `useSaveDraftRoleToDB` hook contained navigation logic that caused
conflicts when used from different contexts (role detail page vs agent
form).
### 4. Linting Errors
Unused `useIcons` import in `SettingsAgentRoleTab.tsx`.
---
## 🔧 Changes Made
### Agent Role Tab (`SettingsAgentRoleTab.tsx`)
- ✅ Use `isNonEmptyString(agentId)` to validate agentId (follows
codebase patterns)
- ✅ Improved role exclusivity logic to handle both create and edit
modes:
- **Edit mode**: Role must be assigned exclusively to this agent
- **Create mode**: Role must not be assigned to anyone yet
- ✅ Only call `assignRoleToAgent` when a valid agentId exists
- ✅ Pass `undefined` instead of empty string for `fromAgentId` prop
### Role Hook (`useSaveDraftRoleToDB.ts`)
- ✅ Removed navigation logic from the hook (better separation of
concerns)
- ✅ Removed `useNavigateSettings` and `SettingsPath` dependencies
- ✅ Hook now only handles data persistence, not navigation
### Role Component (`SettingsRole.tsx`)
- ✅ Added navigation after successful role creation in create mode
- ✅ Navigation now handled by the component using the hook
### Agent Form (`SettingsAgentForm.tsx`)
- ✅ Added `SettingsRolesQueryEffect` to ensure role data is loaded
- ✅ Agent form handles its own navigation after save
---
## ✅ Testing Scenarios
All these scenarios now work correctly:
1. ✅ Create new agent → Create role → Edit permissions → Save agent
2. ✅ Edit existing agent → Create role → Edit permissions → Save
3. ✅ Edit existing agent → Try to edit shared role (shows warning
message)
4. ✅ Navigate to object-level permissions from agent form with proper
breadcrumbs
---
## 📝 Technical Details
### Root Cause Analysis
The main issue was that empty string was being treated differently in
different checks:
- `agentId &&` → evaluates to `false` (empty string is falsy)
- `isDefined(agentId)` → returns `true` (empty string is defined)
This inconsistency caused the role to appear as non-editable and
attempted invalid API calls.
### Solution
Used `isNonEmptyString()` from `@sniptt/guards` which properly checks
both that the value is defined AND not empty, following codebase
conventions.
---
## 🎯 Impact
- Fixes critical bug preventing role permission configuration for new
agents
- Improves code quality with better separation of concerns
- Makes navigation logic more predictable and maintainable
- Follows codebase patterns and guidelines
## Summary
This PR replaces the Active/Inactive accordion sections with a modern
filter dropdown button and enables full access to system objects in
advanced mode.
## Changes
### UI Improvements
- ✅ Replaced accordion sections with a filter button dropdown (matching
the design pattern from the Group filter)
- ✅ Added 'Deactivated' toggle filter (hidden by default, uses
IconArchive)
- ✅ Added 'System objects' toggle filter (only visible in advanced mode,
uses IconSettings)
- ✅ Fixed search input width to properly fill available space
- ✅ Proper button sizing and alignment
### System Objects Support
- ✅ Made system objects visible when 'System objects' filter is toggled
on
- ✅ System objects are now fully clickable and accessible
- ✅ Updated object detail page to support system objects
- ✅ Updated field creation/edit pages to support system objects
- ✅ System objects can now have custom fields added
### Architecture
- ✅ Implemented scalable filter architecture using a single filtered
list
- ✅ Easy to add more filters in the future (e.g., show remote objects)
- ✅ All filters work independently and can be combined
## Testing
- [x] Tested deactivated objects toggle
- [x] Tested system objects toggle (only shows in advanced mode)
- [x] Tested clicking on system objects
- [x] Tested adding custom fields to system objects
- [x] No linter errors
## Screenshots
See attached screenshots in the conversation for the new filter UI.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Adds a filter dropdown to the Settings Objects table (incl.
deactivated/system toggles), enables system objects across
settings/field flows, seeds core views (workspace members, messages,
threads, calendar events), and adds actions for Workspace Members.
>
> - **Settings UI**
> - **Objects Table**: Replaces Active/Inactive sections with a single
filterable list and dropdown (`Deactivated`, `System objects` in
advanced mode); updates props to `objectMetadataItems` and removes
accordion sections.
> - **Search/UX**: Search input fills available space; inactive rows
show activation/delete menu; active rows remain navigable.
> - **Pages Updated**: `SettingsObjects`,
`SettingsApplicationDetailContentTab` switch to new table API; object
detail and new-field flows use `findObjectMetadataItemByNamePlural`
(works with system objects).
> - **Action Menu**
> - **Workspace Members**: Adds `WORKSPACE_MEMBERS_ACTIONS_CONFIG` with
"Manage members in settings" action; wired into `getActionConfig` for
`WorkspaceMember`.
> - **Server (Core Views Seed)**
> - Adds default views: `workspaceMembersAllView`, `messagesAllView`,
`messageThreadsAllView`, `calendarEventsAllView`; included in
`prefillCoreViews`.
> - Marks workflow entities as system (`WorkflowRun`,
`WorkflowVersion`).
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6a2856df85104665bd986cc63f2d54f19bf668d0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
As title
- adds decorators in twenty-sdk
- update twenty-cli load-manifest to it gets @FieldMetadata infos +
testing
- update twenty-server so it CRUD fields properly, using
universalIdentifier
- Fix UI so we can update managed objects records
- move FieldMetadata items from twenty-server to twenty-shared
# Complete color refactoring
Closes https://github.com/twentyhq/core-team-issues/issues/1779
- Updated all colors to use Radix colors with P3 color space allowing
for brighter colors
- Created our own gray scale interpolated on Radix's scale to have the
same values for grays as the old ones in the app
- Introduced dark and light colors as well as there transparent versions
- Added many new colors from radix that can be used in the tags or in
the graphs
- Updated multiple color utilities to match new behaviors
- Changed the computation of Avatar colors to return only colors from
the theme (before it was random hsl)
These changes allow the user to use new colors in tags or charts, the
colors are brighter and with better contrast. We have a full range of
color variations from 1 to 12 where before we only had 4 adaptative
colors.
All these changes will allow us to develop custom themes for the user
soon, where users can choose their accent colors, background colors and
there contrast.
# Introduction
Please first review this PR initial base
https://github.com/twentyhq/twenty/pull/15358
In a nutshell refactored the frontend fetchers to display v2 errors
format smoothly
Please note that the v2 now finished the whole validation and does fail
fast anymore ( summary is hardcoded for the moment )
```json
[
{
"extensions": {
"code": "BAD_USER_INPUT",
"errors": {
"cronTrigger": [],
"databaseEventTrigger": [],
"fieldMetadata": [
{
"errors": [
{
"code": "INVALID_FIELD_INPUT",
"message": "Default value should be as quoted string",
"value": "",
},
{
"code": "INVALID_FIELD_INPUT",
"message": "Default value "" must be one of the option values",
"value": "",
},
],
"flatEntityMinimalInformation": {
"id": Any<String>,
"name": "testField",
"objectMetadataId": Any<String>,
},
"status": "fail",
"type": "create_field",
},
],
"index": [],
"objectMetadata": [],
"routeTrigger": [],
"serverlessFunction": [],
"view": [],
"viewField": [],
"viewFilter": [],
"viewGroup": [],
},
"message": "Validation failed for 0 object(s) and 0 field(s)",
"summary": {
"invalidCronTrigger": 0,
"invalidDatabaseEventTrigger": 0,
"invalidFieldMetadata": 0,
"invalidIndex": 0,
"invalidObjectMetadata": 0,
"invalidRouteTrigger": 0,
"invalidServerlessFunction": 0,
"invalidView": 0,
"invalidViewField": 0,
"invalidViewFilter": 0,
"invalidViewGroup": 0,
"totalErrors": 0,
},
"userFriendlyMessage": "Validation failed for 0 object(s) and 0 field(s)",
},
"message": "Multiple validation errors occurred while creating fields",
"name": "GraphQLError",
},
]
```
## What's done
- `usePersistView` tool ( CRUD )
- renamed `usePersistViewX` tools accordingly ( no more records or core
)
- Now catching a lot of before unhandled exceptions
- refactored each services to handle their own exception handlers and
return either the response or the error within a discriminated union
record
## Result
### Primary entity error
When performing an metadata operation on a given metadata, if validation
errors occurs we will display each of them in a toast
Here while creating an object metadata.
<img width="700" height="327" alt="image"
src="https://github.com/user-attachments/assets/0c33d13c-c66c-4749-af36-b253abd3449b"
/>
### Related entity error
Still while creating an object
<img width="700" height="327" alt="image"
src="https://github.com/user-attachments/assets/52607788-c4e9-470c-ac8c-23437345ee5c"
/>
### Translated
<img width="700" height="327" alt="image"
src="https://github.com/user-attachments/assets/a7198c20-ae82-47a6-910c-761de9594672"
/>
## Conclusion
This PR is an extract of https://github.com/twentyhq/twenty/pull/15331
close https://github.com/twentyhq/core-team-issues/issues/1776
## Notes
- Not refactor around triggers services as they're not consumed directly
by any frontend services
Fixes [Dependabot Alert
85](https://github.com/twentyhq/twenty/security/dependabot/85) -
prototype pollution in lodash.
Added a shared pick helper (with unit tests) in twenty-shared and
refactored front-end/server code to import { pick } from the shared
barrel instead of lodash.pick.
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: martmull <martmull@hotmail.fr>
🎯 Merge Settings Relation and Morph Relation Forms
In the settings, we unify morph and relation into a single form.
The form now automatically creates
- a `RELATION` field when 1 destination object is selected
- or a `MORPH_RELATION` field when 2+ objects are selected.
Better UI labels (showing object name for single selection, "X Objects"
for multiple), proper field editing controls on destination objects, and
capitalized field labels.
We still make sure the isMorphRelationEnabled feature flag prevents
current users from accessing this feature
Fixes https://github.com/twentyhq/core-team-issues/issues/1589
fix:Ability to add a new option for a multi-select on the fly
Issues:#13877
---------
Co-authored-by: ehconitin <nitinkoche03@gmail.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
# [WIP] Make Local Search Non-Accent-Sensitive
fixes(#14468)
---
**Description:**
This PR adds accent- and case-insensitive search for the
**SettingsWorkspaceMembers** component’s local search. It ensures that
searching for names or emails works correctly even if the user types
letters without accents.
**Implementation:**
- Added a helper util: `removeAccentsAndCase(text: string)`
- This util:
- Normalizes text to NFD form
- Removes diacritics (accents)
- Converts text to lowercase
- Replaced current `.includes(searchFilter)` logic with a normalized
comparison:
---
### Video ->
[Screencast from 2025-09-16
16-42-50.webm](https://github.com/user-attachments/assets/7035906c-9c5d-414d-81e5-74e53803628a)
---
Opening a draft pr for initial strategy review before extending it to
other components.
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Problem
**CRITICAL:** Two PRs were accidentally reverted when PR #14347 "Prevent
csv export injections" was merged:
1. **PR #14348** "[Page Layout] - Review Refactor" - ✅ **RESTORED**
2. **PR #14352** "Fix wrong path used by backend" - ✅ **RESTORED**
## Root Cause Analysis
During the merge of PR #14347, there was a complex merge conflict with
PR #14352 "Fix wrong path used by backend". The merge commit
`324d7204bb` in the PR #14347 branch brought in changes from PR #14352,
but during the conflict resolution, **BOTH PR #14348 and PR #14352's
changes were accidentally overwritten**.
## What This PR Restores
This PR restores **BOTH** PRs by cherry-picking their commits:
### ✅ PR #14348 Changes Restored:
- `GraphWidgetRenderer.tsx` - was deleted, now restored
- `WidgetRenderer.tsx` - was missing, now restored
- `SettingsPageLayoutTabsInstanceId.ts` - was deleted, now restored
- `useUpdatePageLayoutWidget.ts` - was renamed back, now restored with
correct name
- Multiple test files that were deleted
- Several hook files that were renamed/reverted
- File renames: `usePageLayoutWidgetUpdate.ts` →
`useUpdatePageLayoutWidget.ts`
- Hook refactoring and test file organization
- Page layout component improvements
### ✅ PR #14352 Changes Restored:
- **Types moved to twenty-shared:**
- `packages/twenty-shared/src/types/AppBasePath.ts` ✅ RESTORED
- `packages/twenty-shared/src/types/AppPath.ts` ✅ RESTORED
- `packages/twenty-shared/src/types/SettingsPath.ts` ✅ RESTORED
- **Navigation utilities moved to twenty-shared:**
- `packages/twenty-shared/src/utils/navigation/getAppPath.ts` ✅ RESTORED
- `packages/twenty-shared/src/utils/navigation/getSettingsPath.ts` ✅
RESTORED
- **200+ import statements updated** across the codebase to use
twenty-shared
- **Old type files deleted** from twenty-front/src/modules/types/
## Evidence of Complete Restoration
**Before (reverted state):**
- ❌ Types were in `packages/twenty-front/src/modules/types/`
- ❌ Page layout files missing
- ❌ Hook files incorrectly named
**After (this PR):**
- ✅ Types correctly in `packages/twenty-shared/src/types/`
- ✅ All page layout files restored
- ✅ Hook files correctly named
- ✅ All import statements updated
## Verification
**Total changes:**
- PR #14348: 36 files changed, 863 insertions(+), 442 deletions(-)
- PR #14352: 243 files changed, 492 insertions(+), 461 deletions(-)
- **Combined: 279 files changed, 1355 insertions(+), 903 deletions(-)**
## Impact
This completely restores both PRs that were accidentally lost, ensuring:
1. Page layout refactoring work is back
2. Type organization and path utilities are correctly in twenty-shared
3. Backend email paths work correctly again
4. No functionality is lost
Fixes the reversion caused by the merge conflict in PR #14347.
---------
Co-authored-by: nitin <142569587+ehconitin@users.noreply.github.com>
**Small Security Issue:** CSV exports were vulnerable to formula
injection attacks when users entered values starting with =, +, -, or @.
(only happens if a logged-in user injects corrupted data)
Solution:
- Added ZWJ (Zero-Width Joiner) protection that prefixes dangerous
values with invisible Unicode character
- This is the best way to preserve original data while preventing Excel
from executing formulas
- Added import cleanup to restore original values when re-importing
Changes:
- New sanitizeValueForCSVExport() function for security
- Updated all CSV export paths to use both security + formatting
functions
- Added comprehensive tests covering attack vectors and international
characters
- Also added cursor rules for better code consistency
---------
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
After moving a section on the frontend, this broke the path that was
sent by email on the backend.
This kind of error comes back every ~2-3 month under different forms so
we need a more robust solution: I moved routes to the shared folder,
that way we will share one common source of truth between the frontend
and the backend.
Fixes#14343
The goal of this PR is to test if Twenty can support a large number of
members, a question which was raised by a large company that is
considering moving away from Salesforce.
I was expecting the currentWorkspaceMembersState to cause a lot more
issue. It would be very hard to get rid of it in the context of actors,
I think that would require a big refactoring. I thought we'd have to do
it but it turns out the perf are pretty good. One thing we need to
improve is the pagination on the roles page, we'll wait for @Bonapara to
update that
## Add Morph Relation Field Display Support for Tables (one to many &
many to one)
**Features:**
- Display morph relation fields (one-to-many, many-to-one) in table
cells
- Multi-field record retrieval for improved performance
- Enhanced table cell rendering with morph relation support
**Components Added:**
- `MorphRelationManyToOneFieldDisplay` - Shows many-to-one morph
relations
- `MorphRelationOneToManyFieldDisplay` - Shows one-to-many morph
relations
TODO :
handle notes and tasks case if we choose these kind of objects as
targets/source for a morph relation
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
# Implement Morph Frontend Settings
Possiblity to create a morh relation from the Settings !
## Overview
Morph object system with new frontend settings UI for configuring morph
relations.
## What Changed
- **New Components**: `SettingsDataModelFieldMorphRelationForm`,
`SettingsMorphRelationMultiSelect`
- **Form System**: React Hook Form + Zod validation for morph relation
configuration
- **Preview System**: Live preview of field configurations with
validation
- **State Management**: Enhanced component state handling for complex
form interactions
## Technical Details
- **Architecture**: Restructured field input/display components for
better maintainability
- **Types**: Added comprehensive TypeScript types for morph relations
(`isFieldMorphRelation`, etc.)
- **Validation**: Dynamic validation rules based on field types and
relation patterns
- **Performance**: Optimized rendering with proper state management
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
This PR removes any V2 naming in state management logic and some minor
utils and hooks.
It has a lot of changes but nearly all of them were made by the rename
functionality of vscode which is deterministic, so it shouldn't
introduce any regression.
QA has been made on this PR on the main features of the app without any
noticeable issue.
Also renamed some other v2 naming related items :
- TextInputV2 => TextInput
- TextInput => SettingsTextInput
- ObjectFilterDropdownFilterSelectMenuItemV2 =>
ObjectFilterDropdownFilterSelectMenuItem
- useInitDraftValueV2 => useInitDraftValue
- useOpenRecordTableCellV2 => useOpenRecordTableCell
Removed the Variable FeildMetaDataType.UUID at line 52
from
twenty\packages\twenty-front\src\modules\settings\data-model\constants\SettingsNonCompositeFieldTypeConfigs.ts
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
This PR removes every legacy state management logic left in the code
base, we only keep our last component state management logic.
Removed :
- Scoped states logic
- Dropdown scope logic
- Scope id naming
- Component state v1
- Component state v2_alpha
# QA
| Component | Comments |
| --- | --- |
| AttachementDropdown | Ok |
| ObjectTasks | Ok |
| ActivityRichTextEditor | Ok |
| App | Ok dialogs work |
| AppRouterProviders | Ok dialogs work |
| RecordBoardScrollToFocusedCardEffect | Ok |
| RecordBoard | Ok |
| RecordBoardCard | OK |
| useSelectAllCards | Ok |
| RecordInlineCell | Ok |
| useInlineCell | Ok |
| RecordDetailRelationRecordsListItem | Ok |
| RecordDetailRelationSectionDropdownToMany | Ok |
| RecordDetailRelationSectionDropdownToOne | Ok |
| useHandleContainerMouseEnter | Ok |
| useResetTableRowSelection | Ok |
| useSelectAllRows | Ok |
| useSetRecordTableData | Ok |
| useRecordTable | Ok |
| useRecordTableMoveFocusedCell | Ok |
| useRecordTableMoveFocusedRow | Ok |
| useMoveHoverToCurrentCell | OK |
| useTriggerActionMenuDropdown | Ok |
| RecordTableBodyDragDropContextProvider | Ok |
| RecordTableHeaderCell | Ok |
| useSetCurrentRowSelected | Ok |
| useRecordTitleCell | Ok |
| SettingsObjectFieldActiveActionDropdown | Ok |
| SettingsObjectFieldInactiveActionDropdown | Ok |
| SettingsObjectFieldItemTableRow | Ok |
| SettingsObjectInactiveMenuDropDown | Ok |
| SettingsRoleEditEffect | Ok |
| SettingsRolesQueryEffect | Ok |
| Dropdown | Ok |
| useSelectableList | Ok |
| useSelectableListHotKeys | Ok |
| useSelectableListListenToEnterHotkeyOnItem | Ok |
| useNavigationSection | Ok |
| useCreateViewFromCurrentState | Ok |
| useDeleteViewFromCurrentState | Ok |
| useUpdateViewFromCurrentState | Ok |
| ViewPickerFavoriteFoldersDropdown | Ok |
| useCreateViewFromCurrentView | Ok |
| ViewBarDetails | Ok |
| WorkflowRunVisualizer | Ok |
| useHandleWorkflowRunDiagramCanvasInit | Ok |
| WorkflowDiagramCanvasBase | Ok |
| WorkflowRunVisualizerEffect | Ok |
| useRemoveStepFilter | Ok |
| useRemoveStepFilterGroup | Ok |
| useUpsertStepFilterSettings | Ok |
| WorkflowFindRecordsFilters | Ok |
| SettingsObjects | Ok |
This PR fixes a bug that happened when adding a field to a table right
after a field creation in the data model settings.
This happened because the backend adds the newly created field to all
relevant views without telling the frontend (because we don't have web
sockets yet), so the frontend ended up in a stale state, and when the
user added the field manually to a view the backend rightly threw an
error telling that the view field it already existed.
So the fix is just to refetch all views after a field creation, sparing
us the difficult work of manually updating the Apollo cache.
Fixes https://github.com/twentyhq/twenty/issues/13071
## Expected behavior
Described behavior regarding: (update | create) x (custom | standard) x
(icon, label, name, isSynced)
**Custom:**
- Field RELATION create: name, label, isSynced, icon should be editable
- Field RELATION update: name should not, icon label, isSynced should
- For other fields, icon, label, name, isSynced should be editable at
field creation | update
To simplify: Field RELATION name should not be editable at update
**Standards**
- Field: create does not makes sense
- Field: name should not, icon label, isSynced should (this will end up
in overrides)
To simplify, no Field RELATION edge case, name should not be editable at
update
**Note:** the FE logic is quite different as the UI is hiding some
details behind the syncWithLabel. See my comments and TODO there
## What I've tested:
(update | create) x (custom | standard) x (icon, label, name, isSynced,
description)
Currently, when a server query or mutation from the front-end fails, the
error message defined server-side is displayed in a snackbar in the
front-end.
These error messages usually contain technical details that don't belong
to the user interface, such as "ObjectMetadataCollection not found" or
"invalid ENUM value for ...".
**BE**
In addition to the original error message that is still needed (for the
request response, debugging, sentry monitoring etc.), we add a
`displayedErrorMessage` that will be used in the snackbars. It's only
relevant to add it for the messages that will reach the FE (ie. not in
jobs or in rest api for instance) and if it can help the user sort out /
fix things (ie. we do add displayedErrorMessage for "Cannot create
multiple draft versions for the same workflow" or "Cannot delete
[field], please update the label identifier field first", but not
"Object metadata does not exist"), even if in practice in the FE users
should not be able to perform an action that will not work (ie should
not be able to save creation of multiple draft versions of the same
workflows).
**FE**
To ease the usage we replaced enqueueSnackBar with enqueueErrorSnackBar
and enqueueSuccessSnackBar with an api that only requires to pass on the
error.
If no displayedErrorMessage is specified then the default error message
is `An error occured.`
In this PR:
- add query hashKey to ObjectMetadataItems query graphql cache to avoid
caching outdated queries
- improve performance by removing ResolveField at FieldLevel and adding
this at resolver level
Introduce a loading state to SaveButton and SaveAndCancelButtons
components to enhance user feedback during save operations. Update
SettingsNewObject to manage the loading state while submitting the form.
Fix https://github.com/twentyhq/core-team-issues/issues/572
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
# What
Fully deprecate old relations because we have one bug tied to it and it
make the codebase complex
# How I've made this PR:
1. remove metadata datasource (we only keep 'core') => this was causing
extra complexity in the refactor + flaky reset
2. merge dev and demo datasets => as I needed to update the tests which
is very painful, I don't want to do it twice
3. remove all code tied to RELATION_METADATA /
relation-metadata.resolver, or anything tied to the old relation system
4. Remove ONE_TO_ONE and MANY_TO_MANY that are not supported
5. fix impacts on the different areas : see functional testing below
# Functional testing
## Functional testing from the front-end:
1. Database Reset ✅
2. Sign In ✅
3. Workspace sign-up ✅
5. Browsing table / kanban / show ✅
6. Assigning a record in a one to many / in a many to one ✅
7. Deleting a record involved in a relation ✅ => broken but not tied to
this PR
8. "Add new" from relation picker ✅ => broken but not tied to this PR
9. Creating a Task / Note, Updating a Task / Note relations, Deleting a
Task / Note (from table, show page, right drawer) ✅ => broken but not
tied to this PR
10. creating a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
11. updating a relation from settings should not be possible ✅
12. deleting a relation from settings (custom / standard x oneToMany /
manyToOne) ✅
13. Make sure timeline activity still work (relation were involved
there), espacially with Task / Note => to be double checked ✅ => Cannot
convert undefined or null to object
14. Workspace deletion / User deletion ✅
15. CSV Import should keep working ✅
16. Permissions: I have tested without permissions V2 as it's still hard
to test v2 work and it's not in prod yet ✅
17. Workflows global test ✅
## From the API:
1. Review open-api documentation (REST) ✅
2. Make sure REST Api are still able to fetch relations ==> won't do, we
have a coupling Get/Update/Create there, this requires refactoring
3. Make sure REST Api is still able to update / remove relation => won't
do same
## Automated tests
1. lint + typescript ✅
2. front unit tests: ✅
3. server unit tests 2 ✅
4. front stories: ✅
5. server integration: ✅
6. chromatic check : expected 0
7. e2e check : expected no more that current failures
## Remove // Todos
1. All are captured by functional tests above, nothing additional to do
## (Un)related regressions
1. Table loading state is not working anymore, we see the empty state
before table content
2. Filtering by Creator Tim Ap return empty results
3. Not possible to add Tasks / Notes / Files from show page
# Result
## New seeds that can be easily extended
<img width="1920" alt="image"
src="https://github.com/user-attachments/assets/d290d130-2a5f-44e6-b419-7e42a89eec4b"
/>
## -5k lines of code
## No more 'metadata' dataSource (we only have 'core)
## No more relationMetadata (I haven't drop the table yet it's not
referenced in the code anymore)
## We are ready to fix the 6 months lag between current API results and
our mocked tests
## No more bug on relation creation / deletion
---------
Co-authored-by: Weiko <corentin@twenty.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Changes the default behavior for settings navigation items to stay
active when navigating to sub-pages.
**Problem:**
- Navigation items like "Data Model" and "Webhooks" were not staying
highlighted when navigating to detail pages
- This was because `matchSubPages` defaulted to requiring exact path
matches
**Solution:**
- Updated logic to make sub-page matching the default behavior (`end:
item.matchSubPages === false`)
- Only "Accounts" explicitly sets `matchSubPages: false` for its custom
sub-item navigation
- Removed redundant `matchSubPages: true` declarations throughout the
codebase
**URL Changes:** -- checked with @Bonapara
- `/settings/workspace` → `/settings/general`
- `/settings/workspace-members` → `/settings/members`
- `/settings/api-keys` → `/settings/apis`
- `/settings/developers/webhooks` → `/settings/webhooks`
before:
https://github.com/user-attachments/assets/56b94a49-9c31-4bb5-9875-ec24f4bc4d1e
after:
https://github.com/user-attachments/assets/38742599-c045-44d1-8020-56f3eacca779
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>