Commit Graph

395 Commits

Author SHA1 Message Date
Félix Malfait 27da9d60eb fix: set isActive=true in morph migration & add system fields toggle (#17736)
## Summary

Three fixes in this PR:

### 1. Migration commands now set `isActive = true` and use generic
'Target' label

When converting relation fields to `MORPH_RELATION` type, the migration
commands now:
- Set `isActive = true` to prevent inactive fields from being selected
as the representative morph field
- Update all field labels to generic **'Target'** instead of keeping
individual labels like 'Company', 'Person'

This ensures the UI shows a coherent label ('Target') alongside 'X
Objects' for the type.

**Files changed:**
- `1-17-migrate-note-target-to-morph-relations.command.ts`
- `1-17-migrate-task-target-to-morph-relations.command.ts`

### 2. Added system fields/relations toggles in Settings

The fields and relations tables in Settings > Data Model were filtering
out system fields with no way to view them. Added a "System fields" /
"System relations" toggle (visible in advanced mode) to allow viewing
these fields.

**Files changed:**
- `SettingsObjectFieldTable.tsx`
- `SettingsObjectRelationsTable.tsx`

This matches the existing behavior on the Objects table which already
has a "System objects" toggle.
2026-02-05 13:35:46 +00:00
Weiko 8674cf973e Display "Not shared" indicator for RLS-restricted relation fields (#17713)
## Context
Previously, if for example a Person had a companyId but the company
relation was null due to RLS, the company column appeared empty. Now it
displays ForbiddenFieldDisplay to indicate the relation exists but is
inaccessible.

When RLS restricts access to a related record, the frontend now shows a
"Not shared" indicator (with lock icon) instead of an empty field.

<img width="1275" height="399" alt="Screenshot 2026-02-04 at 15 37 53"
src="https://github.com/user-attachments/assets/870306f8-f811-4dc0-b23b-a33e89043a37"
/>
2026-02-04 16:49:39 +00:00
Etienne 4fcc424e24 Files field - add files field display and input + filtering (#17637)
This PR introduces a new FILES field type for Twenty CRM, allowing users
to attach multiple files to any record.

- Files field display
- Files field preview
- Files field input
- Files field filtering

To test : 
1/ need to activate feature flag `IS_FILES_FIELD_ENABLED` + create a new
FILES field

- display in read only, edit, inline, table
- edit
- filter
- export


closes https://github.com/twentyhq/core-team-issues/issues/2154


<img width="354" height="134" alt="Screenshot 2026-02-02 at 19 11 01"
src="https://github.com/user-attachments/assets/3c3de89e-f6b6-4526-b710-e4c7ee1a6d30"
/>
<img width="1081" height="933" alt="Screenshot 2026-02-02 at 19 10 41"
src="https://github.com/user-attachments/assets/7c9a7278-edb7-4d4a-882c-f7404689d011"
/>
<img width="1073" height="719" alt="Screenshot 2026-02-02 at 19 10 33"
src="https://github.com/user-attachments/assets/79cc372b-56a2-4cbf-b4fe-023adc4753a8"
/>
2026-02-04 10:55:48 +00:00
Marie 54cf857a1a Revert "fix: prevent default object re-selection in relation field fo… (#17619)
I suggest to revert [this
PR](https://github.com/twentyhq/twenty/pull/17313) as it had already
been fixed [in this
PR](https://github.com/twentyhq/twenty/pull/17209/changes) (which fixes
more than it says in its title). Issue was tracked by [this
ticket](https://github.com/twentyhq/core-team-issues/issues/2049) not
very explicit - sorry, my fault.
Code added in the PR does not add value
2026-02-02 10:51:11 +00:00
Clayton b8d85e0b26 fix: prevent default object re-selection in relation field form (#17313)
Fixes #17111

### Problem
When creating a Relation field, after deselecting the pre-selected
default object (e.g., Company) and selecting a different object (e.g.,
Opportunity), both objects would end up being selected, showing "2
Objects" instead of just the newly selected one.

### Root Cause
The `initialMorphRelationsObjectMetadataIds` array was being recreated
on every component render, causing react-hook-form's `Controller` to
treat the `defaultValue` prop as a new value and re-apply it after user
changes.

### Solution
1. **Memoized the initial value**: Used `useMemo` to ensure
`initialMorphRelationsObjectMetadataIds` has a stable reference across
renders
2. **Added initialization guard**: Used `useEffect` with a `useRef` flag
to ensure the default value is only set once during component mount
3. **Maintained Controller defaultValue**: Kept the `defaultValue` prop
on the Controller, which now works correctly with the stable memoized
value

### Changes
- `SettingsDataModelFieldRelationForm.tsx`: Added memoization and
initialization guard to prevent default value re-application

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-01-30 17:12:43 +00:00
Eniola Osabiya 1cc08b84c4 feat: Add bulk input mode for select options #5539 (#17459)
- Implemented bulk input mode in SettingsDataModelFieldSelectForm to
allow users to input multiple options at once.
- Added convertBulkTextToOptions and convertOptionsToBulkText utility
functions for handling bulk text conversion.
- Created tests for both conversion functions to ensure correct
functionality.

Screenshot:
<img width="601" height="752" alt="image"
src="https://github.com/user-attachments/assets/95932860-090e-4743-9bd9-7aa6747ad04f"
/>
<img width="543" height="362" alt="image"
src="https://github.com/user-attachments/assets/84490808-2e0f-4126-951e-167b35f1b0d0"
/>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-01-29 08:49:38 +00:00
Félix Malfait 161689be18 feat: fix junction toggle persistence and add type-safe documentation paths (#17421)
## Summary

- **Fix junction relation toggle not being saved**: The form schema
wasn't tracking the `settings` field, so changes to
`junctionTargetFieldId` weren't marked as dirty
- **Add type-safe documentation paths**: Generate TypeScript constants
from `base-structure.json` to prevent broken documentation links
- **Create many-to-many relations documentation**: Step-by-step guide
for building many-to-many relations using junction objects
- **Update `getDocumentationUrl`**: Now uses shared constants from
`twenty-shared` for base URL, default path, and supported languages

## Key Changes

### Junction Toggle Fix
- Added `settings` field to the form schema in
`SettingsDataModelFieldRelationForm.tsx`
- Fixed the toggle to properly merge settings when updating
`junctionTargetFieldId`

### Type-Safe Documentation Paths
- New constants in `twenty-shared/constants`:
- `DOCUMENTATION_PATHS` - All 161 documentation paths as typed constants
  - `DOCUMENTATION_SUPPORTED_LANGUAGES` - 14 supported languages
  - `DOCUMENTATION_BASE_URL` / `DOCUMENTATION_DEFAULT_PATH`
- Generator script: `yarn docs:generate-paths`
- CI integration: Added to `docs-i18n-pull.yaml` workflow

### Documentation
- New article:
`/user-guide/data-model/how-tos/create-many-to-many-relations`
- Updated `/user-guide/data-model/capabilities/relation-fields.mdx` with
Lab warning and link

## Test plan
- [ ] Verify junction toggle saves correctly when enabled/disabled
- [ ] Verify documentation link opens correct localized page
- [ ] Verify `yarn docs:generate-paths` regenerates paths correctly
2026-01-25 13:29:20 +01:00
martmull 0091ef5f6c Sync built files (#17379)
as title, upload built files to local storage

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-23 13:43:53 +01:00
Baptiste Devessier 183cf6c803 Shrink table rows (#17360)
We often use the `fr` unit in a CSS grid thinking that it will force the
max-width of the grid's items. However, [`1fr` is always equal to
`minmax(auto, 1fr)`](https://stackoverflow.com/a/52861514). The
consequences are:

- By default, the width of the element will be `1fr`.
- However, if the size of the element becomes wider than the resolved
dimension of `1fr`, the item will expand to match its `auto` width. This
can be easily encountered when an item has a really long text. The
`auto` size will be the dimension of the long text displayed on a single
line.

If you want your element not to overflow, you can use `minmax(0, 1fr)`
instead of `1fr`.

This is a known behavior in the community. CSS frameworks like Tailwind
CSS even made their utility classes setting grid columns use `minmax(0,
xfr)` by default.

<img width="1380" height="84" alt="CleanShot 2026-01-22 at 16 11 00@2x"
src="https://github.com/user-attachments/assets/ace3c862-90ef-4a47-9ad5-9ae8b6e0fe40"
/>

See:
https://www.bigbinary.com/blog/understanding-the-automatic-minimum-size-of-flex-items.

Another fix is to use `min-width: 0;` on items themselves, instead of
using `minmax(0, 1fr)` at the grid level. This would make it possible to
create a reusable `Td` component.

## Data model - fields

### Before
<img width="1120" height="1808" alt="CleanShot 2026-01-22 at 15 46
48@2x"
src="https://github.com/user-attachments/assets/893115f4-219d-4a75-b628-56315298d791"
/>

### After
<img width="1120" height="1808" alt="CleanShot 2026-01-22 at 15 47
00@2x"
src="https://github.com/user-attachments/assets/093ae231-ccae-4df5-8227-a662a3fae97e"
/>

## Data model - relations

### Before
<img width="1172" height="754" alt="CleanShot 2026-01-22 at 16 00 33@2x"
src="https://github.com/user-attachments/assets/3367b849-a4f4-471b-b73a-a80a95368640"
/>

### After
<img width="1146" height="770" alt="CleanShot 2026-01-22 at 16 00 44@2x"
src="https://github.com/user-attachments/assets/ff08556e-fc16-4984-bd4b-bb15f4dabf36"
/>

## Object level object field permission

### Before
<img width="1150" height="1902" alt="CleanShot 2026-01-22 at 15 50
16@2x"
src="https://github.com/user-attachments/assets/adce1ba1-042b-4892-9a0e-af254109d03c"
/>

### After
<img width="1150" height="1902" alt="CleanShot 2026-01-22 at 15 50
01@2x"
src="https://github.com/user-attachments/assets/55476711-2573-43ae-b1d6-b8695f4305ab"
/>
2026-01-22 19:42:09 +00:00
Ayesha Waseem 669da1a87d fix: display current object name in morph relation picker after rename (#17209)
**Summary**

Issue #16963: When an object is renamed, the morph relation picker still
shows the old name.

**Root cause**

The picker used searchRecord.objectNameSingular from the GraphQL search
response, which can be stale after a rename.
The search record stores the object name at query time, not the current
metadata.

**Solution**

- Updated SingleRecordPickerMenuItem:
- Added useObjectMetadataItems to access current object metadata.
- Look up the current object metadata by morphItem.objectMetadataId.
- Use labelSingular (or nameSingular as fallback) instead of
searchRecord.objectNameSingular for display.
- Updated MultipleRecordPickerMenuItemContent:
- Use objectMetadataItem.labelSingular (already available as a prop)
instead of searchRecord.objectNameSingular.

---------

Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
2026-01-22 15:40:57 +00:00
Félix Malfait 3ed67b825e feat: implement generic many-to-many junction relation support (#16820)
## Overview

This PR implements **generic many-to-many relation support** through
junction tables (also known as associative entities or join tables).
This replaces the need for hardcoded taskTarget/noteTarget logic and
provides a flexible foundation for modeling complex entity
relationships.

## Architecture

### Data Model

Many-to-many relationships are implemented using a **junction object
pattern**:

```
┌─────────┐       ┌──────────────────┐       ┌─────────┐
│  Pet    │──────>│   PetRocket      │<──────│ Rocket  │
│         │ 1:N   │  (junction)      │  N:1  │         │
│ rockets ├───────┤ pet    : Pet     ├───────┤         │
└─────────┘       │ rocket : Rocket  │       └─────────┘
                  └──────────────────┘
```

The junction object (PetRocket) has:
- A `MANY_TO_ONE` relation to **Pet** (the source)
- A `MANY_TO_ONE` relation to **Rocket** (the target)

The source object (Pet) has a `ONE_TO_MANY` relation pointing to the
junction, with **field settings** that specify which target field to
follow.

### Field Settings Schema

Junction configuration is stored in `FieldMetadataRelationSettings`:

```typescript
{
  relationType: "ONE_TO_MANY",
  // Points to the target field on the junction object
  junctionTargetFieldId?: string;      // For regular relations
  junctionTargetMorphId?: string;      // For polymorphic relations
}
```

**Two configuration modes:**
1. **`junctionTargetFieldId`** - References a specific `RELATION` field
on the junction
2. **`junctionTargetMorphId`** - References a `morphId` group for
polymorphic targets (e.g., link to Person OR Company)

### GraphQL Query Generation

When a junction relation is detected, the GraphQL fields are generated
to fetch the nested target:

```graphql
query GetPetWithRockets {
  pet(id: "...") {
    rockets {           # ONE_TO_MANY to junction
      id
      rocket {          # Target field on junction
        id
        name
        __typename
      }
    }
  }
}
```

For polymorphic junction targets:
```graphql
caretakerPerson { id, name }
caretakerCompany { id, name }
```

## Frontend Architecture

### Display Flow

1. **Detection**: `hasJunctionConfig()` checks if field has junction
settings
2. **Config Resolution**: `getJunctionConfig()` resolves junction object
metadata and target fields
3. **Record Extraction**: `extractTargetRecordsFromJunction()` extracts
target records from junction records
4. **Rendering**: Target records displayed as chips (not junction
records)

### Edit Flow

1. **Picker Opening**: Initializes the multi-record picker with:
   - Searchable object types (derived from junction target fields)
   - Pre-selected items (extracted from existing junction records)
   
2. **Selection Handling**: Manages create/delete of junction records:
   - **Select**: Creates new junction record with source + target IDs
   - **Deselect**: Finds and deletes the junction record
- **Optimistic Updates**: Manually updates Recoil store before API call

### Key Trade-offs

| Decision | Trade-off |
|----------|-----------|
| Junction records managed manually | More control over optimistic
updates, but requires manual cache management |
| Settings stored per-field | Flexible (same junction can power
different views), but requires UI to configure |
| Polymorphic via morphId groups | Supports N target types, but adds
query complexity |
| Feature flag gated | Safe rollout, but requires flag management |

## Backend Changes

- **Validation**: Junction target field must exist and be a valid
`MANY_TO_ONE` relation
- **Settings**: Extended `FieldMetadataRelationSettings` type with
junction fields
- **Dev Seeder**: Added sample junction objects (PetRocket,
EmploymentHistory, PetCareAgreement) for testing

## How to Test

1. Enable the `IS_JUNCTION_RELATIONS_ENABLED` feature flag
2. Create objects with junction pattern (Pet → PetRocket → Rocket)
3. Configure the junction target in field settings (advanced mode)
4. Verify:
- Display shows target objects (Rockets), not junction records
(PetRockets)
   - Picker allows selecting/deselecting targets
   - Changes persist correctly



https://github.com/user-attachments/assets/d04f057a-228c-4de8-af48-76bb2d72cac1

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-01-20 21:58:13 +01:00
Etienne 30c13fc947 Files v2 - Add new FILES field type (#17236)
In this PR : 
- New field type FieldMetadataType.FILES added (as jsonb in DB)
- Backend: GraphQL types, validation, REST API schema, data processor
handling
- Frontend: field configuration in settings
- Feature flag IS_FILES_FIELD_ENABLED to gate the feature
- Integration tests for create/filter validation
- Dev seed: Feature flag enabled + FILES field on survey result object


To do in next PRs : 
- Backend : 
-- new workspaceFile controller (for download) & new workspaceFile
upload resolver (for upload)
-- pre-hook/post-hook to ensure fileId existence + listener to ensure
cleaning
- Frontend : FILES field display/edit in table view, record, ...
2026-01-20 17:03:49 +00:00
Abdullah. 92eff62523 Replace test-runner with vitest for storybook (#17187) 2026-01-18 03:25:45 +00:00
Félix Malfait c737028dd6 Move tools/eslint-rules to packages/twenty-eslint-rules (#17203)
## Summary

Moves the custom ESLint rules from `tools/eslint-rules` to
`packages/twenty-eslint-rules` for better organization within the
monorepo packages structure.

## Changes

- Move `eslint-rules` from `tools/` to `packages/twenty-eslint-rules`
- Use `loadWorkspaceRules` from `@nx/eslint-plugin` to load custom rules
- Update all ESLint configs to use the `twenty/` rule prefix instead of
`@nx/workspace-`
- Update `project.json`, `jest.config.mjs` with new paths
- Update `package.json` workspaces and `nx.json` cache inputs
- Update Dockerfile reference

## Technical Details

The custom ESLint rules are now loaded using Nx's `loadWorkspaceRules`
utility which:
- Handles TypeScript transpilation automatically
- Allows loading workspace rules from any directory
- Provides a cleaner approach than the previous `@nx/workspace-`
convention

## Testing

- Verified all 17 custom ESLint rules load correctly from the new
location
- Verified linting works on dependent packages (twenty-front,
twenty-server, etc.)
2026-01-17 07:37:17 +01:00
Abdullah. 2c8d3f02e1 feat: upgrade to Storybook version 10 (#17110)
Upgraded to Storybook 10. We still use `@storybook/test-runner` for
testing since it appears it'd require more work to move from Jest to
Vitest than I initially anticipated, but I completed this PR to fix
`storybook:serve:dev` - it takes time to load, but it works the way it
used to with Storybook 8.


https://github.com/user-attachments/assets/7afc32c6-4bcf-4b37-b83b-8d00d28dda15
2026-01-13 08:18:07 +00:00
Thomas des Francs d7638a9075 Fix settings data model tables to take full width and align columns (#17104)
## Summary
- Updated Relations and Fields tables in the object detail settings page
to use flexible width (`1fr`) for the Name column instead of fixed
pixels
- Aligned column widths between both tables (`1fr 148px 148px 36px`) so
the App and Type/Data type columns line up

## Test plan
- [ ] Navigate to Settings > Data model > select any object (e.g.,
Companies)
- [ ] Verify the Relations table rows take the full available width
- [ ] Verify the Fields table rows take the full available width
- [ ] Verify the App and Type/Data type columns are aligned between both
tables
2026-01-12 18:58:29 +01:00
Abdullah. 5240a1818f feat: upgrade Storybook to version 9 (#17077)
Upgraded from 8.6.15 to 9.1.17 in two steps: 
- 8.6.15 -> 9.0.0 
- 9.0.0  -> 9.1.17

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

Additionally, once we upgrade to Version 10 successfully, I will start
looking into integrating the official Vitest add-on.
2026-01-11 13:54:41 +00:00
Abdullah. a46619ec55 fix: enable save button when changing currency default value (#16864)
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>
2026-01-06 18:02:43 +00:00
Paul Rastoin 221a6262f0 Fix metadata relation field settings item type tag display (#16949)
# Introduction
followup https://github.com/twentyhq/twenty/pull/16880

Fixing the item tag type displayal of the relation field within an
object
Inferring the application id at field level instead of object level

## From
<img width="1162" height="1220" alt="image"
src="https://github.com/user-attachments/assets/28af2242-2786-4e17-b910-3fc26871bc04"
/>

## To
<img width="1162" height="1220" alt="image"
src="https://github.com/user-attachments/assets/63fb89a0-a853-4157-baa4-d0f758648c3e"
/>
2026-01-06 11:23:17 +01:00
Rajdeep Das de33d17809 Fix navigation memory after custom object rename (#16918)
This PR fixes an issue where exiting Settings after renaming a custom
object could redirect to a stale object URL and result in a `404`. When
a custom object name was updated, the memorized navigation URL was not
kept in sync, causing redirects to use the old object route.
The navigation state is now updated only when the memorized URL belongs
to the renamed object, ensuring redirects always point to the correct
route while preserving unrelated navigation context.

Fixes https://github.com/twentyhq/twenty/issues/11291

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
2026-01-05 17:46:22 +00:00
Paul Rastoin 1128331cc1 Fix field item type tag (#16860)
# 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
2025-12-30 15:02:07 +00:00
Félix Malfait 4f1f0eb177 Redesign Object/Field tables (#16844)
Redesign the data model pages for more clarity / better distinction
between fields and relations
2025-12-30 09:49:55 +01:00
nitin e5e5ae8e1d fix: guard against invalid date and undefined links field value (#16039)
closes https://github.com/twentyhq/twenty/issues/15854

- Add `isValid()` check in `formatDateISOStringToDateTime` before
calling `formatInTimeZone`
- Add `isDefined()` guard in `getFieldLinkDefinedLinks` (mirrors
`phonesUtils` pattern)

before:


https://github.com/user-attachments/assets/1eb89fa4-70b6-4794-8860-0a42522598b5



https://github.com/user-attachments/assets/781c7d37-c435-4832-98d4-8e6925b51e10



after:


https://github.com/user-attachments/assets/b1c22d25-4e8e-45c3-af98-be1684a5962e



https://github.com/user-attachments/assets/ce084a9d-03b8-4f88-8522-a32cb1b7cf2f

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-12-29 17:03:24 +00:00
Abdullah. c020f71ba1 Add "number of decimal" on currency field. (#16439)
Closes [571](https://github.com/twentyhq/core-team-issues/issues/571).

Replicates the behavior of number field and allows specifying the number
of decimals for currency field.

<img width="931" height="858" alt="image"
src="https://github.com/user-attachments/assets/f5100d58-b1b0-4a88-a090-e98b2feeebd0"
/>

Currencies around the world have a maximum of three decimal places -
BHD, KWD etc. However, I have added a maximum of five decimal places in
case someone wants to use the currency field type for displaying things
like `per-second-billing` or `exchange rates`.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Adds configurable decimals (0–5) for currency fields, updating
settings UI, types/schema, display/aggregate formatting, and input
precision.
> 
> - **Currency field settings**:
> - Add `decimals` (0–5) to `FieldCurrencyMetadata.settings` and
validate via `currencyFieldSettingsSchema`.
> - Update `SettingsDataModelFieldCurrencyForm` to manage `format`
(short/full) and `decimals` with counter when `full`; wire defaults via
`useCurrencySettingsFormInitialValues`.
> - **Display & aggregation**:
> - `CurrencyDisplay` and
`transformAggregateRawValueIntoAggregateDisplayValue` honor `decimals`
when `format` is `full`; keep short format using `formatToShortNumber`.
> - **Input**:
>   - Increase currency `IMaskInput` precision with `scale=5`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
959a8fc1ea726d206548ea32cada28d77c1c6eb9. 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>
2025-12-26 22:53:43 +05:00
martmull 158a7a89d5 1859 extensibility improve application settings section (#16786)
## After
<img width="934" height="750" alt="image"
src="https://github.com/user-attachments/assets/f2d7f743-fa4f-4e7d-a060-033f6087e4b6"
/>
<img width="1008" height="652" alt="image"
src="https://github.com/user-attachments/assets/3d36bfae-aa30-4946-88f2-e99bf074f768"
/>
2025-12-24 14:35:36 +01:00
Félix Malfait b27a97f2c5 feat: enforce @/ alias for imports and fix all relative parent imports (#16787)
## 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
2025-12-23 22:57:51 +01:00
Abdul Rahman ba76cf4fed Fix: Record label identifier setting not saving on first attempt (#16769) 2025-12-23 09:17:31 +01:00
Félix Malfait 1088f7bbab feat: add lingui/no-unlocalized-strings ESLint rule and fix translations (#16610)
## 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
2025-12-17 22:08:33 +01:00
Lakshay Manchanda d43e21b695 Feature 15797 add secondary action button (#16582)
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>
2025-12-17 09:13:00 +01:00
Abhishek Kumar 8dbcd506ed feat: add feature to customize onClick behaviour for phone, email and links data type (#16265)
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>
2025-12-12 14:34:47 +01:00
Marie 7a7f36d38c [Fix] Forbid default value removal for non-nullable select field (#16465)
Permanently fixes https://github.com/twentyhq/private-issues/issues/389

On a non-nullable select field, default value should not be removable,
otherwise users won't be able to create new records from the interface.
This PR enforces this in FE and BE.


https://github.com/user-attachments/assets/1dfa2bcc-b9df-4a00-9915-679d36ec1b25
2025-12-11 00:53:48 +01:00
Abdullah. ee08060798 Improve deactivated objects & fields behaviors. (#16090)
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>
2025-12-01 15:04:36 +00:00
neo773 316aec3c40 fix: prevent NUMERIC field type creation via API (#16038)
Block users from creating NUMERIC, POSITION, and TS_VECTOR fields via
the API as these are system-only types. Users should use NUMBER instead
of NUMERIC.

/closes #16023
2025-11-25 09:51:48 +01:00
Paul Rastoin 8299488f21 Fix front data model edition + non nullable workspaceCustom application migration (#16016)
# 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
2025-11-24 13:39:04 +00:00
Guillim 0389fcf00d removing feature flag IS_MORPH_RELATION_ENABLED (#15783)
releasing the morph feature for all workspaces
2025-11-13 12:03:25 +01:00
Balaji Krishnamurthy ec7e49c8bb fix: minor color changes (#15616)
Closes #15597

The `color` of `OnBoardingModalCircularIcon` was set to `gray`. Now it
is set to `inverted` and it is displayed properly. I couldn't figure out
how to reach the onboarding screen, so I created a temporary path and
rendered the element there to verify the changes. Attaching screenshots
of the same.
<img width="398" height="393" alt="Screenshot from 2025-11-05 00-11-05"
src="https://github.com/user-attachments/assets/25efc790-92a3-42b5-8298-5128a3f1a466"
/>

<img width="398" height="418" alt="Screenshot from 2025-11-05 00-10-32"
src="https://github.com/user-attachments/assets/af52c695-4b01-40e9-a873-39d491c633cc"
/>

Additionally, a border has been added to the color picker icons.
<img width="573" height="383" alt="Screenshot from 2025-11-05 00-12-23"
src="https://github.com/user-attachments/assets/03d967aa-8c6f-4dfd-be3d-a2e16fe12b9a"
/>

I noticed that the dropdown after clicking on the icon also renders a
bunch of colors. Do let me know if these need the same border as well.
<img width="571" height="366" alt="Screenshot from 2025-11-05 00-12-37"
src="https://github.com/user-attachments/assets/a13bf253-6765-4d7a-9f0f-17cb7375a515"
/>

---------

Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
2025-11-13 10:00:28 +00:00
Félix Malfait cff17db6cb Enhance role-check system with stricter checks (#15392)
## Overview

This PR strengthens our permission system by introducing more granular
role-based access control across the platform.

## Changes

### New Permissions Added
- **Applications** - Control who can install and manage applications
- **Layouts** - Control who can customize page layouts and UI structure
- **AI** - Control access to AI features and agents
- **Upload File** - Separate permission for file uploads
- **Download File** - Separate permission for file downloads (frontend
visibility)

### Security Enhancements
- Implemented whitelist-based validation for workspace field updates
- Added explicit permission guards to core entity resolvers
- Enhanced ESLint rule to enforce permission checks on all mutations
- Created `CustomPermissionGuard` and `NoPermissionGuard` for better
code documentation

### Affected Components
- Core entity resolvers: webhooks, files, domains, applications,
layouts, postgres credentials
- Workspace update mutations now use whitelist validation
- Settings UI updated with new permission controls

### Developer Experience
- ESLint now catches missing permission guards during development
- Explicit guard markers make permission requirements clear in code
review
- Comprehensive test coverage for new permission logic

## Testing
-  All TypeScript type checks pass
-  ESLint validation passes
-  New permission guards properly enforced
-  Frontend UI displays new permissions correctly

## Migration Notes
Existing workspaces will need to assign the new permissions to roles as
needed. By default, all new permissions are set to `false` for non-admin
roles.
2025-11-07 15:37:17 +01:00
Guillim 373399fadc Settings of morph needs a CSS fix (#15681)
adding margin auto for morph preview card in order to vertically align
the box, as per figma

Before
<img width="467" height="331" alt="Screenshot 2025-11-06 at 16 36 00"
src="https://github.com/user-attachments/assets/23543cdc-d0f3-4bbf-8dc1-4ac5f26f786e"
/>

After
<img width="576" height="362" alt="Screenshot 2025-11-06 at 16 36 16"
src="https://github.com/user-attachments/assets/8530d59f-53a2-4eaa-834a-68b801bba3c8"
/>

Fixes https://github.com/twentyhq/core-team-issues/issues/1846
2025-11-06 17:06:04 +01:00
martmull abde3c04ac 1630 extensibility twenty cli ability to create edit and delete fields (#15501)
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
2025-11-05 17:50:06 +01:00
Raphaël Bosi 198bf5a333 Complete color refactoring (#15414)
# 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.
2025-10-29 18:08:51 +00:00
沙什瓦特 8d823827da fix: made standard object labels editable (#15388)
Fixes #15302 

## Video ( Fixed ) :

[Uploading
IssueFixed.mov…](https://drive.google.com/file/d/1XNk3i3ae9Wafelqgbj5GujaPAJRQRcQh/view?usp=sharing)

---------

Co-authored-by: prastoin <paul@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-28 19:03:20 +01:00
Paul Rastoin 503a5029da Refactor twenty-front metadata api services for v2 (#15360)
# 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
2025-10-28 10:50:41 +01:00
Félix Malfait f7421c5fc0 Add queue management dashboard (#15202)
Adds a comprehensive queue management interface to the admin panel for
viewing and managing background jobs.

**Features:**
- Queue detail pages showing paginated job lists (50 per page)
- Filter jobs by state: completed, failed, active, waiting, delayed,
paused
- Checkbox selection with bulk actions (delete jobs, retry failed jobs)
- Per-job dropdown menu for individual retry/delete
- Expandable rows showing error messages, stack traces, and job data
- Relative timestamps with hover tooltips
- Display attempt counts on failed jobs
- Dynamic retention policy info from backend

**Changes:**
- Backend: New AdminPanelQueueService with GraphQL endpoints for job
listing, retry, and delete
- Frontend: Queue detail page with QueueJobsTable component
- Updated retention policy: completed jobs kept 4 hours, failed jobs
kept 7 days (max 1000 each)
- Added JobState enum for type safety

<img width="634" height="696" alt="Screenshot_2025-10-20_at_11 45 25"
src="https://github.com/user-attachments/assets/c67bcd27-26cf-47f5-9575-3cd5684d006b"
/>
<img width="484" height="680" alt="Screenshot_2025-10-20_at_11 45 14"
src="https://github.com/user-attachments/assets/68725cc6-b3ec-4098-99ca-f9a717d6f8f1"
/>
<img width="490" height="643" alt="Screenshot_2025-10-20_at_11 45 05"
src="https://github.com/user-attachments/assets/b68a5809-33ff-4452-b48b-741aff7f1dd6"
/>



<img width="685" height="662" alt="Screenshot 2025-10-20 at 13 15 01"
src="https://github.com/user-attachments/assets/eeb5207b-de5c-4b18-bdde-392892053dab"
/>
2025-10-21 16:02:50 +02:00
Guillim 478328129d Morph-settings-relation-form-merge-follow-up (#15122)
🎯 Merge Settings Relation and Morph Relation Forms followup
https://github.com/twentyhq/twenty/pull/15062


Here we fixed some little comments that could have be done earlier in
the main PR
2025-10-16 11:42:47 +02:00
Guillim 20fdb66bd3 Morph-settings-relation-and-morph-merge (#15062)
🎯 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
2025-10-16 09:56:24 +02:00
martmull b16ab1b7c9 1518 extensibility front add an application section in settings (#15056)
Protected by IS_APPLICATION_ENABLED featureFlag

Add `Application` section in settings

<img width="301" height="137" alt="image"
src="https://github.com/user-attachments/assets/ee53bdd2-36f6-45c6-8646-17b1e08abf00"
/>


A `settings/applications` route listing all installed applications

<img width="661" height="428" alt="image"
src="https://github.com/user-attachments/assets/69d534c4-4e9e-452a-a3d9-ded0223bb457"
/>

Introduce a new Tag for application managed items

<img width="885" height="759" alt="image"
src="https://github.com/user-attachments/assets/19767be5-61e5-4bd2-a51d-54ed9bfb1923"
/>



A `settings/applications/<application_id>` details setting page listing
all objects, serverlessFunctions and agents created by the application:

<img width="917" height="778" alt="image"
src="https://github.com/user-attachments/assets/7fc056a6-1d73-4242-b2eb-6f8955d8597d"
/>

A `settings/applications/<application_id>/<serverless_function_id>`

<img width="905" height="652" alt="image"
src="https://github.com/user-attachments/assets/56ca0021-26bf-42cb-9abf-34879f16050a"
/>

Add trigger tab in serverless function details (readonly for now)

<img width="899" height="724" alt="image"
src="https://github.com/user-attachments/assets/5eeefa35-f2a4-4fd8-a640-7b5c5891f226"
/>

Set object, serverless and agent setting detail pages readonly for
managed items
<img width="1075" height="859" alt="image"
src="https://github.com/user-attachments/assets/57c73d69-4980-47a2-b752-8dc5ab494530"
/>
<img width="648" height="582" alt="image"
src="https://github.com/user-attachments/assets/5ad5f3f7-3bc3-4e40-870a-4981c6492524"
/>
<img width="982" height="692" alt="image"
src="https://github.com/user-attachments/assets/7ad756c4-5d33-4a0a-9eb8-416c040362b9"
/>
<img width="1077" height="647" alt="image"
src="https://github.com/user-attachments/assets/e086b9f5-4062-4d10-82a9-4023de3cad3f"
/>
2025-10-15 17:13:29 +02:00
Félix Malfait 938debd83e Refactor record layouts for backend-driven configuration (#15021)
## Refactor: Prepare frontend record layouts for backend-driven
configuration

This PR simplifies and prepares the frontend record layout system for
eventual migration to backend-driven layouts, aligning the architecture
with the existing PageLayout system used for dashboards.

### Key Changes

**Architecture Improvements:**
- Created unified LayoutRenderingContext that works for both record
pages (with targetRecord) and dashboards (standalone)
- Replaced prop drilling with context-based data flow - cards access
targetRecord and isInRightDrawer via context hooks
- Introduced useTargetRecord() helper hook that provides type-safe
access to the current record
- Created generic CardRenderer component that handles configuration
injection and context guards uniformly

**Configuration System:**
- Converted all tab icons from React components to JSON-serializable
strings (e.g., Icon: IconCheckbox → icon: 'IconCheckbox')
- Added configuration field to cards, matching the widget configuration
pattern on the backend
- Created CardConfiguration types system similar to WidgetConfiguration
on the backend
- Moved widget-specific props (like showDuplicatesSection) into
configuration objects

**Code Organization:**
- Extracted visibility evaluation logic into reusable
evaluateTabVisibility() utility
- Organized layouts into dedicated files (one per object:
base-record-layout.ts, company-record-layout.ts, etc.)
- Renamed components to match their purpose: Notes → NotesCard,
Attachments → FilesCard, etc.
- Consolidated card rendering from registry object to direct
getCardComponent() function

**API Alignment:**
- Made ifNoReadPermissionObject an explicit part of TabVisibilityConfig
(follows if* naming convention)
- Removed redundant targetObjectNameSingular from tab-level (now derived
from visibility config)
- Card API now mirrors Widget API (both use type, configuration,
accessed via context)
2025-10-10 16:26:17 +02:00
Ashwin Temkar 1d09cb949a Feat/multivalue limit (#14961)
## Summary
1. This change introduces the ability to limit how many values a
multi-value field can contain (for example: maximum number of emails,
phone numbers, links, or array items).
2. It centralizes the limit as a shared constant and type, validates
settings on the server, updates front-end types and components to
consume the setting, and adds a small settings UI so workspace admins
can change the limit per field.
3. Default behavior is preserved: if no max is configured, the existing
default (10) is used.


## **Fixes Issue:** [#14740
](https://github.com/twentyhq/twenty/issues/14740)

## Manual Test Screenshot
<img width="383" height="451" alt="Screenshot 2025-10-08 002413"
src="https://github.com/user-attachments/assets/a7704af6-10ef-4d10-b8c9-a9eeca03bfd9"
/>


### Values in fields


https://github.com/user-attachments/assets/7f59c4f7-3aca-4f83-8c04-3d44988316e3


Let me know if any changes are needed

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-10-08 12:09:38 +00:00
Etienne f037e92dfa fix incorrect data in sample export (#14933)
fixes https://github.com/twentyhq/twenty/issues/14928
introduced by https://github.com/twentyhq/twenty/pull/14347
2025-10-07 16:20:33 +00:00
ANIMESH DUTTA 9c8e0f628e Redirect to select option creation when no result (#14460)
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>
2025-10-07 14:39:48 +00:00