Commit Graph

58 Commits

Author SHA1 Message Date
Weiko c0ed246a03 Add is unique in migration v2 + refactor inferDeletionFromMissingEntities (#15070)
## Goal
- inferDeletionFromMissingEntities is now a map instead of a single
bool, allowing us to parameterise it based on the entity we want to
compare
- Adding index creation/update when field isUnique is set to true and
index deletion when isUnique is false (for now)

close https://github.com/twentyhq/core-team-issues/issues/1346
2025-10-15 16:08:13 +02:00
Paul Rastoin 7d747c9876 [REQUIRES_CACHE_FLUSH][GQL_VIEW_GROUP_API_BREAKING_CHANGE] ViewGroup in v2 (#15052)
# Introduction
Adding view-group to core engine v2
Following https://github.com/twentyhq/twenty/pull/15010 ( same pattern )

## What's done
- Created flat-view-group
- flat view group runner
- flat view group builder
- create view group service v2 and input transpilers
- refactor the existing view group resolver to fix standard (
BREAKING_CHANGE on graphql api update especially ) REST stays the same
- refactored the front to consume the mutations autogenerated

close https://github.com/twentyhq/core-team-issues/issues/1665
2025-10-14 15:55:50 +02:00
Paul Rastoin 651ab184a7 [GQL_VIEW_FILTER_API_BREAKING_CHANGE][WHEN_RELEASED_REQUIRES_CACHE_FLUSH] ViewFilter migration to workspace migration v2 (#15010)
# Introduction
Migrating `viewFilter` to v2 in order to migrate later the field update
side effect on view to v2 too

## What's done
- Created flat-view-filter
- flat view filter runner
- flat view filter builder
- create view filter service v2 and input transpilers
- refactor the existing view filter resolver to fix standard (
BREAKING_CHANGE on graphql api update especially ) REST stays the same
- refactored the front to consume the mutations autogenerated

## New generic tools
### Compare two flat entity
Introducing a new util to compare two flat entity, it's strictly typed
and will be added to the generic builder in a following PR
This will ease flat entity addition as won't required to create a
specific abstraction for comparison
Generic builder will expect specific constant: properties to compare and
properties to stringify

### Transform flat entity for comparison
Forked and refactor the initial existing method for flat entity business
scope and type safety

## Coverage
Migrated existing integration tests to fit new contract API
This PR does not add strong coverage on validation exceptions
Deadlines are too short

close https://github.com/twentyhq/core-team-issues/issues/1666
2025-10-10 15:02:14 +02:00
Félix Malfait e577c2d746 Update user friendly errors for translations (#15000)
Force msg typing instead of string for user friendly errors
2025-10-09 18:17:32 +02:00
Paul Rastoin 59fbe35a8c Move view in metadata-modules/ and create atomic folder + module for each view entity (#14990)
# Introduction
Preparing view-filter and view-group introduction in v2 core engine
Moving view from `core-modules` to `metadata-modules`

## What happened

### Created dedicated modules for each view entity:
- ViewFieldModule
- ViewFilterModule
- ViewFilterGroupModule
- ViewGroupModule
- ViewSortModule

### Each module is now completely independent with its own:
- Controller
- Resolver
- Service
- Entity

### Created dedicated abstraction metadata module folder for:
- flat-view-field
- flat-view

### Dependencies 
- Eleminated circular dep on ViewModule to all others ones
- Granular import not importing the whole viewModule anymore everywhere


close https://github.com/twentyhq/core-team-issues/issues/1703
2025-10-09 15:18:15 +02:00
Guillim f60817a1e1 Morph many to one picker (#14155)
This PR follows the multiSelect PR merged previously. It will enable
morph relation Many to One to be handled from the table, using a
singleSelect picker

Main point : I decided to change the singleSelect API to take an array
of **objectMetadataName** instead of only one to deal with both our
usecases.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-10-07 17:25:11 +02:00
Weiko 0b60aa4249 Add custom routes to migration v2 (#14846)
## Context
Add routes to migration V2
- Resolvers
- Service v2
- Builder
- Validator
- Action runner

Next PR: Add to twenty-cli to sync routes with serverless
2025-10-03 00:20:21 +02:00
Paul Rastoin 170f6d27c5 Extract field metadata build out of object metadata build (#14763)
# Introduction

Extracting the legacy fields build and dispatch out of the object one to
follow the generic flat entity build, also update caches entries for
object

## Main tasks
- flat field map cache
- flat field builder
- refactored the dispatch matrix to return flat entity maps instead of
flat entity arrays
- orchestrator aggregator
- removing legacy code
- making universal identifier aka standardId of standard field for
custom object deterministically dynamic
- perfs debug logs for v2

## TODO
- [x] Refactor the generic entity builder to be dependency flat maps in
order to main foreign keys list in flat parent
- [x] Refactor the flat object metadata to contain the array of related
fields and avoid costy find object fields
- [ ] Improve the create field handler to handle multiple field at once
- [ ] Refactor the dispatch to embbed the comparison
- [ ] Improve perf by extracting from elements out of existing
- [ ] Fix the labelIdentifierId validators on object before field
creation ( integ tests are in failing mode )

## Debug logs snippet

```ts
[EntityBuilder fieldMetadata] matrix computation: 0.027ms
[EntityBuilder fieldMetadata] creation validation: 0.001ms
[EntityBuilder fieldMetadata] deletion validation: 0.293ms
[EntityBuilder fieldMetadata] update validation: 0.006ms
[EntityBuilder fieldMetadata] entity processing: 0.363ms
[EntityBuilder fieldMetadata] validateAndBuild: 0.455ms
[EntityBuilder index] matrix computation: 0.005ms
[EntityBuilder index] creation validation: 0.001ms
[EntityBuilder index] deletion validation: 0.146ms
[EntityBuilder index] update validation: 0.004ms
[EntityBuilder index] entity processing: 0.199ms
[EntityBuilder index] validateAndBuild: 0.228ms
[Runner] Initial cache retrieval: 0.549ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_index executeForWorkspaceSchema: 11.665ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_index executeForMetadata: 12.864ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_field executeForWorkspaceSchema: 1.476ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_field executeForMetadata: 6.816ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_field executeForWorkspaceSchema: 0.062ms
[BaseWorkspaceMigrationRunnerActionHandlerService] delete_field executeForMetadata: 0.889ms
[Runner] Transaction execution: 23.434ms
[Runner] Cache invalidation: 316.662ms
[Runner] Total execution: 340.767ms
```
As you can see cache invalidation is way to long, we could replace the
cache by the optimistic in the end
2025-10-02 16:07:34 +00:00
Marie 3927b36406 [View migration] Clean ViewFilterOperand (#14785)
In the BE we have stored filter operand as IS_EMPTY, IS_NOT_EMPTY, etc. 
For some reason in the FE we were manipulating IsEmpty, IsNotEmpty, etc.
(maybe because they were used before in Views before they were moved to
core)

So we were converting the operands in the FE from IS to Is
(convertViewFilterOperandFromCore) to read and manipulate viewFilters,
and then back to BE version to send mutations etc., from Is to IS
(convertViewFilterOperandToCore).
The migration is now over, so we can remove and simplify that code. 
(In the 1-5:migrate-views-to-core command we still do the migration from
Is format to IS format.)
2025-09-30 17:12:03 +02:00
Weiko 68b21d2942 Add db event trigger and cron trigger to migration v2 (#14772)
## Context
Add DB events triggers and Cron triggers to migration v2 builder/runner
(and adding corresponding services/resolvers)
2025-09-30 11:14:18 +02:00
Paul Rastoin 4fbdfb6abc Activate v2 default seed (#14660)
## Introduction
After enabling flag by default got following errors:
```ts
Test Suites: 48 failed, 1 skipped, 97 passed, 145 of 146 total
Tests:       499 failed, 1 skipped, 644 passed, 1144 total
Snapshots:   61 failed, 133 passed, 194 total
Time:        363.226 s
Ran all test suites.
```

## From
<img width="2952" height="1510" alt="image"
src="https://github.com/user-attachments/assets/7e3b20c6-2552-40a7-90bb-2d7b3002c895"
/>

## To
<img width="3134" height="1510" alt="image"
src="https://github.com/user-attachments/assets/4fc9ada4-3c14-4333-a1db-11daf87db8d6"
/>

There's a huge test bundle in the latest shard that we could split up

## Notes
- Set as failing morph relation field rename as for the moment we do not
handle relation field mutation
- fixed the object update and creation validation adding label
identifier field metadata id checks
- and more

Some integrations tests are still on the v1 ( they have before and after
all disabling and re-enabling the flat ) but mainly we now have more
coverage on the v2 than the v1.
Mainly related records, uniqueness have to be migrated the v2 and so
tests too
2025-09-26 16:05:09 +02:00
Weiko 188d66909d Add ServerlessFunction to migration v2 (#14698) 2025-09-25 14:05:01 +02:00
Paul Rastoin fbd3286792 Index v2 side effects (#14567)
# Introduction
Honestly this implem is a mess, discussing a potential side effect
handler with @weiko before the build and run that would handle each side
effect per entity and operation

Handling:
- [ ] unique index is generated when a field is updated with the
`isUnique`
- [x] an index is generated when a relation is created
- [x] search vector index creation on custom object creation
- [x] renaming a field metadata or an object should re-create all
related indexes which are composed by their namings
- [x] delete object should remove any related indexes
- [x] delete field should update related indexes ( if index ends up
empty it should be removed )
- [ ] on object renaming that contains morph fields -> triggers update
field -> trigger index recompute
- [x] on update name renaming should recompute all related indexes

## TODO
- [x] Integration testing
- [ ] Refactor the index maps cache to be storing a
`idsByObjectMetadataId`
- [x] Refactor deterministic name to use order sorting
- [x] Remove flat index from flat object

## What's next

Will handle morph indexes in a new dedicated PR for the moment will
stick to this
Same for the cache improvement and uniqueness
2025-09-23 10:57:11 +02:00
Paul Rastoin 2d8669ae71 Index v2 runner (#14537)
## Introduction
https://github.com/twentyhq/twenty/pull/14363
In this PR we're creating builder and runner for index metadata
Removing its previous integration within object builder

## Next:
- implem index impact on field and object metadata api
- Add integration testing coverage add integration test on index
- Implement uniqueness toggle in field metadata api
- add integration test on uniqueness

related to https://github.com/twentyhq/core-team-issues/issues/1344
2025-09-17 13:02:43 +00:00
Paul Rastoin 579f704baa Plugging + improving the new orchestrator (#14430)
# Introduction
Initially this PR was about introducing integration coverage for view
field v2 tests
But feature itself wasn't finished, so ended up in a TDD style
devlopment

## The new orchestrator
Orchestrator will organize each flat entity diffing inferring either
validation errors or actions sequentially.
A new builder has been introduced when extended requires to define flat
entity validation utils and action generation for `delete` `update`
`create` operations. It's highly typed using generics

## View field integration testing
Introduce coverage on failing basic tests cases for view field
operations, successfull create is also covered. We could still add more
coverage, will be done later in following PRs

## Remaining tasks for upcoming PRs:
- [ ] rename builder methods names to add generate action in their names
- [x] refactor view validation to handle field and view uniqueness index
combination
- [ ] implem strict update validator on view and view field
- [ ] dynamic cache invalidation post run
- [ ] Add coverage to successful and failing view field operations
- [ ] error formatting summary computation
- [ ] extract types out of the workspace entity builder

## Some vision
Currently flat field metadata maps is nested in the flat object metadata
maps, making its build nested too. ( not extending the new generic
builder )
We will refactor this part for both to be stored extra flat such as the
other existing flat entities.
It will require a small refactor to the generic builder that will not
only have impact on the currently built flat entity optimistic cache but
to an other one ( for example when building a create object action it
will also have an impact flat field maps )
2025-09-15 14:32:57 +02:00
Paul Rastoin 9e81618773 Refactor morph field name and morph data loader (#14299)
# Introduction
Storing morph relation field names directly in database, using morphId
to aggregate them
Removing dynamic morph field metadata computation in schemas and data
loader

Will add integration tests on morph data loader entry

closes https://github.com/twentyhq/core-team-issues/issues/1425 
closes https://github.com/twentyhq/core-team-issues/issues/1424 
closes https://github.com/twentyhq/core-team-issues/issues/1423
2025-09-08 17:20:18 +02:00
Charles Bochet 286682c197 DevXP improvements on new views (#14330) 2025-09-05 18:49:20 +02:00
Paul Rastoin 17c646f9d8 Fix views integration tests (#14317)
Following https://github.com/twentyhq/twenty/pull/14202
2025-09-05 10:16:40 +00:00
Vinay Arvind Badgujar 5824637d1a fix - newly added object not visible in left menu (#14202)
resolves #14190 

added refreshCoreViews() call after object creation to immediately
update core views state, ensuring new objects appear in the navigation
drawer without requiring a refresh

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: prastoin <paul@twenty.com>
2025-09-05 10:43:03 +02:00
Paul Rastoin 6522498df0 Failing morph relation creation v2 integration testing & fixes (#14253)
# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/1408
2025-09-03 12:14:43 +02:00
Paul Rastoin 6d6ee939cf Morph relation field v2 fixes (#14216)
Fixes, depending on the contextual current operation in order to
retrieve relation target and all morph related fields to be delete:
- DELETE Field,
- DELETE Object, 
- UPDATE Field, that affects all others related fields
2025-09-02 12:17:20 +00:00
Marie 0d5fedfb0a Fix user friendly message for non available object name (#14210)
Fixes https://github.com/twentyhq/twenty/issues/13577.

When naming or renaming an object, we are already checking that the name
was available compared to other existing objects.
But we also need to check that the relation fields that will be created
or updated are available as well: we create relation fields on
Attachment, Note, Favorite, Task and TimelineActivites, that bear the
name of the object. Thus, it is not possible to create an object that
has the same name as one of the fields on Attachment, Note etc: name,
createdAt, ... are not valid names.
2025-09-01 16:35:40 +00:00
Paul Rastoin 59d90bedaa Integration testing v2 enum field types fail and success path (#14010)
# Introduction
Migrating and improving performances of field enum integrations tests
success and failing tests cases to be using the new v2 api

## Discovered issue
When deleting an object in v1 it will leave related enums until the
object is re-created
Something not done anymore within the create in v2 but in the delete
operation
We should implem an upgrade command to remove such relicas

## Bugs
- Update/create default value multi select runner wrong sql query -> FIX
- Update default value multi select regression, we should allow option
without an id to be inserted -> FIX
- default value compare dynamic json stringify convertion or not in
compare tools for object and fields
2025-08-28 10:23:04 +00:00
Weiko 533d7fe49a Deprecate legacy core datasource token (#14096) 2025-08-27 20:09:54 +02:00
Raphaël Bosi 30c42345f0 Core views frontend (#13932)
Parallel code path to read and write core views when
IS_CORE_VIEW_ENABLED.

Migrated view key to an enum.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-08-20 19:04:58 +02:00
Etienne 6936993557 Unique fields - fixes (#13848)
- Enable update to unique for composite field with defaultValue
different from default defaultValue on subfield not included in unique
constraint
- Enable update to unique for standard field + Disable update to
non-unique for standard index
- Fix typo

Fixes https://github.com/twentyhq/core-team-issues/issues/1360
2025-08-13 08:40:46 +02:00
Guillim 63c8bb9530 morph backend CORE api (#13517)
# Morph Relation needs some work on the core API

Especially on the Morph types

<img width="682" height="394" alt="Screenshot 2025-07-31 at 12 19 40"
src="https://github.com/user-attachments/assets/8b185ae3-3fe7-4886-97b1-ec143bb1b0f4"
/>


## Focus Areas:
- GraphQL schema generation
- Query parsing and field selection
- Morph relation field support
- Input type definition preparation
2025-08-12 11:47:02 +02:00
Etienne 7ce96049b8 Unique field - add unique property creation/deletion on field (#13539)
Done : 
- add isUnique prop availability on gql update/create fieldMetadata
resolvers
- add unique index creation logic at update & creation
- add unique index deletion logic at update
- update unique index if field name updated
- edge cases : can't have default value and unique fields / standard
default value excluded from index (where clause) / can't have composite
unique fields / can't create unique fields on MORPH


closes https://github.com/twentyhq/core-team-issues/issues/1222
2025-08-08 17:42:50 +02:00
Félix Malfait 8b4b9ef8da Change type import rule (#13751)
Forcing "type" to be explicit, works best will rollup on the frontend to
exclude depdendencies
2025-08-08 01:27:05 +02:00
Raphaël Bosi 593b064448 Create resolvers and controllers for core views (#13624)
Created:
- Services
- Resolvers
- Controllers
- Tests for services
- Integration tests for GraphQL and Rest

Updated the Rest API playground

Added new feature flag `IS_CORE_VIEW_ENABLED`

Updated `viewFilter` `operand` and `view` `type` to be enums rather than
strings and generated migration file.

Closes https://github.com/twentyhq/core-team-issues/issues/1259

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-08-07 18:45:04 +02:00
Paul Rastoin 14537d74b4 FlatFieldMetadataType hashmap arch and enum validation (#13502)
# Introduction
- FlatFieldMetadataType validators hashmap
- Do not fail fast on validation but aggregate errors
- Implemented `enum` validation
- Plugged the new v2 dynamic call in the field metadata service v2

## What's next:
- Implem integration tests to make things run 🙃 
- migrate existing settings valdiation
- Finish the create object metadata service
- Handle update input transpilation and validation

## Open question
Should we implement, not covered validation ?, adding strictness now or
never.
This will be required by the import anw

## Discovered issue with cache
Currently the cache is not accurately typed, `fieldsById` map are not
storing any relations.
Which means the current transpilation tools are hitting undefined at
runtime
In the best of the world we will refactor the cache to be storing
`FlatObjectMetadata` and `FlatFieldMetadata` so we don't even have to
transpile them for validation and so on
But it would require to refactor the loaders that returns the cache to
the front on hit as FieldMetadataEntity, so we might land on a lighter
solution to rather add a new `getExistingFlatCache` that handles the
transpilation itself
About to do that in an other PR to be discussed with Coco
2025-07-31 14:54:39 +02:00
Guillim 1ea451c8be Morph Relations : deleteOneField (#13349)
This PR adapts teh deleteOneField to make sure morph relations can be
deleted, either
- from a relation type, 
- or from a morph relation type (which is the most obvious case).

This PR covers 
- the deletion of fieldMetadata 
- and the migrationof workspace schemas, by using the already existing
definition of relation migrations

This PR implements a new test suite: "Delete Object metadata with morph
relation" and completes the other test suites for FieldMetadata and
ObjectMetadata creation/deletion.

Last, we added a nitpick from @paul I forgot on a previous PR on
process-nested-realtion-v2

Fixes https://github.com/twentyhq/core-team-issues/issues/1197
2025-07-24 12:40:14 +00:00
Paul Rastoin 47b60bd49f Deprecate FieldMetadataInterface (#13264)
# Introduction

From the moment replaced the FieldMetadataInterface definition to:
```ts
import { FieldMetadataType } from 'twenty-shared/types';

import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';

export type FieldMetadataInterface<
  T extends FieldMetadataType = FieldMetadataType,
> = FieldMetadataEntity<T>;
```
After this PR merge will create a new one removing the type and
replacing it to `FieldMetadataEntity`.
Did not renamed it here to avoid conflicts on naming + type issues fixs
within the same PR

## Field metadata entity RELATION or MORPH
Relations fields cannot be null for those field metadata entity instance
anymore, but are never for the others see
`packages/twenty-server/src/engine/metadata-modules/field-metadata/types/field-metadata-entity-test.type.ts`
( introduced TypeScript tests )

## Concerns
- TS_VECTOR is the most at risk with the `generatedType` and
`asExpression` removal from interface

## What's next
- `FielMetadataInterface` removal and rename ( see introduction )
- Depcrecating `ObjectMetadataInterface`
- Refactor `FieldMetadataEntity` optional fiels to be nullable only
- TO DIG `never` occurences on settings, defaultValue etc
- Some interfaces will be replaced by the `FlatFieldMetadata` when
deprecating the current sync and comparators tools
2025-07-21 11:30:18 +02:00
Charles Bochet 191bbb9e12 Prevent field name conflicts (#13280)
Fixes https://github.com/twentyhq/twenty/issues/13184
2025-07-18 21:38:36 +02:00
Guillim 530a7dea86 Morph relation : migration builder (#13173)
This PR will create the migration to be run for the morph relations

- We created a dedicated util to generate the column name and refactored
a little the code in order to have less dependencies and a clearer devX
(updated the snapshot that changed because of this)
- Moved the `createMigrationActions` to its own util as well
- Created the `MorphRelationColumnActionFactory` based on the relation
one

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-07-17 11:39:45 +02:00
Paul Rastoin c5a74b8e92 Workspace migration v2 testing (#13136)
# Introduction
Introduced `EachTesting` pattern for the builder unit tests.
As always any suggestions are more than welcomed !


Still need to:
- [x] implem basic tests for field
- [x] create `get-flat-index-field-metadata.mock.ts`
- [x] Implement basic tests for index and index-fields
- [ ] Implem standard edges cases tests TDD style

## Misc
- was https://github.com/twentyhq/twenty/pull/13132 closed due to mess
to rebase on main
2025-07-15 16:08:50 +02:00
Guillim 1a81e43286 Moprh-integration-delete (#13165)
Intergartion test dedicated to the delete method
2025-07-15 11:16:19 +02:00
Jean-Baptiste Ronssin ff3f3d4661 fix(api): Allow deactivation of relation fields (#13202)
_(AI generated)_

### Summary

This PR fixes a validation bug in the GraphQL API that prevented
relation fields from being programmatically deactivated. The validation
was incorrectly triggering a "name cannot be changed" error even when
the update payload did not include a name, making it impossible to
disable the field.

Issue #13200 

### Problem

- The [updateOneField] mutation failed when trying to set `isActive:
false` on a `RELATION` field.
- The root cause was a validation check in
[FieldMetadataValidationService] that compared the incoming `name` with
the existing one. If the input `name` was `undefined`, the check
`undefined !== existingName` would incorrectly fail.
- This created a catch-22 where a field could not be deleted (because it
had to be deactivated first) and could not be deactivated (due to this
validation error).

### Solution

- The validation logic in [field-metadata-validation.service.ts] has
been updated to only check for a name change if a new name is
**explicitly provided** in the input
(`isDefined(fieldMetadataInput.name)`).
- This change correctly enforces the rule that relation field names
cannot be changed, while allowing other properties like `isActive` to be
updated without issue.

### How to Test

1.  Create a custom field of type `RELATION`.
2. Using the GraphQL API, call the [updateOneField] mutation with the
field's ID and the payload `{ "isActive": false }`.
3.  Verify that the mutation succeeds and the field is now inactive.
4.  Call the [deleteOneField] mutation to delete the field.
5.  Verify that the deletion is successful.

### Additional Changes

_to be deleted if not necessary_

- Added a new integration test
[successful-field-metadata-relation-update.integration-spec.ts] to cover
this specific use case and prevent future regressions. The existing test
for failing updates remains untouched and continues to pass.
2025-07-15 10:32:52 +02:00
Guillim bed2c640c5 relation-integration-tests (#13113) 2025-07-10 16:55:36 +02:00
Marie c13bc60dad Improve error handling (#13130)
In the BE we throw custom errors with precise error codes (e.g.
"LABEL_ALREADY_EXISTS") before catching them in filters and rethrowing
BaseGraphQLErrors (standard errors such as NotFoundError, UserInputError
etc.).
In the FE we were grouping sentries based on the error codes but we were
actually grouping by very broad codes such as "NOT_FOUND" or
"BAD_USER_INPUT", extracted from the BaseGraphQLErrors.

To fix that, we update the BaseGraphQLError constructor api to allow to
pass on the CustomError directly and retrieve from it the original code
and store it in existing property `subCode` that we will use in the FE
to send errors to sentry.
This new api also eases usage of `userFriendlyMessage` that is passed on
to the api response and therefore to the FE when CustomError is passed
on directly to the BaseGraphQLError constructor.
2025-07-09 17:13:44 +02:00
Charles Bochet 867619247f Fix relation field unknown target object (#13129)
Fixes https://github.com/twentyhq/twenty/issues/12867

Issue:
when you have a variable `toto` which is: `Record<string, MyType>` and
you do toto['xxx'], this will be typed as `MyType` instead of `MyType |
undefined`

Solutions:
- activate `noUncheckedIndexedAccess` check in tsconfig, this is the
preferred solution but will take time to get there (this raises 600+
errors)
- use a Map: cf https://github.com/twentyhq/twenty/pull/13125/files
- set the type to Partial<Record<string, MyType>>. Drawback is that when
you do Object.values(toto), you'll get `Array<MyType | undefined>`.
Hence why we have to filter these behind


<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/d0a0bfed-c441-4e53-84c2-2da98ccbcf50"
/>
2025-07-09 15:43:11 +02:00
Charles Bochet 39f6f3c4bb Prevent relation update from settings (#13099)
## 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)
2025-07-08 21:03:38 +02:00
Guillim a5deddaffd fieldmetadatatype + featurelfag creation (#13021)
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-07-08 12:23:28 +02:00
Marie 288f0919db Define server error messages to display in FE from the server (#12973)
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.`
2025-07-03 12:42:10 +00:00
Marie 540f3ffd67 Fix phone deletion (#12821)
Fixes https://github.com/twentyhq/core-team-issues/issues/1124
2025-06-24 13:12:40 +00:00
Paul Rastoin e1393c4887 Transform record phone field metadata (#12706)
# Introduction
close https://github.com/twentyhq/twenty/issues/12343

Adding a transform step for any field phone in order to infer country
code and calling code from the number if they're provided

## Edges cases
```ts
RecordTransformerExceptionCode.INVALID_PHONE_NUMBER:
RecordTransformerExceptionCode.INVALID_PHONE_COUNTRY_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_COUNTRY_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_CALLING_CODE:
RecordTransformerExceptionCode.CONFLICTING_PHONE_CALLING_CODE_AND_COUNTRY_CODE:
RecordTransformerExceptionCode.INVALID_PHONE_CALLING_CODE:
RecordTransformerExceptionCode.INVALID_URL:
```

## Coverage
Note: Will handle REST api integration testing pivot and UPDATE
operation later in the afternoon, critical bug appeared that I prefer
handling before improving this PR coverage, also would be too many
updates
Note2: Haven't fuzzed all of the string inputs, would seem overkill for
such a use case, to be debated
```ts
 PASS  test/integration/metadata/suites/field-metadata/phone/create-one-field-metadata-phone.integration-spec.ts (23.609 s)
  Phone field metadata tests suite
    ✓ It should succeed create primary phone field (1397 ms)
    ✓ It should succeed create primary phone field with number and other information (930 ms)
    ✓ It should succeed create primary phone field with full international format and other information (893 ms)
    ✓ It should succeed create primary phone field with full international and infer other information from it but not the countryCode as its shared (825 ms)
    ✓ It should succeed create primary phone field with full international and infer other information from it (818 ms)
    ✓ It should succeed create primary phone field with empty payload (827 ms)
    ✓ It should succeed create additional phone field with number and other information (894 ms)
    ✓ It should succeed create additional phone field with full international format and other information (1024 ms)
    ✓ It should succeed create additional phone field with full international and infer other information from it but not the countryCode as its shared (808 ms)
    ✓ It should succeed create additional phone field with full international and infer other information from it (751 ms)
    ✓ It should succeed create additional phone field with empty payload (739 ms)
    ✓ It should fail to create primary phone field without country or calling code at all (776 ms)
    ✓ It should fail to create primary phone field with invalid country code (782 ms)
    ✓ It should fail to create primary phone field with invalid calling code (858 ms)
    ✓ It should fail to create primary phone field with conflicting country code and calling code (872 ms)
    ✓ It should fail to create primary phone field with invalid phone number format (1489 ms)
    ✓ It should fail to create primary phone field with conflicting phone number country code (1425 ms)
    ✓ It should fail to create primary phone field with conflicting phone number calling code (1553 ms)
    ✓ It should fail to create primary phone field without country or calling code at all (814 ms)
    ✓ It should fail to create primary phone field with invalid country code (813 ms)
    ✓ It should fail to create primary phone field with invalid calling code (742 ms)
    ✓ It should fail to create primary phone field with conflicting country code and calling code (783 ms)
    ✓ It should fail to create primary phone field with invalid phone number format (731 ms)
    ✓ It should fail to create primary phone field with conflicting phone number country code (947 ms)
    ✓ It should fail to create primary phone field with conflicting phone number calling code (822 ms)

Test Suites: 1 passed, 1 total
Tests:       25 passed, 25 total
Snapshots:   14 passed, 14 total
Time:        23.627 s
```
2025-06-19 16:39:58 +02:00
Guillim 61237916fd Fix Integration test (#12470)
# Integration test failing

- fix the local run by renaming folder in the jest configuration.
Otherwise "clickhouse" tests were failing

- falsy test introduced 2 days ago in
https://github.com/twentyhq/twenty/pull/12271/files
2025-06-05 19:57:53 +02:00
Abdul Rahman eb7556e333 Fix: multi-select default values validation (#12271)
https://github.com/user-attachments/assets/3bea63cc-b098-4252-8787-fc6263f01e8d


Closes #12277

---------

Co-authored-by: prastoin <paul@twenty.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-06-03 15:01:58 +02:00
Paul Rastoin 97d4ec96af Fix view filter update and deletion propagation (#12082)
# Introduction

Diff description: ~500 tests and +500 additions

close https://github.com/twentyhq/core-team-issues/issues/731

## What has been done here
In a nutshell on a field metadata type ( `SELECT MULTI_SELECT` ) update,
we will be browsing all `ViewFilters` in a post hook searching for some
referencing related updated `fieldMetadata` select. In order to update
or delete the `viewFilter` depending on the associated mutations.

## How to test:
- Add FieldMetadata `SELECT | MULTI_SELECT` to an existing or a new
`objectMetadata`
- Create a filtered view on created `fieldMetadata` with any options you
would like
- Remove some options ( in the best of the world some that are selected
by the filter ) from the `fieldMetadata` settings page
- Go back to the filtered view, removed or updated options should have
been hydrated in the `displayValue` and the filtered data should make
sense

## All filtered options are deleted edge case
If an update implies that a viewFilter does not have any existing
related options anymore, then we remove the viewFilter

## Testing
```sh 
PASS  test/integration/metadata/suites/field-metadata/update-one-field-metadata-related-record.integration-spec.ts (27 s)
  update-one-field-metadata-related-record
    SELECT
      ✓ should delete related view filter if all select field options got deleted (2799 ms)
      ✓ should update related multi selected options view filter (1244 ms)
      ✓ should update related solo selected option view filter (1235 ms)
      ✓ should handle partial deletion of selected options in view filter (1210 ms)
      ✓ should handle reordering of options while maintaining view filter values (1487 ms)
      ✓ should handle no changes update of options while maintaining existing view filter values (1174 ms)
      ✓ should handle adding new options while maintaining existing view filter (1174 ms)
      ✓ should update display value with options label if less than 3 options are selected (1249 ms)
      ✓ should throw error if view filter value is not a stringified JSON array (1300 ms)
    MULTI_SELECT
      ✓ should delete related view filter if all select field options got deleted (1127 ms)
      ✓ should update related multi selected options view filter (1215 ms)
      ✓ should update related solo selected option view filter (1404 ms)
      ✓ should handle partial deletion of selected options in view filter (1936 ms)
      ✓ should handle reordering of options while maintaining view filter values (1261 ms)
      ✓ should handle no changes update of options while maintaining existing view filter values (1831 ms)
      ✓ should handle adding new options while maintaining existing view filter (1610 ms)
      ✓ should update display value with options label if less than 3 options are selected (1889 ms)
      ✓ should throw error if view filter value is not a stringified JSON array (1365 ms)

Test Suites: 1 passed, 1 total
Tests:       18 passed, 18 total
Snapshots:   18 passed, 18 total
Time:        27.039 s
```
## Out of scope
- We should handle ViewFilter validation when extracting its definition
from the metadata
https://github.com/twentyhq/core-team-issues/issues/1009

## Concerns
- Are we able through the api to update an RATING fieldMetadata ? ( if
yes than that's an issue and we should handle RATING the same way than
for SELECT and MULTI_SELECT )
- It's not possible to group a view from a MULTI_SELECT field

The above points create a double nor a triple "lecture" to the post hook
effect:
- ViewGroup -> only SELECT
- VIewFilter -> only SELECT || MULTI_SELECT
- Rating nothing
I think we should determine the scope of all of that

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-28 10:22:28 +00:00
Paul Rastoin 45c89a46d6 FieldMetadata ENUM CREATE UPDATE server validation and integration tests (#12121)
# Introduction

Big diff a lot of tests and snapshots ( real diff < 500+ )

close https://github.com/twentyhq/twenty/issues/12117
close https://github.com/twentyhq/twenty/issues/12133

## What has been done here
Implemented a strong integration coverage on both fieldmetadata`SELECT`
`UPDATE` and `CREATE`.
Implemented server side validation for the options `value` `label` `id`
and collision issue with also `position`

We could improve:
- Position validation
- DefaultValue validation

## Update
```ts
 PASS  test/integration/metadata/suites/field-metadata/update-one-field-metadata-select.integration-spec.ts (41.054 s)
  Field metadata select update tests group
    ✓ Update should succeed with provided option id (2565 ms)
    ✓ Update should succeed with valid default value (1469 ms)
    ✓ Update should succeed with various options id (1257 ms)
    ✓ Update should succeed without option id (1286 ms)
    ✓ Update should trim option values (1366 ms)
    ✓ Update should succeed with default value and no options (1122 ms)
    ✓ Update should fail with unknown default value and no options (1075 ms)
    ✓ Update should fail with only white spaces id (1195 ms)
    ✓ Update should fail with empty string id (1058 ms)
    ✓ Update should fail with null id (1066 ms)
    ✓ Update should fail with not a string id (1098 ms)
    ✓ Update should fail with too long id (1373 ms)
    ✓ Update should fail with only white spaces label (1034 ms)
    ✓ Update should fail with empty string label (1057 ms)
    ✓ Update should fail with null label (1100 ms)
    ✓ Update should fail with not a string label (1144 ms)
    ✓ Update should fail with too long label (1273 ms)
    ✓ Update should fail with only white spaces value (1385 ms)
    ✓ Update should fail with empty string value (1035 ms)
    ✓ Update should fail with null value (1068 ms)
    ✓ Update should fail with not a string value (1021 ms)
    ✓ Update should fail with too long value (1134 ms)
    ✓ Update should fail with invalid option id (1137 ms)
    ✓ Update should fail with empty options (1238 ms)
    ✓ Update should fail with invalid option value format (1104 ms)
    ✓ Update should fail with comma in option label (1004 ms)
    ✓ Update should fail with duplicated option values (1015 ms)
    ✓ Update should fail with duplicated option ids (1079 ms)
    ✓ Update should fail with duplicated option positions (1266 ms)
    ✓ Update should fail with duplicated trimmed option values (1220 ms)
    ✓ Update should fail with undefined option label (1029 ms)
    ✓ Update should fail with an invalid default value (1142 ms)
    ✓ Update should fail with an unknown default value (1081 ms)
    ✓ Update should fail with undefined option value (1086 ms)

Test Suites: 1 passed, 1 total
Tests:       34 passed, 34 total
Snapshots:   28 passed, 28 total
Time:        41.079 s
```


## Create
```ts
 PASS  test/integration/metadata/suites/field-metadata/create-one-field-metadata-select.integration-spec.ts (38.292 s)
  Field metadata select creation tests group
    ✓ Create should succeed with provided option id (2096 ms)
    ✓ Create should succeed with valid default value (1316 ms)
    ✓ Create should succeed with various options id (1113 ms)
    ✓ Create should succeed without option id (1378 ms)
    ✓ Create should trim option values (1296 ms)
    ✓ Create should fail with only white spaces id (1000 ms)
    ✓ Create should fail with empty string id (1325 ms)
    ✓ Create should fail with null id (1060 ms)
    ✓ Create should fail with not a string id (1142 ms)
    ✓ Create should fail with too long id (1321 ms)
    ✓ Create should fail with only white spaces label (999 ms)
    ✓ Create should fail with empty string label (1163 ms)
    ✓ Create should fail with null label (1198 ms)
    ✓ Create should fail with not a string label (1678 ms)
    ✓ Create should fail with too long label (1527 ms)
    ✓ Create should fail with only white spaces value (1200 ms)
    ✓ Create should fail with empty string value (1102 ms)
    ✓ Create should fail with null value (1037 ms)
    ✓ Create should fail with not a string value (1462 ms)
    ✓ Create should fail with too long value (896 ms)
    ✓ Create should fail with invalid option id (997 ms)
    ✓ Create should fail with empty options (1058 ms)
    ✓ Create should fail with invalid option value format (1190 ms)
    ✓ Create should fail with comma in option label (1142 ms)
    ✓ Create should fail with duplicated option values (872 ms)
    ✓ Create should fail with duplicated option ids (860 ms)
    ✓ Create should fail with duplicated option positions (1002 ms)
    ✓ Create should fail with duplicated trimmed option values (1336 ms)
    ✓ Create should fail with undefined option label (754 ms)
    ✓ Create should fail with an invalid default value (696 ms)
    ✓ Create should fail with an unknown default value (678 ms)
    ✓ Create should fail with undefined option value (699 ms)
    ✓ Create should fail with null options (720 ms)
    ✓ Create should fail with undefined options (686 ms)

Test Suites: 1 passed, 1 total
Tests:       34 passed, 34 total
Snapshots:   29 passed, 29 total
Time:        38.314 s
```

## Conclusion
As always any suggestions are welcomed ! Please let me know


## Discussion about validation governance
### Front
Front side will be dealing with zod validations schema that he will
handle and maintain by himself

### Back validation instances
- Validation hold through DTO declarations ( run by yoga through the
resolvers )
- Server programmatic validation and exceptions handling ( run through
the services )

For this refactor/fix we decided to stick to the current implementation
only touching the `Server programmatic validation and exceptions
handling` we will handle validation centralization when we will onboard
the `nestjs-query` deprecation/integration refactor.

### Vision
In the best of the world we could think of an intermediary model that
will handle and take responsibility of the validation decorators that
would be run programmatically through the service, Yoga would still
consume it ? then we would need to have enough grain in the service to
know the input has already validated

## Notes
Introduced zod back side in order to handle very atomic and primitive
validation
2025-05-22 17:58:59 +02:00