Commit Graph

1145 Commits

Author SHA1 Message Date
d73dc1a728 Create form field number (#8634)
- Refactor VariableTagInput to have a reusable low-level TipTap editor
- Create three primitive form fields:
  - Text
  - Number
  - Boolean

## Notes

- We should automatically recognize the placeholder to use for every
FormFieldInput, as it's done for FieldInputs.

## Design decisions

Our main challenge was for variables and inputs to be able to
communicate between each other. We chose an API that adds some
duplication but remains simple and doesn't rely on "hacks" to work.
Common styles are centralized.

## Demo

"Workflow" mode with variables:

![CleanShot 2024-11-26 at 10 43
25@2x](https://github.com/user-attachments/assets/cc17098a-ca27-4f97-b86a-bf88593e53db)

FormFieldInput mode, without variables:

![CleanShot 2024-11-26 at 10 44
26@2x](https://github.com/user-attachments/assets/fec07c36-5944-4a1d-a863-516fd77c8f55)

Behavior difference between fields that can contain variables and static
content, and inputs that can have either a variable value or a static
value:

![CleanShot 2024-11-26 at 10 47
13@2x](https://github.com/user-attachments/assets/1e562cd8-c362-46d0-b438-481215159da9)
2024-11-28 17:03:24 +00:00
75f5afb968 Rename enum types when tables are renamed (#8794)
## Context
Enum are named after this pattern
`${schema}_${tableName}_${columnName}_enum` however now that we allowed
table name update, we need to make sure their enums are renamed as well.
2024-11-28 15:39:20 +01:00
e96ad9a1f2 Admin panel init (#8742)
WIP
Related issues - 
#7090 
#8547 
Master issue - 
#4499

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-28 13:43:11 +01:00
c9fd194695 Fix index renaming (#8771)
Fixes https://github.com/twentyhq/twenty/issues/8760

## Context
Index names are based on table names and column names, which means
renaming an object (or a field) should also trigger a recompute of index
names. As of today it raises a bug where you can't create an object with
a name that was previously used.

I also took the occasion to refactor a bit the part where we create and
update (after renaming) relations. Basically the only relations we want
to affect are standard relations so I've aligned the logic with
sync-metadata which uses standardId as a source of truth to simplify the
code.

Note: We don't create index for custom relations
Next step should be to do that and update that code to update the index
name as well. Also note that we need to update the sync-metadata logic
for that as well
2024-11-28 10:21:03 +01:00
0d6a6ec678 8764 incorrect email sorting (#8768)
Closes #8764
2024-11-27 10:11:57 +01:00
12467d67c8 Remove pg-boss from doc and .env.example (#8766)
Remove pg-boss from doc and .env.example
2024-11-26 17:10:05 +01:00
eb39288583 feat(server): allow to use ssl on server (#8722) 2024-11-26 15:30:51 +00:00
08f163592b Gmail error handling fixes (#8732)
Gmail error handling fixes
2024-11-26 11:22:03 +01:00
182f9b12da Fix labelIdentifierFieldMetadata creation for custom objects (#8729) 2024-11-26 11:19:19 +01:00
88e63262cd Set missing labelIdentifier to custom objects (#8750)
## Context
Following https://github.com/twentyhq/twenty/pull/8729

This command backfills missing labelIdentifier for custom objects
2024-11-26 11:03:27 +01:00
4c413d4802 Fix custom object renaming (#8746)
Currently when renaming an object, we execute
```
await this.fieldMetadataRepository
                    .findOneByOrFail({
                      name: existingObjectMetadata.nameSingular,
                      label: existingObjectMetadata.labelSingular,
                      objectMetadataId: relatedObject.id,
                      workspaceId: workspaceId,
                    })
```
to find the standard relation fields. 
This would throw an error if the label solely was update beforehand
without updating the name too: in that case we will not have migrated
the label of the standard relation fields (which is maybe a mistake?
@Weiko wdyt?).
Let's remove it.
2024-11-26 11:01:12 +01:00
64b8fd544c Fix mutations with camelCase table names (#8740)
## Context
Some mutations are not working properly, workspaceMember soft deletion
for example. workspaceMember being a camelCase table name, it's probably
not propagated properly to pgql (which needs double quote for the table
name to keep it as camelCase)

I didn't have time to dig too much but if the `where` is before
`softDelete`, the query is `WHERE workspaceMember.id = $1` while if it's
after, the query becomes `WHERE id = $1`.
Probably due to the fact that once you call delete/softDelete/update,
the standard builder (SelectQueryBuilder) becomes a
DeleteQueryBuilder/etc... and filters are not handled the same way.
2024-11-26 10:47:13 +01:00
a16b0d233e add delete view fields without views command (#8728)
## Context
We recently added a command to ensure uniqueness on the viewId column in
the viewField table. This created some issues for some old workspaces
that had viewFields with an empty viewId.
This command should get rid of those and set the column as non-nullable.
Also updating the onDelete action accordingly and set one missing for
FavoriteFolder
2024-11-26 10:40:17 +01:00
2e75fae3ad Allow standard field default value and settings editing (#7104) (#8559)
Co-authored-by: Marie Stoppa <marie.stoppa@essec.edu>
2024-11-26 10:03:48 +01:00
7bde2006c5 Add integration tests for /metadata + fix relation deletion (#8706)
In this PR

1. Add integration tests for /metadata (master issue:
https://github.com/twentyhq/twenty/issues/8719)
2. Fix relation deletion: index on "from" object was not deleted,
impeding creation of a new relation between the same two objects A and B
after relation between A and B was deleted
2024-11-26 10:00:36 +01:00
08852dd1b1 Fix enumMigration not working on long fieldNames (#8708)
## Issue

Some users were facing issues while updating SELECT or MULTISELECT
options:

```
Error executing migration QueryFailedError: column "undefined" does not exist
    at PostgresQueryRunner.query (/app/node_modules/typeorm/driver/postgres/PostgresQueryRunner.js:219:19)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async WorkspaceMigrationEnumService.migrateEnumValues (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.js:101:13)
    at async WorkspaceMigrationEnumService.alterEnum (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/services/workspace-migration-enum.service.js:54:9)
    at async WorkspaceMigrationRunnerService.alterColumn (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:254:13)
    at async WorkspaceMigrationRunnerService.handleColumnChanges (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:202:21)
    at async WorkspaceMigrationRunnerService.handleTableChanges (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:94:25)
    at async WorkspaceMigrationRunnerService.executeMigrationFromPendingMigrations (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.service.js:60:17)
    at async WorkspaceExecutePendingMigrationsCommand.run (/app/packages/twenty-server/dist/src/engine/workspace-manager/workspace-migration-runner/commands/workspace-execute-pending-migrations.command.js:24:9)
    at async Command.<anonymous> (/app/node_modules/nest-commander/src/command-runner.service.js:162:24) {
  query: '\n' +
    '        UPDATE "workspace_7i7bwawp7keh3gel1g69jropc"."_funnelInProductsRu"\n' +
    '        SET "reasonForStageTransition" = undefined\n' +
    "        WHERE id='2af8db61-5f75-46de-8b1a-97e312937e06'\n" +
    '      ',
  parameters: undefined,
  driverError: error: column "undefined" does not exist
```

## Root cause

Internally, while migrating enum values, we are doing:
```
const values = await queryRunner.query(
      `SELECT id, "${oldColumnName}" FROM "${schemaName}"."${tableName}"`,
    );

 let val = value[oldColumnName];
```

oldColumnName being: `${columnDefinition.columnName}_old_${v4()}`;

However, TypeORM only supports 63 bits identifiers:
https://github.com/typeorm/typeorm/issues/3118, but silently truncate
the identifer so if oldColumnName gets larger than 63 characters,
`value[oldColumnName]` is undefined.

## Fix

We only need a temporary and unique temporary name, no need to take into
account the previous columnName here
2024-11-24 18:40:23 +01:00
96b5d01ff5 Fix mutations with custom objects (#8688) 2024-11-22 17:54:50 +01:00
4d8445a34a refactor(workspaces): Rename SEED_TWENTY_WORKSPACE_ID to SEED_ACME_WO… (#8611)
…RKSPACE_ID

The Pull Request modifies seed data by replacing
SEED_TWENTY_WORKSPACE_ID with SEED_ACME_WORKSPACE_ID across several
files.
- Updated SEED_TWENTY_WORKSPACE_ID to SEED_ACME_WORKSPACE_ID.
- Modified relevant import paths and seeds involving workspace data.
- Changes affect seeding processes for workspace members, user
workspaces, and general workspace details.
2024-11-22 16:03:18 +01:00
35f2d7a004 Add entitlement table and sso stripe feature (#8608)
**TLDR**


Added Billing Entitlement table, based on stripe
customer.ActiveEntitlements webhook event. In this table it has a key
value pair with each key being the stripe feature lookup key and the
value a boolean. We use this table in order to see if SSO or other
feaures are enabled by workspace.

**In order to test: twenty-server**


Billing:

- Set IS_BILLING_ENABLED to true
- Add your BILLING_STRIPE_SECRET and BILLING_STRIPE_API_KEY
- Add your BILLING_STRIPE_BASE_PLAN_PRODUCT_ID (use the one in testMode
> Base Plan)

Auth:

- Set AUTH_SSO_ENABLED to true
- Set your ACCESS_TOKEN_SECRET, LOGIN_TOKEN_SECRET, REFRESH_TOKEN_SECRET
and FILE_TOKEN_SECRET
- Set IS_SSO_ENABLED feature flag to true

Stripe Webhook: 

- Authenticate with your account in the stripe CLI
- Run the command: stripe listen --forward-to
http://localhost:3000/billing/webhooks

Migration:

- npx nx typeorm -- migration:run -d
src/database/typeorm/core/core.datasource.ts

**In order to test: twenty site**

- Buy a subscription (you can use the card 4242...42 with expiration
date later in the future)
- Go to SSO and create an OICD subscription
- Change the value in the entitlement table in order to put it in false
- An error should occur saying that the current workspace has no
entitlement

**Considerations**

The data from the Entitlement table is updated based on the stripe
webhook responses, and we use the customerActiveEntitlemet response to
update the info on the table, however this event doesnt have the
metadata containing the workspaceId. Because we cannot control at wich
order the webhook send events, we force a server error if the
entitlements are updated before the BillingSubscription. Stripe resends
the event based on a exponential backoff (for more info see
https://docs.stripe.com/webhooks#retries ) because we are in test mode
Stripe retries three times over a few hours. So if the
BillingEntitlement is not updated it is completely normal and it will be
updated when stripe resends the event.

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-22 15:32:48 +01:00
a41e563b9c Bump 0.34.0-canary (#8675) 2024-11-22 11:53:33 +01:00
04c359a5dc Fix record creation (#8664)
## Context
Now that each operation has its own resolver, we need to make sure they
all map to query arg getters. CreateOne was not properly mapped to the
position getter which made record creation fail because "position:
first" was not properly converted to a float.
Also fixing queries with custom object where we were wrongly using the
table name instead of entity name
2024-11-21 22:53:22 +01:00
1c04b2b0b7 [Flexible-schema] Refactor gql query runner to emit api event before processing to gql types (#8596)
Fixes https://github.com/twentyhq/twenty/issues/8300

## Context
API events were created too late and were already formatted as Gql
responses (including nesting with edges/node/type + formatting that
should not exist in an event payload). This PR moves the emit logic to
the resolver where we actually do the DB query
Note: Also added RESTORED events
2024-11-21 18:11:28 +01:00
52df5301a8 Enforce unique constraints for 0.33 (#8645)
## Context
- Fixing folder structure where 0.33 was inside 0.32.
- Updating the command so it runs enforce uniqueness on all tables
- Updating workspaces entities so the sync metadata adds the index
2024-11-21 17:39:26 +01:00
39373b4a28 8643 fix sentry error (#8644)
- fixes missing data in event payload when adding a new workspaceMember
- add strong typing to database event emitters
2024-11-21 16:09:36 +00:00
670c8a0b98 Refactor standard relations update at custom object renaming (#8638)
Refactoring update of standard relations when a custom object is
renamed, after observing occasional issues.

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-11-21 15:54:12 +01:00
24dbabcad7 Improve object metadata maps size (#8635)
## Context
The object metadata map is becoming quite large and its structure could
be simplified.
We are removing byNameSingular/byNamePlural keys, the former can be
retrieved through a new helper and the latter is not used in the code
base currently.
2024-11-21 11:49:19 +01:00
39076df922 Fix version status colored tag + fix trash icon hover (#8618)
As title

Closes 
- https://discord.com/channels/1130383047699738754/1306250586668404736
- https://discord.com/channels/1130383047699738754/1305934421529985055
2024-11-20 18:42:57 +01:00
ffbc9ca59c Set infinite ttl to all workspace cache keys (#8616)
## Context
We recently added an infinite ttl to metadata version however other keys
such as the object metadata map are also linked to the version so
keeping the version in cache without the rest breaks the app. I'm
editing all engine related keys with infinite ttl
2024-11-20 18:29:29 +01:00
2968085e73 Feat: revamp group by settings (#8503)
This PR fix #8202 that is revamping the `Options` settings for board and
table.

<img width="221" alt="Screenshot 2024-11-15 at 11 47 52 AM"
src="https://github.com/user-attachments/assets/0b143c95-810d-408b-b19e-c2678cd5653a">
<img width="214" alt="Screenshot 2024-11-15 at 11 47 59 AM"
src="https://github.com/user-attachments/assets/3468734a-8174-4e36-a8ee-08dad6c56227">
<img width="210" alt="Screenshot 2024-11-15 at 11 48 10 AM"
src="https://github.com/user-attachments/assets/300628f5-6645-4f1c-af8a-befce2714716">
<img width="212" alt="Screenshot 2024-11-15 at 11 48 37 AM"
src="https://github.com/user-attachments/assets/37a3db40-2146-45eb-bea4-44e1041f5bcf">
<img width="214" alt="Screenshot 2024-11-15 at 11 48 44 AM"
src="https://github.com/user-attachments/assets/42d2adcc-8f03-4f28-928b-d3c3d54d388a">
<img width="213" alt="Screenshot 2024-11-15 at 11 48 51 AM"
src="https://github.com/user-attachments/assets/90824568-b979-46a7-9841-ab8b9978e138">
<img width="211" alt="Screenshot 2024-11-15 at 11 49 00 AM"
src="https://github.com/user-attachments/assets/fa22446a-b1db-4d97-9a45-0778bf09ae3c">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2024-11-20 17:03:18 +01:00
0f7ebd3026 Fix wrong getAll keyValue method (#8603)
Fixes
https://github.com/twentyhq/twenty/issues/8520#issuecomment-2485913500

- Fix the getAll key-value pairs method, as it returns incorrect
results. The keyVar values were being affected by keyValues from other
workspaces.
- Fix missing Sync Email step for existing users joining existing
workspace
  
Before, this method returned keyValues that verifies:
- workspaceId = user.defaultWorkspaceId
- userId = user.id

This method now returns:
- userId = null && workspaceId = user.defaultWorkspaceId
- userId = user.id && workspaceId = null
- userId = user.id && workspaceId = user.defaultWorkspaceId

## Result


https://github.com/user-attachments/assets/b7563db6-a6a8-4e09-a0c6-c372d7e2b712
2024-11-20 15:41:42 +00:00
a744515303 Fix composite subfields format in OpenAPI schema (#8592)
Fixes https://github.com/twentyhq/twenty/issues/7262
## Before

![image](https://github.com/user-attachments/assets/54d188d3-5e72-4b8f-8ebe-b074f43c2685)


## After

![image](https://github.com/user-attachments/assets/316c69db-0e0b-43d9-a745-66d753682c4e)

![image](https://github.com/user-attachments/assets/22e39d16-e2f3-4aae-a491-f7f0765f557d)
2024-11-20 10:06:05 +01:00
271af37327 Fix relations in search queries (#8595)
We were not handling relations in the search resolver, which started
being an issue as we query those relations in the combinedSearch queries
(introduced here https://github.com/twentyhq/twenty/pull/8564); they
were nullified in the response payload. The response was overwriting
findManyRecords results in the cache as it contained the exact same
fields.

So we now
1. Handle relations in the search resolver
2. Stop querying relations in search queries (no use)
2024-11-19 19:07:57 +01:00
2f3c41620c Wrap Long text fields (textarea) (#8557)
Here we add the option for Text inputs to be wrapped, and to select on
how many lines text should be displayed.

Fix #7552

---------

Co-authored-by: guillim <guillaume@twenty.com>
2024-11-18 17:36:19 +01:00
83b5eb69b0 feat(env-vars): Add warning validation decorator (#8555)
Introduced a custom decorator 'WarningIf' to log warnings for specific
environment variable conditions. Implemented this for
SESSION_STORE_SECRET to ensure users change it from the default value.
2024-11-18 17:04:10 +01:00
0125d58ba8 Favorite folders (#7998)
closes - #5755

---------

Co-authored-by: martmull <martmull@hotmail.fr>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2024-11-18 15:22:19 +01:00
8b8b9fe55b Add "type" to reserved keywords in object metadata validation (#8548)
This PR adds "type" to the reserved keywords list in
validate-object-metadata-input.util.ts. This prevents users from
creating objects with "type" as a key, which has caused issues in the
past .
issue solved #8543 

1.Updated the RESERVED_KEYWORDS array to include "type"

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-11-18 15:10:49 +01:00
ba847292b6 refactor: add default fallback for session store secret (#8553)
**Description:**
- Add default fallback for session store secret.
- Updated SESSION_STORE_SECRET validation to be optional and of type
string.
2024-11-18 14:29:19 +01:00
0f1cf0e4e9 Add composite fields to aggregation (#8518)
## Context
This PR introduces a first aggregation for a composite field

## Test
<img width="1074" alt="Screenshot 2024-11-15 at 15 37 05"
src="https://github.com/user-attachments/assets/db2563f9-26b7-421f-9431-48fc13bce49e">
2024-11-18 12:02:57 +01:00
badebc513f Fix multi select filtering (#5358) (#8452)
Allow filtering by multi-select fields.

<img width="1053" alt="Screenshot 2024-11-11 at 11 54 45"
src="https://github.com/user-attachments/assets/a79b2251-94e3-48f8-abda-e808103a6c39">

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-17 15:27:38 +01:00
ac1197afe1 Fix secondary links default value and types (#8532)
Fixes broken companies view
2024-11-17 15:18:02 +01:00
9b2853bb01 Fix variable dropdown (#8521)
- fixed dropdown width
- add icons
- handle composite fields
## After

![image](https://github.com/user-attachments/assets/b9ac585e-2a39-4ab2-8620-739f83272b9b)

![image](https://github.com/user-attachments/assets/d9f7eabb-5693-4c1c-b81c-45a901479042)

![image](https://github.com/user-attachments/assets/9edced28-8a04-4951-913d-3e5561d4fcbe)
2024-11-15 18:08:03 +00:00
54b28ff7ed Enable workflow testing + fix header (#8512)
- clean execution header
- enable test on workflows + add snack bar
- display snack bar error if workflow cannot be tested

Behaviour still need to be validated by @Bonapara 
<img width="880" alt="Capture d’écran 2024-11-15 à 12 16 36"
src="https://github.com/user-attachments/assets/1dab0c3b-157c-449f-aee7-4c8cf2e369a6">
<img width="880" alt="Capture d’écran 2024-11-15 à 12 16 48"
src="https://github.com/user-attachments/assets/16279611-0a58-4fe6-b117-0192714a6d5c">
2024-11-15 18:38:39 +01:00
77165a280e Refactored query result getter handlers to support recursivity (#8497)
The `QueryResultGettersFactory` that is called on every query return to
was called only on the first level of relations because recursivity
wasn't implemented.

In this PR I implement recursivity and add some typing for the possible
forms a GraphQL query field can take.

This PR will fix any issue we have with pictures that were losing their
token (here for person.avatarUrl)

Fixes https://github.com/twentyhq/twenty/issues/8425
Fixes https://github.com/twentyhq/twenty/issues/8498

---------

Co-authored-by: Weiko <corentin@twenty.com>
2024-11-15 15:34:58 +00:00
34a3a66451 Improve flaky storybook test (#8515)
I don't think that will solve the flaky test but at least it will
cleanup the error message to avoid confusion
2024-11-15 14:29:39 +01:00
4f99b8eea1 8495 workflow display relevant columns in workflow related tables (#8502)
## After
### Workflows

![image](https://github.com/user-attachments/assets/535e0ff5-1276-41b9-aa52-d66150cd85ae)
### WorkflowRuns

![image](https://github.com/user-attachments/assets/8a7e076b-53ec-4b72-97d8-41bd77ed59ac)
### WorkflowVersions

![image](https://github.com/user-attachments/assets/7d2566b2-e6ea-4a3a-8e88-0f6850203219)

## Change Created By into Executed By in workflowRuns

![image](https://github.com/user-attachments/assets/b90b7a07-a4bc-4bd2-b7f5-ab7d2ae6ee45)
2024-11-15 10:13:36 +00:00
a2a272fed4 Add crud actions (#8500)
Adding update / delete / find actions

Update and delete are not really different than creation.

Find uses the same logique as for graphql filters.
Expected formats are:

Filter
```
{
  "and": [
    {
      "name": {
        "eq": "salut"
      }
    },
    {
      "employees": {
        "eq": "0"
      }
    }
  ]
}
```

Order
`[ { "name": 'AscNullsFirst' } ]`
2024-11-15 10:10:00 +01:00
736635a94b Begin moving to postgres spilo + adding pgvector (#8309)
We will remove the `twenty-postgres` image that was used for local
development and only use `twenty-postgres-pilo` (which we use in prod),
bringing the development environment closer to prod and avoiding having
to maintain 2 images.


Instead of provisioning the super user after the db initialization, we
directly rely on the superuser provided by Spilo for simplicity. We also
introduce a change that tries to create the right database (`default` or
`test`) based on the context.
  

How to test:
```
docker build -t twentycrm/twenty-postgres-spilo:latest -f ./packages/twenty-docker/twenty-postgres-spilo/Dockerfile .
docker images --no-trunc | grep twenty-postgres-spilo
postgres-on-docker:
	docker run \
	--name twenty_pg \
	-e PGUSER_SUPERUSER=twenty \
	-e PGPASSWORD_SUPERUSER=twenty \
	-e ALLOW_NOSSL=true \
	-v twenty_db_data:/home/postgres/pgdata \
	-p 5432:5432 \
	REPLACE_WITH_IMAGE_ID
```
2024-11-15 09:38:30 +01:00
cfe3515aa6 Set cache metadata version to infinite TTL (#8507)
## Context
To avoid having a corrupt metadata version, we want to remove TTL for
that key.

## Test
<img width="592" alt="Screenshot 2024-11-15 at 00 02 05"
src="https://github.com/user-attachments/assets/9da0ae33-26a8-4e7b-82d0-dd691135a08f">
2024-11-15 00:05:42 +01:00
a799370483 Aggregated queries #1 (#8345)
First step of https://github.com/twentyhq/twenty/issues/6868

Adds min.., max.. queries for DATETIME fields
adds min.., max.., avg.., sum.. queries for NUMBER fields 

(count distinct operation and composite fields such as CURRENCY handling
will be dealt with in a future PR)

<img width="1422" alt="Capture d’écran 2024-11-06 à 15 48 46"
src="https://github.com/user-attachments/assets/4bcdece0-ad3e-4536-9720-fe4044a36719">

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Weiko <corentin@twenty.com>
2024-11-14 18:05:05 +01:00
51c54d4c5b validation on Select field (#8316)
fix #8204
I changed "API keys" to "API values".
Stopped inputting special characters in Select field option keys.

@lucasbordeau please check the changes and tell me if I need to do any
other changes. :)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2024-11-14 17:46:18 +01:00