Compare commits

..
245 Commits
Author SHA1 Message Date
Charles BochetandCharles Bochet 3e731da69c Fix docker setup (#12209)
For fresh install, we need the migrations to happen before the upgrade
command is triggered as the upgrade command is a NestJS command and the
app will try to load env variables from db
2025-05-22 11:32:26 +02:00
Paul RastoinandGitHub 8d105417ba Add forgotten 054 commands (#12193)
Wrongly named branch
2025-05-21 17:59:17 +02:00
Charles Bochet d38f448d05 Move fieldMetadata migration from metadata to core 2025-05-21 16:36:04 +02:00
Charles Bochet dc2d7f7c94 Fix upgrade command for 0.54 2025-05-21 16:25:39 +02:00
6c9d17eee7 i18n - translations (#12189)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-21 16:20:48 +02:00
martmullandGitHub 578f07374b 922 remove todos from 11809 after release (#12183)
- remove todos
- remove workflow-event-listener.workspace-entity.ts
2025-05-21 16:15:48 +02:00
Paul RastoinandGitHub 85a17a54b3 Do not upgrade if no migrate (#12187) 2025-05-21 16:01:03 +02:00
martmullandGitHub a5b212369b Set findOneServerlessFunction result nullable (#12179)
solves https://github.com/twentyhq/twenty/issues/11819
remove fetch query when deleting code step
2025-05-21 13:59:20 +00:00
MarieandGitHub 8c6569be3b Add relation exceptions (#12185)
Introducing a class of RelationException extending CustomException to
help grouping those exception in sentries by ExceptionCode.
I did not introduce a filter as these are thrown in utils that can be
used in multiple places now or in the future, and filters are to be
added at resolver-level.
2025-05-21 15:53:25 +02:00
Raphaël BosiandGitHub c982bcdb52 Introduce focus stack to handle hotkeys (#12166)
# Introduce focus stack to handle hotkeys

This PR introduces a focus stack to track the order in which the
elements are focused:
- Each focused element has a unique focus id
- When an element is focused, it is pushed on top of the stack
- When an element loses focus, we remove it from the stack 

This focus stack is then used to determine which hotkeys are available.
The previous implementation lead to many regressions because of race
conditions, of wrong order of open and close operations and by
overwriting previous states. This implementation should be way more
robust than the previous one.

The new api can be incrementally implemented since it preserves
backwards compatibility by writing to the old hotkey scopes states.
For now, it has been implemented on the modal components.

To test this PR, verify that the shortcuts still work correctly,
especially for the modal components.
2025-05-21 15:52:40 +02:00
7f1d6f5c7f Continue migration schema from metadata to core (#12168)
2nd part of the migration - this time we're migrating all the tables

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-05-21 15:44:13 +02:00
Félix MalfaitandGitHub 8c20bada79 Fix Scalar preload (#12184)
Chrome doesn't really respect preloading and was loading it before other
important assets, slowing down the app while in 99% of sessions people
don't check the REST API playground
2025-05-21 15:27:46 +02:00
Thomas TrompetteandGitHub 5c16b2752d Fix workflow sub objects updates validation (#12169)
Fixes https://github.com/twentyhq/core-team-issues/issues/983

- Enabling workflow version name update, even if not in draft status
- Assert draft when updating steps
- Enabling workflow run name update
2025-05-21 13:11:32 +00:00
MarieandGitHub 23ebd69541 Add Approved access domain exception filter (#12180)
We have approvedAccessDomain custom exceptions, but they were never
filtered while some of them reflects 4xx errors which we don't want to
be captured as 5xx errors
2025-05-21 14:36:14 +02:00
Baptiste DevessierandGitHub 4f4d216a21 Use null as the default value for link fields when persisting (#12173)
Follow up for https://github.com/twentyhq/twenty/pull/12113

I created stories for the LinksFieldInput component.
2025-05-21 14:11:38 +02:00
MarieandGitHub fdde7651a4 Fix email verification exception are not caught (#12174)
cf
[sentry](https://twenty-v7.sentry.io/issues/6606375182/?project=4507072499810304&query=is%3Aunresolved%20%21issue.type%3A%5Bperformance_consecutive_db_queries%2Cperformance_consecutive_http%2Cperformance_file_io_main_thread%2Cperformance_db_main_thread%2Cperformance_n_plus_one_db_queries%2Cperformance_n_plus_one_api_calls%2Cperformance_p95_endpoint_regression%2Cperformance_slow_db_query%2Cperformance_render_blocking_asset_span%2Cperformance_uncompressed_assets%2Cperformance_http_overhead%2Cperformance_large_http_payload%5D&referrer=issue-stream&sort=date&stream_index=4)

Email verification exception were not caught when thrown outside of
email-verification resolver, which be the case at authentication step.
2025-05-21 14:09:11 +02:00
EtienneandGitHub 76a8a644a2 fix mail thread design (#12167)
## Before
METADATA
<img width="400" alt="Screenshot 2025-05-21 at 11 34 51"
src="https://github.com/user-attachments/assets/b057dd3f-3ba1-4597-86a4-84157941f10a"
/>
SUBJECT
<img width="400" alt="Screenshot 2025-05-21 at 11 34 38"
src="https://github.com/user-attachments/assets/c41bc102-a84d-443f-bf8c-a77ca9eacd2c"
/>
SHARE_EVERYTHING
<img width="400" alt="Screenshot 2025-05-21 at 11 34 04"
src="https://github.com/user-attachments/assets/0ed39c88-3516-4ebf-9950-5ceabbc38f13"
/>


## After
SHARE_EVERYTHING
<img width="400" alt="Screenshot 2025-05-21 at 11 29 18"
src="https://github.com/user-attachments/assets/72efbf0f-021b-4012-8516-8b7b8318a1e8"
/>
METADAT
<img width="400" alt="Screenshot 2025-05-21 at 11 28 49"
src="https://github.com/user-attachments/assets/73065e89-c5ab-4938-ae71-e557aa3fe8f3"
/>
SUBJECT
<img width="400" alt="Screenshot 2025-05-21 at 11 28 35"
src="https://github.com/user-attachments/assets/10487afb-602d-41fc-bb66-15d71e2fb90f"
/>

Design :
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=23338-52430&t=9NbeB5idQaaOWPAq-0
2025-05-21 12:07:17 +02:00
EtienneandGitHub 3702fefc89 Move defaultAvatarUrl on userWorkspace + migration command (#12100)
closes https://github.com/twentyhq/core-team-issues/issues/883
2025-05-21 12:07:02 +02:00
martmullandGitHub 8e2d0139ed Emit proper event on createOrUpdate csv import operation (#12163)
- use proper event emitter when upserting records with csv import
- After:


https://github.com/user-attachments/assets/8303da38-2e35-4f4c-bb13-8a7a222971b7
2025-05-21 11:59:50 +02:00
819b3c6c0d followup #12033 (#12150)
follow up #12033

in #12033, SettingsDataModelFieldRelationForm I changed the the use of
objectMetadataItems to activeObjectMetadataItems, which filtered out
system objects. The naming was one factor for this confusion
Renaming it everywhere to specify that they don't include system objects

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-21 11:45:33 +02:00
Baptiste DevessierandGitHub c29ed1c0c9 Consider null values as empty values for link fields (#12113)
This pull request introduces changes to improve handling of nullable
values in link-related data structures and simplifies field value
generation logic. Key updates include adjustments to type definitions,
utility functions, and component logic to support `null` values for
links, along with the removal of the `generateDefaultFieldValue`
function in favor of `generateEmptyFieldValue`.

There will be a few more follow-up Pull Requests.

---

Closes https://github.com/twentyhq/twenty/issues/11844
2025-05-21 11:30:15 +02:00
EtienneandGitHub 7461b7ac58 lowercase user and invitation emails (#12130)
### Solution

> After discussion with charles & weiko, we chose the long term
solution.
> 
> Fix FE to request checkUserExists resolver with lowercased emails
> Add a decorator on User (and AppToken for invitation), to lowercase
email at user (appToken) creation. ⚠️ It works for TypeOrm .save method
only (there is no user email update in codebase, but in future it
could..)
> Add email lowercasing logic in external auth controller
> Fix FE to request sendInvitations resolver with lowercased emails
> Add migration command to lowercase all existing user emails and
invitation emails

> For other BE resolvers, we let them permissive. For example, if you
made a request on CheckUserExists resolver with uppercased email, you
will not found any user. We will not transform input before checking for
existence.

[link to comment
](https://github.com/twentyhq/twenty/pull/12130#discussion_r2098062093)

### Test 🚧 
- sign-in and up from main subdomain and workspace sub domain > Google
Auth (lowercased email) ✔️ | Microsoft Auth (uppercased email ✔️ &
lowercased email) | LoginPassword (uppercased email ✔️& lowercased
email✔️)
- invite flow with uppercased and lowercased ✔️
- migration command + sign-in ( former uppercased microsoft email ✔️) /
sign-up ( former uppercased invited email ✔️)

closes https://github.com/twentyhq/private-issues/issues/278, closes
https://github.com/twentyhq/private-issues/issues/275, closes
https://github.com/twentyhq/private-issues/issues/279
2025-05-21 11:06:29 +02:00
GuillimandGitHub 6ff5a5bafa fixing a microsoft graph api error (#12154)
The issue is "Microsoft Graph API unknown error: TypeError: Cannot read
properties of undefined (reading 'emailAddress')"

Sentry :
https://twenty-v7.sentry.io/issues/6605750776/events/7feb4f5949a64ab78bb429cffb7f0fea/?project=4507072499810304

Fixes https://github.com/twentyhq/core-team-issues/issues/981
2025-05-21 11:04:43 +02:00
GuillimandGitHub 91e487dd63 Catching "no licence" microsoft account (#12143)
Catching "no licence - removed" microsoft message channels. 

Current behabiour 
> ` MessageImportException [Error]: The mailbox is either inactive,
soft-deleted, or is hosted on-premise.`

Goal:
better track errors VS user mistakes

Context: 
A similar logic was already implemented for the calendar channels. I
just replicated it to message channels
2025-05-21 11:04:11 +02:00
Thomas TrompetteandGitHub fe25557337 Fix send email connected account (#12149)
Fixes https://github.com/twentyhq/twenty/issues/12144

Account owner id is not fetched anymore by default in find many
connected accounts.
This is coming from the relation migration, since account owner id is
not a basic field anymore.

Enforcing the fetch of account owner id + adding tests

<img width="251" alt="Capture d’écran 2025-05-20 à 18 23 44"
src="https://github.com/user-attachments/assets/3e3105a0-d3e8-4b5d-87b0-80d3e97ab034"
/>
2025-05-21 09:02:04 +00:00
ca78fc3f27 i18n - translations (#12148)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-20 17:21:01 +02:00
Thomas TrompetteandGitHub 538f831fc1 Prevent webhook trigger from enabling keys with spaces (#12146)
Fixes https://github.com/twentyhq/core-team-issues/issues/984

Variables do not support spaces. Preventing those in webhook triggers

<img width="501" alt="Capture d’écran 2025-05-20 à 16 22 19"
src="https://github.com/user-attachments/assets/563e4068-583f-4802-9309-a12c00143509"
/>
2025-05-20 17:04:48 +02:00
Lucas BordeauandGitHub 5f333ccd65 Fixes RelationFromManyFieldDisplay story (#12141)
This PR adds back and fixes the story for RelationFromManyFieldDisplay,
which was broken due to the removal of use-context-selector state.

The story was also setting unnecessary states, we now only keep one
state set in the recoil state.
2025-05-20 15:30:43 +02:00
GuillimandGitHub ad136b5246 better logging errors in messages (#12136) 2025-05-20 13:37:24 +02:00
Lucas BordeauandGitHub 0553f58c52 Removed use-context-selector completely (#12139)
This PR removes use-context-selector completely, so that any bug
associated with state synchronization between recoil and
use-context-selector disappears.

There might be a slight performance decrease on the table, but since we
have already improved the average performance per line by a lot, and
that the performance bottleneck right now is the fetch more logic and
the windowing solution we use, it is not relevant.

Also the DX has become so hindered by this parallel state logic recently
(think [cache
invalidation](https://martinfowler.com/bliki/TwoHardThings.html)), that
the main benefit we gain from this removal is the DX improvement.

Fixes https://github.com/twentyhq/twenty/issues/12123
Fixes https://github.com/twentyhq/twenty/issues/12109
2025-05-20 13:35:28 +02:00
9ba24b3654 Fix: Editing a task assignee relation from the list opens both the command menu and the multi item picker (#12138)
Fixes https://github.com/twentyhq/twenty/issues/12129

To fix this, we need to stop the click event from propagating up from
the ActivityTargetsInlineCell

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-05-20 12:14:19 +02:00
WeikoandGitHub 203d4fc84f Fix: Deleting an opportunity from the relation detail section deletes a person (#12137)
Fixes https://github.com/twentyhq/twenty/issues/12131

All instances of RecordDetailRelationRecordsListItem are sharing the
same DELETE_RELATION_MODAL_ID, this PR makes the modal ID unique for
each item.
2025-05-20 11:38:16 +02:00
Charles Bochet d6215cad46 Fix Modal stories 2025-05-20 00:53:32 +02:00
b48c8a11e0 Fix #10941: Make sure content adjusts itself when resizing cell (#11392)
Regarding issue #10941:
Previously, when resizing a column relative to the record's name, the
content did not properly adjust to the selected width. This issue
occurred because the parent element (the link) was not a flex container,
preventing the child elements from resizing accordingly.
This fix makes the Chip link inline-flex to allow proper content
adjustment.
Additionally, the Chip itself is now set to width: 100% so that it fully
adapts to its parent.
A small margin of 2 * theme.spacing(1) has also been added to improve
spacing.

Files changed:
packages/twenty-ui/src/components/chip/Chip.tsx
packages/twenty-ui/src/components/chip/LinkChip.tsx

**Video:**

https://github.com/user-attachments/assets/83832c25-0b70-490f-90ed-0d391addf6f8

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-20 00:43:26 +02:00
2477cad989 i18n - translations (#12135)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-20 00:14:45 +02:00
6f62636763 Refactor: Improve Docker volume permission handling and remove run-once service (#11405)
**Problem:**

The previous `docker-compose.yml` included a `change-vol-ownership`
service. This service was designed to run once upon startup to `chown`
the `server-local-data` and `docker-data` volumes to user/group
`1000:1000`. This was necessary because:
1. The main `server` and `worker` containers run as the non-root user
`1000` for security.
2. Docker typically creates/mounts named volumes initially owned by
`root`.
3. The application needs write access to these volumes.

However, this run-once service pattern causes problems in certain
deployment environments (like Coolify) that don't gracefully handle
services designed to exit after completing their task. This can lead to
deployment failures or warnings.

**Solution:**

This PR refactors the Docker setup to address the volume permission
issue directly within the Docker image build process, eliminating the
need for the run-once service.

**Changes:**

1.  **`packages/twenty-docker/docker-compose.yml`:**
    *   Removed the `change-vol-ownership` service definition entirely.
* Removed the `depends_on: change-vol-ownership` condition from the
`server` service definition.
* **Proposed Change:** Removed the `${STORAGE_LOCAL_PATH}` environment
variable from the `server-local-data` volume mounts for both `server`
and `worker` services. The path is now hardcoded to
`/app/packages/twenty-server/.local-storage`. (See Reasoning below).

2.  **`packages/twenty-docker/twenty/Dockerfile`:**
* In the final stage, *before* the `USER 1000` command, added lines to:
* Create the necessary directories: `RUN mkdir -p
/app/packages/twenty-server/.local-storage /app/docker-data` (and also
`/app/.local-storage` for safety, though it's likely unused by volumes).
* Set the correct ownership: `RUN chown -R 1000:1000 /app/.local-storage
/app/packages/twenty-server/.local-storage /app/docker-data`.

3.  **`packages/twenty-docker/twenty/entrypoint.sh`:**
* Added a check near the beginning of the script for the presence of the
now-potentially-unused `STORAGE_LOCAL_PATH` environment variable.
* If the variable is set, a warning message is printed to standard
output, informing the user that the variable might be deprecated and
ignored if the hardcoded path change in `docker-compose.yml` is
accepted.

**Reasoning:**

By creating the target directories
(`/app/packages/twenty-server/.local-storage` and `/app/docker-data`)
within the Docker image *and* setting their ownership to `1000:1000`
during the build (while still running as root), we leverage Docker's
volume initialization behavior. When a named volume is mounted to a
non-empty directory in the container image, Docker copies the content
and ownership from the image directory into the volume. This ensures
that when the `server` and `worker` containers start (running as user
`1000`), the volumes they mount already have the correct permissions,
eliminating the need for the separate `change-vol-ownership` service.

**Regarding `STORAGE_LOCAL_PATH`:**
The `docker-compose.yml` previously allowed configuring the path for
local storage via the `STORAGE_LOCAL_PATH` variable, defaulting to
`.local-storage`. Since the Dockerfile now explicitly creates and sets
permissions for `/app/packages/twenty-server/.local-storage`,
maintaining this configuration might be unnecessary or could potentially
lead to permission errors if a user sets it to a path *not* prepared in
the Dockerfile.

This PR proposes hardcoding the path in `docker-compose.yml` to
`/app/packages/twenty-server/.local-storage` to align with the
Dockerfile changes and simplify configuration. Is this acceptable, or is
there a specific use case for retaining the `STORAGE_LOCAL_PATH`
variable that needs to be considered? If retained, the Dockerfile would
need further changes to dynamically handle permissions based on this
variable.

**Impact:**

* Improves compatibility with deployment platforms that struggle with
run-once containers.
* Simplifies the `docker-compose.yml` setup (potentially, pending
discussion on `STORAGE_LOCAL_PATH`).
* Fixes volume permissions at the source (image build) rather than
relying on a runtime fix.
* Adds a warning for users who might have the potentially deprecated
variable set.

**Testing:**

The changes have been tested locally using `docker compose up`. The
services start correctly, the application is accessible, and the warning
message for the potentially deprecated variable appears as expected when
the variable is set.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-20 00:14:33 +02:00
PuruandGitHub 39fe7aa2a5 fix(docker-compose): increase retry for server service (#11883)
## Background
I'm trying to self-host twenty using [official 1-Click w/ Docker Compose
guide](https://twenty.com/developers/section/self-hosting/docker-compose)
on AWS EC2 (using `t3.small` instance type).

## What happened
I used the one-line script but it failed with
```
[skipped]
server-1                | Successfuly migrated DB!
dependency failed to start: container twenty-server-1 is unhealthy
```

Then I tried manual steps, and it failed again with same issue as above.
No configuration changed, everything default used.

I re-run manual steps multiple times with `docker compose down -v` and
`docker compose up`, everything time it failed with `server` unhealthy
as it seems server takes longer than configured health check duration
(which is 50 seconds)

Here's the `time` summary running it:
```
[skipped]
server-1                | Successfuly migrated DB!
dependency failed to start: container twenty-server-1 is unhealthy

________________________________________________________
Executed in   58.26 secs      fish           external
   usr time  661.43 millis  362.00 micros  661.07 millis
   sys time  646.10 millis  212.00 micros  645.89 millis

root@ip-10-0-10-43 ~/twenty [1]# 
```

## Why it happend

My hunch (new to twenty, just used it yesterday) is that server service
takes much longer to become healthy with DB migration and etc, that
configured health check retries is not sufficient.

## What solution worked

Increased the retry for server service from 10 to 20, and it worked and
service came up healthy (everytime). The increase wasn't needed for db
or worker service, just server service.

If this all makes sense, please feel free to merge this, so it'll be
smoother experience for others new to self-hosting twenty.
2025-05-20 00:04:38 +02:00
98e199c01d Support Full Name as Record Text Identifier (#11610)
closes #11296 


[recording.webm](https://github.com/user-attachments/assets/da0f2587-a435-4bee-a802-81eb9ca92733)

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-20 00:03:30 +02:00
477a10ba4a close dropdown when model opens (#12060)
fixes #11900

changes desc:
1.moved confirmation model adjacent to dropdown component instead inside
it.
2.passing variables of useRecordGroupReorderConfirmationModal from
dropdown root component so confirmations model should remount get
updated with new state

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-05-19 23:46:40 +02:00
Abdul RahmanandGitHub 503aeee81f Fix/record board keyboard navigation empty columns (#12103)
https://github.com/user-attachments/assets/6830217b-28a9-46e6-a9f5-40d508cd262b

Closes #12077
2025-05-19 23:22:56 +02:00
Abdul RahmanandGitHub 42c69dd11a fix: Ensure attachment modal appears above Command Menu button using createPortal (#12112)
<img width="1509" alt="Screenshot 2025-05-19 at 12 50 48 AM"
src="https://github.com/user-attachments/assets/fba95ecb-015a-4742-bda2-4d515d168c16"
/>


Closes #12092
2025-05-19 23:08:31 +02:00
Lucas BordeauandGitHub 4f4f3a64fd Fix table re-renders on update or keyboard navigation (#12127)
This PR fixes the problem of full table re-render on any update or
keyboard navigation.

This was due to a recoil state subscribe in the RecordTable component, I
just moved it in the children effect components so that the Flux
dependency becomes inoffensive.

I also extracted one hook from the useRecordTable hook that we have to
refactor gradually.

Fixes https://github.com/twentyhq/core-team-issues/issues/979
Fixes https://github.com/twentyhq/core-team-issues/issues/932
2025-05-19 22:44:51 +02:00
85e2a2a92b fix: prevent unwanted newlines in note editor when typing (#12128)
https://github.com/user-attachments/assets/16706d7a-fe0e-4979-bd72-00f4bfec594b

Closes #12119

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-05-19 22:43:49 +02:00
Charles BochetandGitHub cba36af1e8 Fix dropdown (#12126)
In this PR:
- deprecating listenClickOutside ComparePixel mode as this is not
accurate. We were using to avoid portal issue with CompareHtmlRef mode
but this is still an issue when portalled content overflows the
container.
- add ClickOutsideContext to specify excluded className so portal
children can use it easily (part of the tooling)
- fix stories
- remove avoidPortal from dropdown as this was not used
2025-05-19 16:37:51 +02:00
WeikoandGitHub bb4fed5a5e Fix Identifier chips in Timeline Activities are broken (#12122)
Fixes https://github.com/twentyhq/twenty/issues/12114
Fixes https://github.com/twentyhq/core-team-issues/issues/856

Links were in the wrong format. This is because the timeline activity
code is re-using FieldDisplay which expects a context with a specific
recordId that we can't have (since this is not a true record but simply
the result of a diff and each row in the diff needs to be unique)
Today we build the artificial record ID like this `eventId + '--' +
fieldMetadataItem.id` to keep it unique.
However, in case the event concerns a labelIdentifier field, it uses the
ChipDisplay which creates a link to the record using the artificial ID
which results in a 404 when using the link.
We don't really need that link since it points to the record itself (the
one that is already opened) so I'm simply removing the
isLabelIdentifierField set in
[EventFieldDiffValue.tsx](https://github.com/twentyhq/twenty/compare/c--fix-identifier_chips_in_timeline_activities_are_broken?expand=1#diff-af17142141c5334214f43840460a142d531c61be7c3cff55bd8a495eb831bc69)
so even if it's one labelIdentifierField, it won't try to display it as
such.

Ideally we should refactor this logic and not try to reuse FieldDisplay
imho, we probably did that to avoid duplicating logic but that's a lot
of "fake" context to get the desired result

Before
<img width="423" alt="Screenshot 2025-05-19 at 15 23 46"
src="https://github.com/user-attachments/assets/b9573f4c-e205-4fdb-bdee-65b890da7810"
/>

After
<img width="428" alt="Screenshot 2025-05-19 at 15 23 33"
src="https://github.com/user-attachments/assets/96f29842-b9aa-4230-8125-dd7d1a56baed"
/>
2025-05-19 16:21:29 +02:00
Raphaël BosiandGitHub b70119dbe6 Fix modal click outside (#12120)
Fixes https://github.com/twentyhq/twenty/issues/12111

The bug occurred because in
https://github.com/twentyhq/twenty/pull/12062, I changed the click
outside mode of the modal from compare pixels to compare html ref. This
happens because the modal is in a portal, so the `compareHTMLRef`
doesn't work.

A bug already existed before but since the mode was compare pixel, it
only happened when a dropdown was overflowing from the modal:


https://github.com/user-attachments/assets/e34bfaca-dd21-46e5-a532-a66ba494889d

I commented the tests `CancelButtonClick`, and `ConfirmButtonClick`
because they don't work with compare pixel mode (the `userEvent.click()`
creates a `MouseEvent` with `clientX`=0 and `clientY`=0 so it triggers
the click outside listener even when the story tiggers a click on an
element inside a modal)

We should find a way to make the ClickOutsideMode `compareHTMLRef` work
with portals. I believe the `comparePixels` mode was used as a hacky way
to get around this problem (hacky because of the existing bug above).
2025-05-19 15:04:04 +02:00
EtienneandGitHub efc43208d3 add command to clean not found files (#12094)
closes https://github.com/twentyhq/core-team-issues/issues/883

tested on person, workspaceMember, workspace and attachments files -
dry/normal
2025-05-19 14:45:15 +02:00
MarieandGitHub a8753113a7 Fix aggregate operation update on dates on kanban views (#12115)
Fixes https://github.com/twentyhq/core-team-issues/issues/968
2025-05-19 13:19:38 +01:00
EtienneandGitHub 52ad789e7a fix billingCustomer stripeId fetching (#12116)
### Context
Several 'Customer not found' errors arrived in Sentry, all coming from
webhook-entitlement.service, at subscription creation (coinciding with
customer creation 99% of the time).
Stripe sends many events to update/create customer, subscription,
entitlement, ...
All these events are handle in parallel but customer.created stripe
event arrived first and few seconds after subscription.created and
entitlements.active_entitlement_summary.updated

Issue happens at entitlements.active_entitlement_summary.updated
handling. It checks for customer existence through subscription. But
subscription can be not created yet at this moment.

### Solution
Check directly for customer existence in billingCustomer table. Not sure
it will fix the error because of the parallel handling of Stripe event,
but should still be better.

### Tested
- Workspace creation
- Subscription upgrade (check for entitlement update)

closes https://github.com/twentyhq/twenty/issues/11960
2025-05-19 13:37:18 +02:00
martmullandGitHub b52ef76376 971 rest api bug sentry on filter parameters (#12088)
- fix missing createBy injection in api createOne and createMany
endpoints
- add a command to fix null default value for createdBySource in
production entities
- tested on `1747159401197/` dump extract of production db without issue
2025-05-19 12:46:03 +02:00
Lucas BordeauandGitHub 58b40b1f89 Removed value setter effect completely (#12101)
This PR removes the effect component that was synchronizing the record
store recoil state with the context selector equivalent state that is
used for performance on the tables.

Now we only set the context selector in parallel with the recoil state,
thus avoiding any synchronization side-effect between those two states.
2025-05-17 15:41:01 +02:00
Félix MalfaitandGitHub 64d988cdec Fix pg pool implementation (#12106)
Fix the following error: 
Cannot use a pool after calling end on a pool

<img width="917" alt="Screenshot 2025-05-17 at 14 56 18"
src="https://github.com/user-attachments/assets/63081831-9a7e-4633-8274-de9f8a48dbae"
/>

The problem was that the datasource manager was destroying the
connections when a datasource cache expired.
2025-05-17 15:22:10 +02:00
GuillimandGitHub d93024fd02 Refactoring the reconnect service (#12089)
following qrqc #3 : refactoring the reconnect service

Fixes https://github.com/twentyhq/twenty/issues/12064
2025-05-17 13:47:01 +02:00
e83baa5438 Patch pg pool (#12081)
This PR implements a global PostgreSQL connection pool sharing
mechanism.

- Patches pg.Pool to reuse connection pools across the application when
connection parameters match, reducing resource overhead.
- New environment variables allow enabling/disabling sharing and
configuring pool size, idle timeout, and client exit behavior.

WorkspaceDatasourceFactory will now use shared pools if enabled, this
will avoid recreating 10 connections for each pods for each workspace.

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-05-16 21:46:37 +02:00
Thomas TrompetteandGitHub eca5ef7cfe Fix composite field edition (#12095)
Fixes https://github.com/twentyhq/twenty/issues/12056

Bug has been introduced by
https://github.com/twentyhq/twenty/pull/11983/files

Adding onClick on the container makes it always available. Before it was
only when not in edit mode.
It breaks the click outside of the `RecordInlineCell`.

This PR set the onClick only when not in edit mode.



https://github.com/user-attachments/assets/a44337a9-72e6-4de8-afa1-95de6b953459
2025-05-16 18:58:32 +02:00
Raphaël BosiandGitHub e48b84f241 Fix hidden copy button on production build for text fields (#12099)
Fixes #11762

The `copy-button` classname from scalar was overwritting the style of
our copy button. It only happened in production build and not with `npx
nx run twenty-front:start` so it was quite hard to catch. Thanks
@charlesBochet for finding the root cause.

- Removed `copy-button` classname since it was unused
- Added `?inline` when importing scalar css to have inline css

Before:
<img width="210" alt="Capture d’écran 2025-05-16 à 17 43 50"
src="https://github.com/user-attachments/assets/7256b5e6-0b61-4590-a4de-d6b28ab2b4ed"
/>

After:
<img width="230" alt="Capture d’écran 2025-05-16 à 17 43 32"
src="https://github.com/user-attachments/assets/a763172b-0566-413d-bbdd-470f28097ae4"
/>
2025-05-16 18:29:42 +02:00
WeikoandGitHub 806bb611e8 Fix yoga scalar validations being captured (#12085)
Yoga graphql error were not correctly interpreted by the exception
handler. Mostly validations on the scalars such as bad enum options,
wrong format for uuid and such.
This PR adds a new convertGraphQLErrorToBaseGraphQLError utility
function in graphql-errors.util.ts that converts those errors to our
custom BaseGraphQLError by using the extension.http.code from the error
when possible so they can be handled the same way we treat the graphql
errors we throw ourselves.

Before
<img width="799" alt="Screenshot 2025-05-16 at 11 04 08"
src="https://github.com/user-attachments/assets/08b0a908-34d8-45a6-b315-8e211d1104ce"
/>

After
<img width="797" alt="Screenshot 2025-05-16 at 11 16 37"
src="https://github.com/user-attachments/assets/3fff0a70-6c3f-413a-b458-56030377fec9"
/>
2025-05-16 18:11:52 +02:00
Paul RastoinandGitHub 6823224177 [DOCS] A Note about audit log removal in 0.53 upgrade (#12097)
# Introduction

Please see related added docs
2025-05-16 15:18:11 +00:00
Raphaël BosiandGitHub 455615b14c Fix drag selection on table make rows bigger (#12096)
Fixes [#12036](https://github.com/twentyhq/twenty/issues/12036)
2025-05-16 17:15:24 +02:00
Raphaël BosiandGitHub 6554947671 Modal API Refactoring (#12062)
# Modal API Refactoring

This PR refactors the modal system to use an imperative approach for
setting hotkey scopes, addressing race conditions that occurred with the
previous effect-based implementation.

Fixes #11986
Closes #12087

## Key Changes:

- **New Modal API**: Introduced a `useModal` hook with `openModal`,
`closeModal`, and `toggleModal` functions, similar to the existing
dropdown API
- **Modal Identification**: Added a `modalId` prop to uniquely identify
modals
- **State Management**: Introduced `isModalOpenedComponentState` and
removed individual boolean state atoms (like
`isRemoveSortingModalOpenState`)
- **Modal Constants**: Added consistent modal ID constants (e.g.,
`FavoriteFolderDeleteModalId`, `RecordIndexRemoveSortingModalId`) for
better maintainability
- **Mount Effects**: Created mount effect components (like
`AuthModalMountEffect`) to handle initial modal opening where needed

## Implementation Details:

- Modified `Modal` and `ConfirmationModal` components to accept the new
`modalId` prop
- Added a component-state-based approach using
`ModalComponentInstanceContext` to track modal state
- Introduced imperative modal handlers that properly manage hotkey
scopes
- Components like `ActionModal` and `AttachmentList` now use the new
`useModal` hook for better control over modal state

## Benefits:

- **Race Condition Prevention**: Hotkey scopes are now set imperatively,
eliminating race conditions
- **Consistent API**: Modal and dropdown now share similar patterns,
improving developer experience

## Tests to do before merging:

1. Action Modals (Modal triggered by an action, for example the delete
action)

2. Auth Modal (`AuthModal.tsx` and `AuthModalMountEffect.tsx`)
   - Test that auth modal opens automatically on mount
   - Verify authentication flow works properly

3. Email Verification Sent Modal (in `SignInUp.tsx`)
   - Verify this modal displays correctly

4. Attachment Preview Modal (in `AttachmentList.tsx`)
   - Test opening preview modal by clicking on attachments
   - Verify close, download functionality works
   - Test modal navigation and interactions

5. Favorite Folder Delete Modal (`CurrentWorkspaceMemberFavorites.tsx`)
   - Test deletion confirmation flow
- Check that modal opens when attempting to delete folders with
favorites

6. Record Board Remove Sorting Modal (`RecordBoard.tsx` using
`RecordIndexRemoveSortingModalId`)
- Test that modal appears when trying to drag records with sorting
enabled
   - Verify sorting removal works correctly

7. Record Group Reorder Confirmation Modal
(`RecordGroupReorderConfirmationModal.tsx`)
   - Test group reordering with sorting enabled
   - Verify confirmation modal properly handles sorting removal

8. Confirmation Modal (base component used by several modals)
   - Test all variants with different confirmation options

For each modal, verify:
- Opening/closing behavior
- Hotkey support (Esc to close, Enter to confirm where applicable)
- Click outside behavior
- Proper z-index stacking
- Any modal-specific functionality
2025-05-16 15:04:22 +00:00
nitinandGitHub 8334fe9528 Add placeholder to signinup modal's secondary logo (#12079)
closes https://github.com/twentyhq/core-team-issues/issues/972

checks - 

- [x]  If we have an icon it should be displayed as `secondary`

<img width="1064" alt="Screenshot 2025-05-16 at 00 33 42"
src="https://github.com/user-attachments/assets/20716df3-28be-40c5-b0fc-2133fccdad83"
/>

- [x] If no icon is provided, display a placeholder

<img width="1062" alt="Screenshot 2025-05-16 at 00 33 09"
src="https://github.com/user-attachments/assets/0241dafe-3d31-4f8e-a9e4-321634f6d41c"
/>

- [x] Add story for auth logos
<img width="550" alt="Screenshot 2025-05-16 at 16 16 24"
src="https://github.com/user-attachments/assets/3859547d-32c5-469f-879b-a130a36a23fa"
/>

<img width="548" alt="Screenshot 2025-05-16 at 16 16 30"
src="https://github.com/user-attachments/assets/4937fa6a-459a-4c75-86ae-2080b1c8a5ae"
/>

<img width="487" alt="Screenshot 2025-05-16 at 16 16 16"
src="https://github.com/user-attachments/assets/2c634be1-4a51-4b06-a590-cdd7eff91b76"
/>

<img width="556" alt="Screenshot 2025-05-16 at 16 16 07"
src="https://github.com/user-attachments/assets/e4a518b4-c338-45c1-a329-5c9f85319c52"
/>
2025-05-16 14:21:24 +00:00
4017bd48f7 Update SettingsFieldCurrencyCodes.ts — XOF Currency (#12047)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-16 12:09:41 +02:00
EtienneandGitHub 160eb23454 QRQC #2 - Fix (#12054)
- [x] findOne/findManyCalendarEvents / findOne/findManyMessages - add
integration tests
- [ ] ~~fix typing~~ - coming in new PR >
[Issue](https://github.com/twentyhq/core-team-issues/issues/976)
2025-05-16 11:38:34 +02:00
MarieandGitHub dc4bcc3049 Improve sentry filtering and grouping (#12071)
Follow-up on https://github.com/twentyhq/twenty/pull/12007

In this PR

- adding a filter on HttpExceptionHandlerService to filter out 4xx
errors from driver handling (as we do for graphQL errors: see
useGraphQLErrorHandler hook - only filteredIssues are sent to`
exceptionHandlerService.captureExceptions()`.)
- grouping together more missing metadata issues
- attempting to use error codes as issues names in sentry to improve UI;
for now it says "Error" all the time
2025-05-16 11:35:48 +02:00
Félix MalfaitandGitHub 4d303a61d1 Change idle connection time (#12073)
As discussed with @Weiko

Even though we cache the datasource, the connection expire after
10minutes in TypeORM, that might be the reason why our app is spamming
the proxy asking for connections. Also lowering the pool size.
2025-05-15 19:23:51 +00:00
Antoine MoreauxandGitHub 1570ad955e fix(domain-manager): correct domain URL reference and filter logic (#12074)
Updated URL reference from getFrontUrl to getBaseUrl to ensure correct
hostname handling. Adjusted record filtering logic to exclude successful
records, preventing unnecessary rendering in the UI.
2025-05-15 19:35:55 +02:00
Lucas BordeauandGitHub 09d92c9113 Fixes infinite loop on record data update in command menu (#12072)
This PR fixes the infinite loop that was happening in `RecordShowEffect`
component due to a useEffect on `recordStoreFamilyState` which was
creating a non-deterministic open loop.

The fix was to use a recoilCallback to avoid reading a stale state from
Recoil with `useRecoilValue`, useRecoilCallback always gets the most
fresh data and commits everything before React goes on with rendering,
thus avoiding any stale value in a useEffect.

Fixes https://github.com/twentyhq/twenty/issues/11079
Fixes https://github.com/twentyhq/core-team-issues/issues/957
2025-05-15 18:26:01 +02:00
Paul RastoinandGitHub 442f8dbe3c [QRQC_2] No implicitAny in twenty-server (#12075)
# Introduction
Following https://github.com/twentyhq/twenty/pull/12068
Related with https://github.com/twentyhq/core-team-issues/issues/975

We're enabling `noImplicitAny` handled few use case manually, added a
`ts-expect-error` to the others, we should plan to handle them in the
future
2025-05-15 18:23:22 +02:00
martmullandGitHub 08ce2f831e Fix missing exception catch (#12069)
add a check about uuid in rest api findOne handler
2025-05-15 15:01:57 +00:00
a8423e8503 [QRQC_2] No explicit any in twenty-server (#12068)
# Introduction

Added a no-explicit-any rule to the twenty-server, not applicable to
tests and integration tests folder

Related to https://github.com/twentyhq/core-team-issues/issues/975
Discussed with Charles

## In case of conflicts
Until this is approved I won't rebased and handle conflict, just need to
drop two latest commits and re run the scripts etc

## Legacy
We decided not to handle the existing lint error occurrences and
programmatically ignored them through a disable next line rule comment

## Open question
We might wanna activate the
[no-explicit-any](https://typescript-eslint.io/rules/no-explicit-any/)
`ignoreRestArgs` for our use case ?
```
    ignoreRestArgs?: boolean;
```

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-05-15 16:26:38 +02:00
GuillimandGitHub c95c4383b4 Gmail temporary error (#12058)
# Handling Google error

This bug is hard to reproduce so the resolution is based only on the
Sentry logs. There is not definite error code
for this error message. in the documentation.
https://developers.google.com/workspace/gmail/api/guides

This is why i added more 5xx code types in order to be sure we catch
this. In order to refine this later, i added the error code to the
message.

Fixes https://github.com/twentyhq/twenty/issues/12025
2025-05-15 16:12:10 +02:00
MarieandGitHub f782f4dcd8 Fix CSV import upsert (#12048)
Fixes https://github.com/twentyhq/twenty/issues/11864 and
https://github.com/twentyhq/core-team-issues/issues/908

We should not send `createManyXXX` mutations with FE-forged ids in the
payload if we want to do an upsert, because that 1) prevents records
from being merged 2) triggers optimistic rendering while we can't know
before-hand which records will actually be created and which records
will only be updated

Also noticed createdBy was being overriden even for records we are
updating and not creating, which did not seem right, so fixed that too
2025-05-15 14:44:31 +02:00
Thomas TrompetteandGitHub aa424c6680 Make workflow custom fields editable (#12063)
Fixes https://github.com/twentyhq/twenty/issues/11989

<img width="1267" alt="Capture d’écran 2025-05-15 à 14 05 15"
src="https://github.com/user-attachments/assets/fbb22f52-2c76-424f-8b8c-fb030fef9fa8"
/>

`isCustom` was not properly set everywhere because it was not mandatory
in `isFieldValueReadOnly`. Removing the default value and adding it to
missing places
2025-05-15 12:28:13 +00:00
GuillimandGitHub 411cb33137 [reconnect account] Reseting calendar status and stage on reconnect (#12061)
## Description
When a calendar channel fails, its status is not reset during the
reconnect step.

In some cases, resetting is necessary—especially when we’ve deployed a
fix and users try to reconnect their accounts after the patch.

## Why reseting to initial state
Our processes are idempotent, so we can safely set the status to null to
restart the flow. This approach covers all cases and avoids edge
conditions caused by inconsistent statuses.


Fixes : https://github.com/twentyhq/twenty/issues/12026
2025-05-15 14:12:32 +02:00
3a494905ec Fixed error with previous filters on ACTOR with new sub-field filtering (#12050)
Fixes https://github.com/twentyhq/core-team-issues/issues/969 that
appeared since the new ACTOR sub-field filtering that changed the
default sub-field filtering from name to source.

Now we apply any existing filter value on an ACTOR field, whether for a
sub-field or not, to the name sub-field by default.

If the user wants to create a sub-field filter on source, he has to
create a new advanced filter.

Fixes https://github.com/twentyhq/core-team-issues/issues/967

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-05-15 13:58:22 +02:00
nitinandGitHub 93c91c88dc Exclude workflows from relation field object dropdown when inactive (#12033)
closes #11996
- Switched the “Object destination” select in
SettingsDataModelFieldRelationForm to use
activeObjectMetadataItems.filter(...) so workflows, system, and remote
objects are excluded
- Updated useRelationSettingsFormInitialValues to fall back on the same
filtered activeObjectMetadataItems list for its initial value

This ensures workflows (and any unwanted system/remote objects) no
longer show up in the dropdown or as the default.
2025-05-15 17:04:10 +05:30
Thomas TrompetteandGitHub 6a40ec604c Validate existing fields on creation (#12057)
Fixes https://github.com/twentyhq/twenty/issues/12040

When fields are deleted but still used in workflows we do not update
create record action settings.
It breaks all following workflow execution and the user cannot update
the settings anymore.

This PR fixes the bug by filtering on existing fields.

Next step will be to clean settings on field deletion. Adding it to fast
follows.

Also lowering throttle limit because some infinite loops are not
catched.
2025-05-15 13:24:57 +02:00
Lucas BordeauandGitHub 9e00a67b25 Fix kanban loading bug (#12042)
Fixes https://github.com/twentyhq/core-team-issues/issues/956

This PR fixes a bug that appeared when switching between two kanban
views multiple times.

Steps to reproduce : 
- Go to kanban view A
- Go to kanban view B
- Go back to kanban view A

Video before : 


https://github.com/user-attachments/assets/4fa789ae-7187-498e-82b4-ee7896cd95d1

Video after : 


https://github.com/user-attachments/assets/2b323a2d-2f76-405d-9abd-38fe72ee2214

The problem was that we allowed a hook to take a nullable parameter that
can be nullable between page switch, and threw when it was undefined.

In order to be more cautious in the future, let's be sure that we don't
throw for undefined props of a hook, when it is expected that those
props can be in an undefined state for several React render loops, while
fetching new data.

Here I identified the parent effect : `<RecordIndexBoardDataLoader />`
that loads all states for a board when we switch between views, for each
column, by calling `<RecordIndexBoardColumnLoaderEffect />` in a
`.map()`.

Each `RecordIndexBoardColumnLoaderEffect` was calling
`useLoadRecordIndexBoardColumn` with a potentially undefined
`boardFieldMetadataId`.

So to fix this, I cut the render flow higher than the throw in
`useLoadRecordIndexBoardColumn`, and by doing that I was able to ensure
that `recordIndexKanbanFieldMetadataItem` in
`RecordIndexBoardDataLoader` was already defined when using it inside
`useLoadRecordIndexBoardColumn`.

`recordIndexKanbanFieldMetadataItem` was unnecessarily fetched two
times, one time in `RecordIndexBoardDataLoader` and another time in its
child `useLoadRecordIndexBoardColumn` hook.

By implementing this flow-cut higher up, I could then remove the `|
null` in TypeScript in children components, and expect a defined value
in all the children of `RecordIndexBoardDataLoader`, thus removing the
need to ask ourselves if we should throw or not in
`useLoadRecordIndexBoardColumn`.
2025-05-15 10:27:47 +02:00
nitinandGitHub 52c38c3082 Correct default fallback logo path in Logo component (#12053)
closes #11849
The Logo component’s fallback URL was pointing to
`/icons/android/android-launchericon-192-192.png`, but the asset lives
under `/images/icons/....`. This updates defaultPrimaryLogoUrl to use
the correct `/images/icons/android/android-launchericon-192-192.png`
path, restoring the default logo display when no primaryLogo prop is
provided.
2025-05-15 09:44:37 +02:00
martmullandGitHub 81cc5da982 [Rest Api] Fix find duplicates endpoint (#12044)
- fix endpoint
- migrate to new rest api v2 service
- add integration test
2025-05-14 20:03:59 +00:00
GuillimandGitHub fdc7d6c93c Messaging issues (#12041)
messageImportException
for messaging and calendar
add more context to the Sentry Exceptions

Fixes https://github.com/twentyhq/twenty/issues/11994
2025-05-14 18:37:42 +02:00
Lucas BordeauandGitHub 628ba18115 Fix infinite loop critical bug (#12046)
This PR fixes an infinite loop than happens due to a useEffect in a non
deterministic manner.

The fix is to put a `isDeeplyEqual()` to avoid re-rendering the
useEffect if the value is the same.

Fixes : https://github.com/twentyhq/core-team-issues/issues/957
2025-05-14 17:40:05 +02:00
EtienneandGitHub 929f7876de fix calendar events and messages post hooks (#12034)
Context
workspaceMemberId is not always present in AuthContext. Solution
implemented here is to fetch workspaceMemberId via userId.

QRQC coming ... 

Tested
- FindManyCalendarEvents / FindOneCalendarEvent
- FindManyMessages / FindOneMessage

closes https://github.com/twentyhq/twenty/issues/12027
2025-05-14 15:52:52 +02:00
MarieandGitHub 0c60fa9c23 Fix cacheData not found after recomputes (#12032)
Closes https://github.com/twentyhq/core-team-issues/issues/861

sentries: [User workspace role map not found after
recompute](https://twenty-v7.sentry.io/issues/6575092700/events/f9825338a30b470eb2345fe78c1e3479/?project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D%20not%20found%20after%20recompute&referrer=next-event&stream_index=0)
(64 events in 90d), [Feature flag map not found after
recompute](https://twenty-v7.sentry.io/issues/6547696076/?project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D%20not%20found%20after%20recompute&referrer=issue-stream&stream_index=1)
(23 events in 90d)

We have a structural issue with cached data and our locking mechanism:
if a data is missing in cache and queried at the same time by two
different entities, the first one will recompute the data and indicate a
lock during the operation, while the second one will seek to recompute
the data too but be stopped because of the ongoing lock, and be left
with no data to use, condemned to throw an error. In this PR I
considered that it was more important to avoid that error and chose to
ignoreLock instead when the data is being queried (through
getFromCacheWithRecompute), but this is maybe questionnable.
An important note is that I can't figure out how users that regularly
use twenty (as it has been the case since this error occured on our
internal workspace) can encounter that error as once computed, **the key
should always be present in the workspace**: the corresponding value it
is always updated, never deleted (until this PR) and recreated. I was
not able understand how this happened

For our data cached without a version to refer to in the database, I
also chose to ignore the lock when the recompute is triggered by a data
change (eg feature flag enabling or assigning user to a role or adding
an objectPermission on a role, etc.), as we never want to imped the
recompute in that case to avoid potential stale data.
2025-05-14 15:41:24 +02:00
Paul RastoinandGitHub 83bdb1a515 [DOCS] New troubleshoot password authentication failed for user "postgres" (#12031)
# Introduction
Shorter and clearer issue
https://github.com/twentyhq/twenty/issues/11868
close https://github.com/twentyhq/twenty/issues/8701
2025-05-14 15:17:06 +02:00
Raphaël BosiandGitHub 8ef9109925 Fix table click outside (#12038)
Fixes #12037 
Follow up on #12011

Make `RecordTableBodyFocusClickOutsideEffect` also be available for
`RecordIndexHotkeyScope.RecordIndex`
2025-05-14 13:08:06 +00:00
martmullandGitHub a4c56bd7fb 960 api rest batch create not working (#12028)
- fix batch endpoint
- migrate batch endpoint to the rest api v2
- add new integration test for batch endpoints
2025-05-14 14:44:04 +02:00
Raphaël BosiandGitHub 0766e73fc4 Fix filtering on grouped table view (#12029)
# Fix filtering on grouped table view

Fixes #11776 
This PR fixes the filtering issue on the grouped by column in the table.
State filters were overwritten by group filters.

- Implemented a new `combineFilters` utility function that properly
merges multiple filter objects using AND logic
- Added tests
- Modified `useFindManyRecordIndexTableParams` to use the new utility
instead of directly merging filter objects

## Before


https://github.com/user-attachments/assets/45d51535-ecbc-4cfd-b523-37e72aafc723


## After


https://github.com/user-attachments/assets/70416779-9a9c-4972-82ed-73ad98b0234f
2025-05-14 13:30:37 +02:00
nitinGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Félix Malfait
2aa5db580b fix 11997 (#12018)
addressing:
https://github.com/twentyhq/twenty/issues/11997#issuecomment-2875772322
<img width="922" alt="Screenshot 2025-05-13 at 22 52 28"
src="https://github.com/user-attachments/assets/dc3b5fdd-b81b-4732-94f3-2ef2eb0012c2"
/>
before: 


https://github.com/user-attachments/assets/b55bf77e-99bf-485f-bcfa-5d311e7d2bd0

after: 


https://github.com/user-attachments/assets/70fb80b2-ce9f-4a8a-ac5d-d8c793c023be

### Some other issues I found

- On clicking clear, nothing happens

Before:


https://github.com/user-attachments/assets/01e937bb-b4d4-4296-baa7-ec1602de2cc9

After:


https://github.com/user-attachments/assets/8e4e5022-fe32-44fe-a7e4-5c98a7f3c2fa


- same behaviour for inline cell DateInput: 


https://github.com/user-attachments/assets/787354e5-b50a-457c-a392-4779270e2832


### Notes
The root issue seems to be that ViewBarFilterDropdown sets a fixed width
of 208px, which isn’t enough for the calendar to render correctly - it
ends up cropping the content. The fix here is more of a workaround than
a deep fix: I’ve adjusted styles to avoid the cropping, but it might be
worth revisiting how we handle sizing for filter dropdowns in general.

cc @lucasbordeau - thoughts?
Related commit:
https://github.com/twentyhq/twenty/commit/afea017c127b5055ead5170873636c0e81953898

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-14 16:35:51 +05:30
9c2b88870f Improve sentry grouping (#12007)
This PR attemps at improving sentry grouping and filtering by 
- Using the exceptionCode as the fingerprint when the error is a
customException. For this to work in this PR we are now throwing
customExceptions instead of internalServerError deprived of their code.
They will still be converted to Internal server errors when sent back as
response
- Filtering 4xx issues where it was missing (for emailVerification
because errors were not handled, for invalid captcha and billing errors
because they are httpErrors and not graphqlErrors)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-14 09:00:06 +00:00
Jordan ChalupkaandGitHub 6a1da5fe53 Make the default view names consistent (#12022) (#12023)
Fixes #12022

## What changed

Now the default names given to views are consistent for People,
Companies and Opportunities

## Before

Some say "All", others say "Some {object name}"


![Image](https://github.com/user-attachments/assets/4233f793-55e1-4566-b9b3-08a6f136dd53)


![Image](https://github.com/user-attachments/assets/29b1af5c-487e-4593-ba40-86163b518ca7)


![Image](https://github.com/user-attachments/assets/81fc1933-0e13-4144-914e-0d99a44db8e4)


![Image](https://github.com/user-attachments/assets/9439fc64-e6e0-4a04-ba28-13c3954a1aa1)

## After


![Image](https://github.com/user-attachments/assets/e88288ac-3a41-4810-bb2a-8e91c937ed6c)


![Image](https://github.com/user-attachments/assets/8fc353e3-5a7c-42ac-88d3-b7014c0fd02c)
2025-05-14 10:44:14 +02:00
martmullandGitHub 4d2e431277 959 api rest startingafter and endingbefore not working properly with orderby (#12012)
Fixes https://github.com/twentyhq/core-team-issues/issues/959
2025-05-14 10:41:56 +02:00
Raphaël BosiandGitHub e835e0ad64 Fix UI not being refreshed after grouping by None in the table (#12013)
Fixes https://github.com/twentyhq/twenty/issues/11719

Before:


https://github.com/user-attachments/assets/9350d20c-e782-4bf4-9e24-bc7dd7f3d03b


After:


https://github.com/user-attachments/assets/d452fd54-63f7-4519-b70f-5c380b7dd8da
2025-05-14 08:14:19 +00:00
nitinandGitHub fcac7b8a40 docs: update admin panel access property name in upgrade guide (#12019)
## Changes
- Updated the property name in the upgrade guide to reflect the
permission split in Admin Panel:
  - `canImpersonate`: only provides access to impersonate functionality
- `canAccessFullAdminPanel`: provides access to all other admin panel
features
2025-05-13 21:59:43 +02:00
c0b2d400d8 [DRAFT]: Add full Dev Workspace seeding to Preview Env Keep-Alive workflow (#12020)
does this work?

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-13 21:58:36 +02:00
Charles BochetandGitHub 0202586d36 Fix message channel processing (#12021)
Several users have complained about not being able to read their emails
anymore.

This is because the find-messages post query hook is expecting
ObjectRecord[] as an input but is actually getting a graphql Connection

Typing was wrong. This PR fixes the typing and make sure the post query
hook always get an ObjectRecord[]
2025-05-13 21:16:23 +02:00
EtienneandGitHub c0a0214879 delete attachment when file is removed from activity body (#11952)
Using useEffect triggered at ActivityRichTextEditor unmount, to delete
attachments only when note is closed (and not when file block is deleted
during note update to keep command + z shortcut)

closes : https://github.com/twentyhq/twenty/issues/11229
2025-05-13 19:18:38 +02:00
Paul RastoinandGitHub 3fe9c79967 docs(website): fix typos (#12016) 2025-05-13 19:16:44 +02:00
Paul RastoinandGitHub 6ac82b9591 [DOCS] Upgrade guide 0.53 (#12015) 2025-05-13 18:35:09 +02:00
Baptiste DevessierandGitHub fc4d313907 Remove duplicated position for task's status field (#11998)
In this PR:

- Set the default position for the DONE option of the task's status
option to `2` instead of `1`, which was the same as `IN_PROGRESS`
option's position.
- Write a command to prevent position duplicates in the database for the
task's status field.

What I've checked before setting this PR as ready to be reviewed:

- De-duplicating the position solves the issue and it's possible to edit
the field (solves the related issue)
- The upgrade command de-duplicates the position for each workspace.
There are no more DONE options with `position=2`. I ran the upgrade
command on the `database-snapshot-manager` dataset.
- Suspended workspaces aren't fixed

---

To test the script:

```ts
const scannedPositions = new Set();
let biggestPosition = -1;

// Sort options by position for consistent processing
const sortedOptions = [
  { name: 'a', position: 2 },
  { name: 'b', position: 1 },
  { name: 'c', position: 1 },
  { name: 'd', position: 2 },
].sort((a, b) => a.position - b.position);

for (const option of sortedOptions) {
  if (scannedPositions.has(option.position)) {
    option.position = biggestPosition + 1;
  }

  biggestPosition = Math.max(biggestPosition, option.position);
  scannedPositions.add(option.position);
}

console.log('Sorted options:', sortedOptions);
```

Closes https://github.com/twentyhq/twenty/issues/11790
2025-05-13 16:21:47 +00:00
Raphaël BosiandGitHub dfe8011948 Fix side panel click outside (#12011)
Fixes https://github.com/twentyhq/twenty/issues/11988

## Description

The issue came from `RecordTableBodyFocusClickOutsideEffect`.
When clicking outside the table with the side panel opened, two click
outside listeners were triggered: the one which closes the side panel
and the one which leaves the table focus. There was a race condition and
the leave table focus was executed first, changing the hotkey scope. The
side panel closure wasn't executed because the hotkey scope was wrong.

## Fix
Only leave the table focus if the hotkey scope is `TableFocus`


## Videos

Before:


https://github.com/user-attachments/assets/0ea666a6-c212-4b94-b89b-49211d18a13b


After:


https://github.com/user-attachments/assets/2ec6d593-ff65-4cbf-ac92-a0cfbd7dfd8b
2025-05-13 17:56:04 +02:00
Félix MalfaitandGitHub 3efdbed5d1 Fix clickhouse connection 2 (#12010)
Revert changes in #12006 as it might still be handy to have the DB
auto-created (e.g. for test or self-hosting users), but if there is a
permission exception we will just ignore it and assume the database
exist in that case
2025-05-13 16:52:07 +02:00
cec381c4de i18n - translations (#12009)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-13 16:26:27 +02:00
Charles BochetandGitHub e94d90894b Fix relation deletion (#12008)
## What
This PR fixes a regression tied to the new relation format refactoring.
I'm also slightly improving the performance by decreasing the number of
queries.

## Considerations
1. I've started adding an integration test to cover relation creation
and deletion but we are still using the r`elation-metadata.service` to
create a relation and the `field-metadata.service` to delete it. As we
plan to fully deprecate the `relation-metadata.service`, I did not want
to invest into writing test tooling to change it in a few weeks so I've
reverted the test

2. We are still maintaining relationMetadata table up-to-date (so
deleting them when we delete the field). relationMetadata full
deprecation is up coming but I'm waiting a bit so we don't have breaking
changes in 0.53
2025-05-13 16:22:59 +02:00
EtienneandGitHub bed33b00b9 adapt billing banners according to user's permissions (#12005)
closes https://github.com/twentyhq/twenty/issues/11951
2025-05-13 16:18:57 +02:00
Félix MalfaitandGitHub fb615ed201 Remove clickhouse check requiring elevated permissions (#12006)
This check was un-necessary, it will fail after in anycase. Let's leave
it to the user to create the DB
2025-05-13 15:36:55 +02:00
Ajay A AdsuleandGitHub efffac2a1a Deleted view disable delete btn (#11990)
This PR updates the defaultRecordActionConfig for the
SingleRecordActionKeys.DELETE action. A condition
!isSoftDeleteFilterActive was added to the shouldBeRegistered function
to ensure the delete button is only visible when the deleted records
view is not selected.

This prevents the delete button from appearing when viewing deleted
records.

#11974  

![Screenshot 2025-05-12 at 9 41
30 PM](https://github.com/user-attachments/assets/ab7c1f61-d5ab-4315-9f39-50108d11438c)

![Screenshot 2025-05-12 at 9 42
11 PM](https://github.com/user-attachments/assets/82a9843b-4d5e-406c-8186-dce5b7b16bf3)
2025-05-13 14:00:15 +02:00
Charles BochetandGitHub 45d4845b26 Remove old relations (#11993)
This is a first PR to remove old relation logic

Next steps:
- remove relationMetadata from cache
- remove relationMetadata table content and structure
- refactor relationDefinition to leverage field.settings instead
2025-05-13 11:28:22 +02:00
9ed6edc005 Twenty config integration tests + conversion refactor (#11972)
- In this PR the default value of IS_CONFIG_VARIABLES_IN_DB_ENABLED has
been changed to true,
    
- This is my first time writing integration tests, so I’d appreciate a
thorough review. :)
I’ve tried to follow the existing test patterns closely, but there might
be some small mistakes I may have missed.
Also let me know if I have missed any important test cases that should
be tested

UPDATE - 
### Config Value Converter Refactoring
- Created a centralized type transformers registry with bidirectional
validation
- Refactored ConfigValueConverterService to support validation in both
directions:
- Maintained existing DB-to-app conversion behavior
- Added validation for app-to-DB conversion
- Added integration tests to verify validation works in both directions

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-13 13:34:27 +05:30
Lucas BordeauandGitHub df3db85f7f Implemented LINKS and EMAILS sub-field fitering (#11984)
This PR introduces LINKS and EMAILS sub-field filtering. It's mainly
about the implementation of secondaryLinks and additionalEmails
sub-fields, which are treated like additionalPhones.

There's also a refactor on the computeViewRecordGqlOperationFilter, a
big file that becomes very difficult to read and maintain. This PR
breaks it down into multiple smaller utils. There's still work to be
done to clean it as it is a central part of the record filter module,
this PR lays the foundation.
2025-05-12 21:30:53 +02:00
Paul RastoinandGitHub 0fb5ea7d06 Sync-metadata swallow FK_e078063f0cbce9767a0f8ca431d (#11991)
# Introduction
Encountering a blocking issue due to legacy upgrade history in staging
due to relation refactor
For the moment ( release 0.53 ) swallowing
@charlesBochet 

## How to test
```ts
checkout v0.52.11
yarn
database:reset
checkout 0.53
yarn
build server
migrate
upgrade
```
2025-05-12 17:14:45 +00:00
Raphaël BosiandGitHub 4d352cb4e4 Keyboard Navigation and Shortcuts Implementation on the board (#11930)
# Keyboard Navigation and Shortcuts Implementation on the board

This PR implements keyboard navigation and shortcuts for the Record
Board component, enabling users to navigate and interact with board
cards using keyboard inputs.

## Key changes

### Navigation Architecture
- Added `useBoardCardNavigation` hook for directional navigation (arrow
keys)
- Implemented scroll behavior to automatically focus visible cards
- Created card focus/active states with component-level management

### State Management
- Added new component states: `focusedBoardCardIndexesComponentState`,
`activeBoardCardIndexesComponentState`,
`isBoardCardActiveComponentFamilyState`
- Extended index tracking with column/row position indicators
- Create hooks to manage these states

### Hotkey Implementation
- Created new `RecordBoardHotkeyEffect` component for hotkey handling
- Added `BoardHotkeyScope`
- Implemented Escape key handling to clear selections
- Replaced table-specific `TableHotkeyScope` with more generic
`RecordIndexHotkeyScope`. This is because, before, the hotkey scope was
always set to Table inside the page change effect, and we used the table
hotkey scope for board shortcuts, which doesn't make a lot of sense.
Since we don't know upon navigation on which type of view we are
navigating, I introduced this generic hotkey scope which can be used on
the table and on the board.

### Page Navigation Integration
- Modified `PageChangeEffect` to handle both table and board view types
- Added cleanup for board state upon navigating away from record pages

### Component Updates
- Updated `RecordBoardColumn` to track indexes for position-based
navigation
- Added `RecordBoardScrollToFocusedCardEffect` for auto-scrolling to
focused cards
- Added `RecordBoardDeactivateBoardCardEffect` for cleanup

This implementation maintains feature parity with table row navigation
while accounting for the 2D navigation needs of the board view.

## New behaviors

### Arrow keys navigation


https://github.com/user-attachments/assets/929ee00d-2f82-43b9-8cde-f7bc8818052f


### Record selection with X


https://github.com/user-attachments/assets/0b534c4d-2865-43ac-8ba3-09cb8c121f06


### Command + Enter opens the record


https://github.com/user-attachments/assets/0df01d1c-0437-4444-beb1-ce74bcfb91a4


### Escape unselect the records and unfocus the card



https://github.com/user-attachments/assets/e2bb176b-b6f7-49ca-9549-803eb31bfc23
2025-05-12 19:02:14 +02:00
Charles BochetandGitHub 4e39ef832c Fix 0.53 upgrade commands (#11987)
In this PR:
- fixes
[0-53-upgrade-search-vector-on-person-entity.command.ts](https://github.com/twentyhq/twenty/pull/11987/files#diff-d97fb2aefe44ac5d849fb7e29b8eaa1ca7c0f109d1b43fbdf87723b05dd22f58)
small mistake
- adding Cascade DELETE on fieldMetadata.relationTargetObjectMetadataId
(like we have on fieldMetadata.objectMetatadaId)
- enabling IsNewRelationEnabled in 0.53 upgrade
2025-05-12 17:26:35 +02:00
a942642b83 Untitled records for CreatedBy (#11914)
# Display "Soft-Deleted Workspace Members" in Actor Field Display

Reminder of the issue :
<img width="154" alt="Screenshot 2025-05-07 at 12 11 59"
src="https://github.com/user-attachments/assets/168f8743-2684-4d9a-b1a4-e86bb335f7a4"
/>

- `ActorFieldDisplay` component : display soft-deleted members
- `UserService` includes soft-deleted records when fetching workspace
members. This is the tricky part : do we want that for all workspace
members or maybe i could create another property dedicated to workspace
members and softdeleted ones. To be discussed

Result looks like this (we loose the source and the context in this
impleentation)
<img width="114" alt="Screenshot 2025-05-07 at 12 05 28"
src="https://github.com/user-attachments/assets/3cdddd91-454f-4e96-8d6d-6fe671658945"
/>


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


Another way we could also get into :
We could also, when a workspace user is softDeleted, change the current
implementation : we could avoid to delete the ActorMetadata like
CreatedByName (and context and source) in the "Person" table.

It would look more like this
<img width="111" alt="Screenshot 2025-05-07 at 12 06 16"
src="https://github.com/user-attachments/assets/daa4ece2-200a-41f0-ba24-177375c72983"
/>

However, this implementation is requires more work, and IMO harder to
maintain since is decouples completely the record from the workspace
member. This could be an issue in case we want tohard delete a user, or
decide another logic to display the Actor name.

Since the usecase should be pretty rare, I chose the first one but
willing to discuss it

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-05-12 15:54:56 +02:00
EtienneandGitHub 679530020c increase recordCard field hovering zone width + click (recordCard and summaryCard) (#11983)
PR preview


https://github.com/user-attachments/assets/7d90f384-6bee-41d7-9aec-cadb434e7db6



closes https://github.com/twentyhq/twenty/issues/10561
2025-05-12 14:13:59 +02:00
GuillimandGitHub e87c6236ca calendar sync failed (#11970)
# TLDR 
fix bug due to some event properties coming from the google calendar API
containing weird characters like this
"\u0000�4\u000b\u00042��K\u0001�z,\u001cm�",

it made the Postgres select and insert operator fail



## Details
We can have event properties (like cal UID below) encoded in a strange
way. From my research, the character \u0000 comes from `C` language to
signal end of line. It is wrongly interpreted by Postgres so must be
escaped. I decided to remove all possibility of failure with this regex
`[^\x20-\x7E]` basically "any character that is not a printable ASCII
character"

```
[
  "5foijj28qb8smqiafjablo17vd@google.com",
  "\u0011�\"�f�\\\u0019G_=��\u0005]x",
  "?}|��\f}l��+�弴�",
  "%���?t\u0007��n\u001e\u000eY�T<",
  ".\u0011�\u0016�!�\u000eIǹ� ��\u001f",
  "!h\u0004��D�6���h�]E",
  "(�CX]�Q�7�^��n\u0006�",
  "_040000008200E00074C5B7101A82E0080000000070105B958DEFD801000000000000000010000000EA30DB22E888B943A8EE0AD483F8DB35",
  "\t�N�#�D��Ic�h",
  "+�)�H���jJ|Ժ�'�",
  "_040000008200E00074C5B7101A82E0080000000070A54736C6EED8010000000000000000100000006502334AFE61904595C2831FA4391034",
  "_040000008200E00074C5B7101A82E0080000000072C80C3590EFD8010000000000000000100000001BA9FD5B330C1A4D85462AC9D70B9D9D",
  "sg�fvUa:St>-<�d\u0006",
  "\u0017ڦ��_\u001e\u001fGm-1����",
  "_040000008200E00074C5B7101A82E00800000000F0F4F01F4EF0D8010000000000000000100000004C11CE0950C85549B79C456C13987AB8",
  "$�����\u0007V\u0007��\u001e�OLN",
  "_040000008200E00074C5B7101A82E00800000000341DA81151EDD8010000000000000000100000007453CEFB19AA2D4899B17F0BDB000493",
  "_01C756CA-98DC-4799-9F06-883A540A065C",
  "_040000008200E00074C5B7101A82E00800000000919548BBF1EDD80100000000000000001000000050AE1E41F3CD314CA9215F193EBE1D39",
  "_040000008200E00074C5B7101A82E0080000000039CF64D718EDD801000000000000000010000000B3824EF0711436488CB5459BE83733B1",
  "_040000008200E00074C5B7101A82E00800000000C50BDADCB5E4D8010000000000000000100000005B95FE762B2EF84B9C5AC53907B7E5E8",
  "�Spx�\u0003ve��ss�X��",
  "\b���>\u0013̈�ыh��0�",
  "_040000008200E00074C5B7101A82E008000000005BCD492230E8D801000000000000000010000000B243A9CE99E94C4DAD201129A8F2A2F7",
  "_040000008200E00074C5B7101A82E008000000009B540B82D1DCD801000000000000000010000000B4AFC9825D94994AA6C528C953BD3D96",
  "_040000008200E00074C5B7101A82E008000000000D39EABDB7E4D801000000000000000010000000CD07BA2D05E61B47A597EE538ECE8CA5",
  "\u0016���\u0003inv�=O����",
  "4?b�-���\u001c\u0013ת�E�p",
  ">\u0000\u0015-;_�^�W&�p\u001f�",
  "_040000008200E00074C5B7101A82E008000000006258818C85D9D80100000000000000001000000003346C625768FE43AF3F8D09917CA3C9",
  "+K��ٔ�\u0006�\u0018G\u000b\u0000�s\u000e",
  "/\f�\rj�IOD�g脅��",
  "_68d820f9-e2c1-4d9a-bf61-83e4957c8261",
  "xĠ�W4>���t�\u001d���",
  "_040000008200E00074C5B7101A82E008000000003F1F314328E3D8010000000000000000100000002C8DC60F5369F44DA2B066441F882B35",
  "_040000008200E00074C5B7101A82E008000000006DFCC204FDDED80100000000000000001000000046ECD444737D2E4992C349B2EA05637F",
  "_1FF7C1BB-4E1A-485F-ADD0-5C4768601179",
  "_040000008200E00074C5B7101A82E00800000000A0AA1223EFD3D801000000000000000010000000C83B72C2B424944199F3353D1442B27E",
  "_040000008200E00074C5B7101A82E0080000000063D101EB06E4D801000000000000000010000000E489F61C89B8914BA6F8C8A2606405FE",
  "\u0011��f�\"�b���rB�[�",
  ";t��\u001d\u001euDY+T\u001d��v",
]
```



Fixes https://github.com/twentyhq/core-team-issues/issues/946

Fixes
https://twenty-v7.sentry.io/issues/6568530279/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D%20b09d7a84-e6bc-45cf-b3ca-1e6047dddeed&referrer=issue-stream&stream_index=0


### Edit :
Changed the regex to match the chars to remove from 
`[^\x20-\x7E]` to `replace('\u0000', '');`
2025-05-12 14:09:57 +02:00
Baptiste DevessierandGitHub a4656b415c Improve Form Layout + add drag and drop (#11901)
https://github.com/user-attachments/assets/cf542921-9354-4f7b-b6e8-061ebcaa9a9b

Closes https://github.com/twentyhq/core-team-issues/issues/887
Closes https://github.com/twentyhq/core-team-issues/issues/889
Closes https://github.com/twentyhq/core-team-issues/issues/890
2025-05-12 12:09:46 +02:00
EtienneandGitHub ca6e979ead fixes on search (#11955)
In this PR
- enable search by email
- search with ' ' (spaces) string and special characters do not throw
entry error

closes https://github.com/twentyhq/twenty/issues/11447 &
https://github.com/twentyhq/core-team-issues/issues/860
2025-05-12 08:59:10 +00:00
martmullandGitHub 650f8f5963 Revert "Revert "[4/n]: migrate the RESTAPI GET /rest/* to use TwentyORM direc…" (#11349) 2025-05-12 08:32:04 +00:00
1f4d4c5265 fix: z-index conflict between aggregate footer and cell popups (#11973)
https://github.com/user-attachments/assets/06f0e76f-69df-4a34-90ca-8d177744d89b

Closes #11956

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-11 12:24:49 +00:00
8216800a4a Fix workspace relation sync (#11963)
## Context

While deploying the IS_NEW_RELATION_ENABLED (we don't compute relation
based on relationMetadata anymore) to existing workspace, I've tested to
run a sync-metadata post feature flag activation. This has raised two
issues:
- the workspaceMigration generator (which is over-complex and should be
refactored later) for fieldMetadata of type RELATION was not handling
settings update properly ;
- we need to delete existing fieldMetadata corresponding to the UUID
foreignKey as they are not needed anymore. This is handled as a 0.53
upgrade command as 0.53 will also come with the full removal of the old
relation system

---------

Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com>
Co-authored-by: prastoin <paul@twenty.com>
2025-05-09 19:03:39 +02:00
Lucas BordeauandGitHub 3308ba56b2 Implemented ACTOR sub-field filtering (#11957)
This PR implements what's missing for ACTOR sub-field filtering,
filtering on the source sub-field was already working.

We can now filter on name sub-field. 

Since the sub-fields are different types and cannot be filtered both by
text, we consider that a simple filter on ACTOR is filtering on the
source, we have to go to advanced filter to have the name filter
sub-field.
2025-05-09 15:49:04 +00:00
EtienneandGitHub 1c0650fbd3 invert load more and add new (#11962)
closes https://github.com/twentyhq/core-team-issues/issues/847
2025-05-09 13:59:51 +00:00
Lucas BordeauandGitHub 8e07160c84 Implemented PHONES sub-field filtering (#11953)
This PR implements sub-field filtering for the PHONES field type.

What was tricky was to have filtering work correctly on the
additionalPhones sub-field, which is an array of objects and is treated
as a RawJsonFilter. Now that it works for this sub-field, we can
implement the same logic for other similar sub-field like
additionalEmails and secondaryLinks.
2025-05-09 14:32:57 +02:00
d63e53943e i18n - translations (#11950)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-09 11:46:15 +02:00
Lucas BordeauandGitHub afea017c12 Sub-field filtering on ADDRESS type (#11912)
This PR adds what's needed to filter on the ADDRESS sub-fields, notably
the country sub-field, that requires a country multi select component,
which was created in this PR (ObjectFilterDropdownCountrySelect)

This PR refactors the common logic between advanced filter dropdown
field selection logic and view bar filter dropdown field selection
logic, notably in useFilterDropdownSelectableFieldMetadataItems.

There are now new components to identify clearly what's tied to view bar
or advanced filter, it could be further simplified or factorized, but as
it is right now, it's simple enough to be maintained easily even if a
little bit too verbose, which is often the best trade-off we should aim
for.

Improvements : 
- Added the CompositeFieldSubFieldName where needed
- Fixes bug in advanced filter dropdown input
- Fixes dropdown content width bug in advanced filter dropdown input
- Fixes a bug when inputing a Currency filter without a sub-field in
view bar filter dropdown
- Used DropdownMenuSearchInput instead of a custom StyledInput which was
doing exactly the same thing
- Factorized the state setting logic in
useSetAdvancedFilterDropdownStates in an anonymous function
setAdvancedFilterDropdownStates
- Created useSelectFilterFromViewBarFilterDropdown hook to have a more
meaningful and clear logic to abstract what happens when we select a
field to filter in the view bard field select dropdown
- Fixes a bug with advanced filter operand dropdown select which wasn't
modifying the current record filter and creating a stale state.

Fixes https://github.com/twentyhq/core-team-issues/issues/612
2025-05-09 09:32:46 +00:00
Paul RastoinandGitHub 97d44d13ba Fix field currency form settings (#11948)
# Introduction
Close #11947 

From my understanding this `singleQuote` manipulation is legacy due to
front preparing sql queries in some way.

We might wanna standardize this behavior for each `CURRENCIES` usage,
such as within the `ObjectFilterDropdownCurrencySelect` that does not
send nor expect singled quoted encapsulated currencies values.

Created core-team-issues tech issue
https://github.com/twentyhq/core-team-issues/issues/941


## Field creation variables
```json
{
  "input": {
    "field": {
      "defaultValue": {
        "amountMicros": null,
        "currencyCode": "'BYN'"
      },
      "description": "",
      "icon": "IconMoneybag",
      "label": "Maquito",
      "name": "maquito",
      "isLabelSyncedWithName": true,
      "objectMetadataId": "6ef5da20-cf03-49b5-81fe-73aa2c9856a9",
      "type": "CURRENCY"
    }
  }
}
```

## Filtering variables
```json
{
  "filter": {
    "test": {
      "currencyCode": {
        "in": [
          "ALL",
          "AED",
          "AFN",
          "ANG"
        ]
      }
    }
  },
  "orderBy": [
    {
      "position": "AscNullsFirst"
    }
  ]
}
```
2025-05-09 10:57:59 +02:00
Yadong (Adam) ZhangandGitHub 3e9bff22bb fix(ui): added primary blue accent disabled color. (#11945)
Close #11941 

<img width="992" alt="Screenshot 2025-05-08 at 23 23 14"
src="https://github.com/user-attachments/assets/99017653-5a49-4025-983b-04ef8b3fcdcd"
/>
2025-05-09 08:50:45 +02:00
Abdul RahmanandGitHub ff4db92900 fix: flickering when updating relation counts (#11943)
https://github.com/user-attachments/assets/f5a87f1d-7c9f-4351-b43a-8b9b47715f94

Closes #11853
2025-05-09 08:28:20 +02:00
Abdul RahmanandGitHub 1a761e39a9 Fix record name column overlapping table footer on horizontal scroll (#11937)
https://github.com/user-attachments/assets/0a119cc4-2085-4cec-967e-61827f938f24



Closes #11889
2025-05-08 15:16:22 +02:00
Félix MalfaitandGitHub 51f7f55b9d Fix condition for preview apps (#11933)
Followup after https://github.com/twentyhq/twenty/pull/11869

We do want to launch previews on every PR. The label is just there to
force a re-launch
2025-05-07 21:27:53 +02:00
c4482f6be6 fix: avoid passing invalid to prop to DOM (#11931)
Fixed a React warning caused by the to prop being passed to the DOM when
its value was undefined or false. Since to is not a valid HTML
attribute, this triggered a console error. The prop is only used for
styling logic, so I used Emotion’s shouldForwardProp to prevent it from
being passed to the DOM, resolving the issue cleanly.

![Screenshot 2025-05-07 at 10 00
54 PM](https://github.com/user-attachments/assets/0660af7f-df98-46a3-b9f2-2ccc993ac227)

#11850

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-05-07 21:12:15 +02:00
Bhavik AgarwalandGitHub e5888d11e2 Note link's color contrast fixed in dark mode (#11932)
# Note link's color contrast fixed in dark mode

## Key changes

This pull request introduces a minor styling update to the `BlockEditor`
component in `BlockEditor.tsx`. It adds a new style rule to ensure
inline links within the `.bn-inline-content` class are styled with the
theme's blue color.

### Styling updates:

*
[`packages/twenty-front/src/modules/ui/input/editor/components/BlockEditor.tsx`](diffhunk://#diff-4a66ce7d5588bddc6237ac1a3b2949fe4432182bd357114294e8a79d98afce51R119-R122):
Added a CSS rule to style links (`<a>` elements) within
`.bn-inline-content` to use the theme's blue color.

## Issue
fixes #11917 


![image](https://github.com/user-attachments/assets/15a15aa4-be46-4d66-9cfa-55b5d961a6ca)
2025-05-07 21:04:01 +02:00
Félix MalfaitandGitHub 7a4599321b Prepare for schema fusion (#11922)
## Architecture Detail

The goal is to merge the two TypeORM schemas.
Having two schemas prevent doing things like fieldMetadata.workspace in
TypeORM, and create useless debates since there is no clear line (is a
serverlessFunction core or metadata? What about events? etc.)

### Before
```
┌───────────────────┐    ┌───────────────────┐
│  core schema      │    │  metadata schema  │
├───────────────────┤    ├───────────────────┤
│- User             │    │- ObjectMetadata   │
│- Workspace        │    │- FieldMetadata    │
│- UserWorkspace    │    │- RelationMetadata │
│- etc.             │    │- etc.             │
└───────────────────┘    └───────────────────┘
```

### After the Migration
```
┌───────────────────────────────────────────┐
│              engine schema                │
├───────────────────────────────────────────┤
│- User                - ObjectMetadata     │
│- Workspace           - FieldMetadata      │
│- UserWorkspace       - RelationMetadata   │
│- etc.                - etc.               │
└───────────────────────────────────────────┘
```

## Strategy

1. During 0.53 we backfill the *_typeorm_migrations* table of the core
schema with all metadata migrations
2. That way in 0.54 we can move the metadata migrations from the
metadata folder to the core folder. We will also edit the migration
files to reference "core" instead of "metadata". For people doing a
fresh install this will run smoothly and create the tables in Core
directly. For people on an existing install, this migrations will not
run because they were added to the *_typeorm_migrations* in 0.53
3. In 0.55 we will rename "core" to something else (for example
"engine")

Note: if someone jumps version, for example skips to 0.54 directly
without having run 0.53 then this could cause issue. In 0.54 we should
consider gating the "migrate:prod" in the docker file so that it's
controlled and run by the upgrade command (and not run if the command
wasn't executed properly)
2025-05-07 15:13:47 +00:00
WeikoandGitHub 09850c827f Fix codegen and missing track mutation (#11928)
Track mutation was recently renamed TrackAnalytics which broke
apollo.factory.test.ts specs due to signature mismatch. This also broke
other surfaces depending on this such as codegen.
I've also ran codegen since it was a bit outdated
2025-05-07 17:11:00 +02:00
EtienneandGitHub 590aaa1fd4 fix on field relation preview (#11926)
To reproduce : 
Modify object destination to an object with a 'simple' field as
labelIdentifier from data model settings, during creation of a relation
field from an object which has a composite field as labelIdentifier +
Relation type 'has many'

Fix : 
fieldValue and fieldDefinition does not update at the same time (when
object destination is modified) in RelationToManyFieldDisplay component.
Need to better define recordId to be sure fieldValue doesn't point on
previous record.

Tested : 
Relation field creation from Person with switch on relationType and
objectDestination (company/workspaceMember)
Relation field creation from Company with switch on relationType and
objectDestination (pet/person)
closes https://github.com/twentyhq/twenty/issues/11826
2025-05-07 14:46:40 +00:00
Paul RastoinandGitHub a78f3f0d89 Fix duplicated workspace id in activeOrSuspendedCommandRunner options (#11903)
# Introduction
From my understand we're kinda hacking through the options parser by
defining class properties within them whereas we should be consuming the
return type value ? Have no time for this right now

Anw for some reason nestjs-commander enters several time the option
parse which result in duplicating the given workspaceId in the array

Added a Set to fix

close https://github.com/twentyhq/twenty/issues/11707
2025-05-07 14:45:16 +00:00
Paul RastoinandGitHub f129bc0ac4 Upgrade infer commands from APP_VERSION (#11881)
# Introduction
This PR refactors the way we previously manually handled the upgrade
command `versionTo` and `versionFrom` values to be replaced by a
programmatic inferring using the `APP_VERSION` env variable. It raises
new invariant edge cases that are covered by new tests and so on

Please keep in mind that an upgrade will run agnostically of any `patch`
semver value as it should be done only when releasing a `major/minor`
version update
[Related discord
thread](https://discord.com/channels/1130383047699738754/1368953221921505280)

## Testing in local
In order to test in local we have to define an `APP_VERSION` value in
`packages/twenty-server/.env` following semver ( or not 🙃 )

## Logs example
```ts
Computing new Datasource for cacheKey: 20202020-1c25-4d02-bf25-6aeccf7ea419-8 out of 0
query: SELECT * FROM current_schema()
query: SELECT version();
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Initialized upgrade context with:
   - currentVersion (migrating to): 0.53.0
   - fromWorkspaceVersion: 0.52.0
   - 2 commands
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Upgrading workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 from=0.52.0 to=0.53.0 1/2
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Upgrade for workspace 20202020-1c25-4d02-bf25-6aeccf7ea419 ignored as is already at a higher version.
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Running command on workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db 2/2
Computing new Datasource for cacheKey: 3b8e6458-5fc1-4e63-8563-008ccddaa6db-8 out of 0
query: SELECT * FROM current_schema()
query: SELECT version();
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Upgrading workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db from=0.52.0 to=0.53.0 2/2
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Upgrade for workspace 3b8e6458-5fc1-4e63-8563-008ccddaa6db ignored as is already at a higher version.
[Nest] 37872  - 05/06/2025, 4:07:21 PM     LOG [UpgradeCommand] Command completed!
```

## Misc
Related to https://github.com/twentyhq/twenty/issues/11780
2025-05-07 13:48:19 +00:00
Thomas TrompetteandGitHub e96afe444f Create filter action (#11904)
Figma
https://www.figma.com/design/xt8O9mFeLl46C5InWwoMrN/Twenty?node-id=59956-288587&t=Dkp83eigIgb3DO6W-11

Issue
https://github.com/orgs/twentyhq/projects/1/views/3?filterQuery=sprint%3A%40current+assignee%3A%40me&pane=issue&itemId=108202682&issue=twentyhq%7Ccore-team-issues%7C897

- filters will be stored as existing GQL filters. It will avoid
re-building frontend
- `applyFilter` function will take the filter and a JS array in input
and returns the filtered array
- filter action calls the util then returns an empty result and error if
no data in the output array. It will end the workflow gracefully.

Example of action:

```
{
      "id": "9d4aeee9-5b78-4053-9615-c367e901ed71",
      "name": "Filter",
      "type": "FILTER",
      "valid": false,
      "settings": {
        "input": {
          "filter": {
            "employees": {
              "gt": 300,
            },
          }
        }
      }
}
```
2025-05-07 14:52:03 +02:00
MarieandGitHub 463dee3fe6 Remove usages of connectToDataSource and use workspaceDataSource (#11873)
In this PR we are

1. cleaning typeORM service by removing connectToDataSource method
2. using workspaceDataSource instead of mainDataSource when possible,
and replacing raw SQL with workspaceRepository methods to use
2025-05-07 10:42:51 +02:00
Abdul RahmanandGitHub b5bacbbd29 Disable Cell Hover Effect During Row Selection (#11908)
https://github.com/user-attachments/assets/925c02b7-6e34-4bb6-8f9e-2426de57088c



Closes #11878
2025-05-07 09:52:23 +02:00
Félix MalfaitandGitHub 7b78b64bca Update clickhouse tables (#11905)
Following a discussion with @Bonapara - changing the base tables
2025-05-07 09:39:18 +02:00
Cole RichardsonandGitHub 8b796647f9 small Update to what-is-twenty.mdx (#11909)
fixed some grammatical errors. self explanatory
2025-05-07 06:52:31 +02:00
fd8da3d943 i18n - translations (#11902)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-06 18:48:51 +02:00
Raphaël BosiandGitHub c726a7d524 Fix input width (#11897)
Fixes #11742. The bug introduced by
https://github.com/twentyhq/twenty/pull/11536
2025-05-06 18:43:53 +02:00
EtienneandGitHub a2388d2dc7 chunk csv file before preview (#11886)
closes https://github.com/twentyhq/twenty/issues/10971
2025-05-06 17:43:32 +02:00
Paul RastoinandGitHub f2691e53a0 [CI]: Increase status check timeout (#11896)
# Introduction
Some jobs start to fail because they exceed the timeout
Such as this job
https://github.com/twentyhq/twenty/actions/runs/14862320942/job/41730200276?pr=11881
2025-05-06 17:14:58 +02:00
Raphaël BosiandGitHub b3f5a3f75f Record Table Row Navigation (#11879)
# Record Table Row Navigation

This PR improves the table accessibility by adding a row navigation and
new shortcuts to the table. Closes #896.

# Introduce focused active row states on the table

This PR implements the focused and active row states feature for the
record table, allowing users to navigate through the table with keyboard
arrows and providing visual feedback for selection.

## Implementation details:

- Added new component states to track focused and active row positions
and states.

- Implemented dedicated hooks for row state management

- Updated UI styling for active and focused rows:
  - Applied blue border (Adaptive Colors Blue 3)
  - Added highlight background (Accent Quaternary)
  - Added styling for focused rows to clearly indicate selection state

- Added row state cleanup:
- `RecordTableDeactivateRecordTableRowEffect` component to reset states
  - Added row state reset logic upon navigation

## Bug fixes
- Fixed record table unselection in the page change effect
- Fixed a hack introduced by
https://github.com/twentyhq/twenty/pull/8489 which duplicated the last
table column

# Shortcuts

## Arrow keys and J+K navigation


https://github.com/user-attachments/assets/6b46f6b5-cd98-4053-aaef-f8bf2b9584b5


## Record selection with X


https://github.com/user-attachments/assets/44ab7397-e00c-4dfe-8dd1-b3ffc53b3e5f


## Enter allows for cell navigation, Escape goes back to row navigation


https://github.com/user-attachments/assets/890d7e25-2d81-47e3-972f-043a1879b8cc


## Command + Enter opens the record



https://github.com/user-attachments/assets/cf8cdbd5-7cf0-4d78-909f-dc6be88b9e25
2025-05-06 12:52:05 +00:00
f1d658bcb6 Fix: Twenty-website docs same TOC ids #11865 (#11872)
This PR fixes issue https://github.com/twentyhq/twenty/issues/11865.

The highlight heading logic in TOC was checking the heading text which
could be the same for multiple headings.
The ids for these headings were also just the heading texts, leading to
conflict in ids too.

Fix:
- Appended index of the heading item from the list of headings to the id
of the heading. This fixed conflicting ids.
- Used these unique ids to toggle the highlight style.

Behaviour after the fix:


https://github.com/user-attachments/assets/ab3bc205-0b0e-451d-b9cb-4fa852263efc


Edit:
close #11865

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-05-06 14:34:52 +02:00
Thomas TrompetteandGitHub 6810ca0204 Move workflow backfill command to 0.53 (#11892)
As title. It has not been added to 0.52 list of commands
2025-05-06 14:09:18 +02:00
2f85471955 i18n - translations (#11890)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-06 11:46:38 +02:00
ef8b015741 Allow moving columns left/right in Kanban view (#11827)
### Demo


https://github.com/user-attachments/assets/9bc81c33-454d-4581-b06e-dbc0ea79a8dd

Closes #11791

---------

Co-authored-by: prastoin <paul@twenty.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-05-06 11:39:57 +02:00
GuillimandGitHub e92117d556 Critical email sync bug (#11885)
Removing the upsert to avoid the ON CONFLICT
2025-05-06 11:17:27 +02:00
Lucas BordeauandGitHub 9435d525cf Clean up record filter refactor (#11884)
This PR cleans up after the refactor of selected filter state and apply
filter logic on record filter.

Since everything is now using the new
objectFilterDropdownCurrentRecordFilter state to derive the value for
all types, we don't need to maintain states for selected record ids and
selected options and the ViewBarFilterEffect that was initializing them.

Details :
- Removed objectFilterDropdownSelectedRecordIdsComponentState
- Removed objectFilterDropdownSelectedOptionValuesComponentState
- Removed ViewBarFilterEffect
2025-05-06 10:28:20 +02:00
EtienneandGitHub a60711c808 Ej/fix message visibility (#11874)
<img width="257" alt="Screenshot 2025-05-05 at 15 30 09"
src="https://github.com/user-attachments/assets/5a8e18e0-efc5-4521-9c3a-bf73277ecdf9"
/>
<img width="257" alt="Screenshot 2025-05-05 at 15 29 05"
src="https://github.com/user-attachments/assets/c1a784af-a744-497a-b6ce-ec3a9e8b851a"
/>
<img width="257" alt="Screenshot 2025-05-05 at 15 33 06"
src="https://github.com/user-attachments/assets/c5fabd1d-a125-49d7-aade-0a208a0eff95"
/>

related to PR https://github.com/twentyhq/twenty/pull/11840 and issue
https://github.com/twentyhq/twenty/issues/9826
2025-05-05 17:23:27 +02:00
GuillimandGitHub da0c7e679e Blocknote editor fix (#11823)
After reading the blocknote documentation :

- we decided to increase to 100% the lines width
- we decided to reduce as much as possible inner padding
- we decided it's on the parent to decide the padding of the richtext
The two last points are recommended in a discussion on the project
blocknote. This way clicking on padding won't trigger weird behaviour on
Chrome.

Fixes
https://github.com/twentyhq/core-team-issues/issues/827#issuecomment-2842350359
2025-05-05 17:22:49 +02:00
MarieandGitHub a9e73c6340 [permissions] Add permissions check layer in entityManager (#11818)
First and main step of
https://github.com/twentyhq/core-team-issues/issues/747

We are implementing a permission check layer in our custom
WorkspaceEntityManager by overriding all the db-executing methods (this
PR only overrides some as a POC, the rest will be done in the next PR).
Our custom repositories call entity managers under the hood to interact
with the db so this solves the repositories case too.
This is still behind the feature flag IsPermissionsV2Enabled.

In the next PR
- finish overriding all the methods required in WorkspaceEntityManager
- add tests
2025-05-05 14:06:54 +00:00
5f8040af5d Modify Decimal Fields to be treated as number in OpenAPI schema. (#11871)
Closes https://github.com/twentyhq/twenty/issues/10807

## Description
This PR will Modify Decimal Fields to be treated as `number` in OpenAPI
schema.

## Testing
<img width="989" alt="スクリーンショット 2025-05-05 20 49 05"
src="https://github.com/user-attachments/assets/2f120317-5860-4c93-91a2-f521a69a1cd5"
/>
<img width="872" alt="スクリーンショット 2025-05-05 20 49 52"
src="https://github.com/user-attachments/assets/0d319785-e30b-4132-be9e-12ed6f3cc46a"
/>

---------

Co-authored-by: Takuya Kurimoto <takuya004869@gmail.com>
Co-authored-by: prastoin <paul@twenty.com>
2025-05-05 15:48:23 +02:00
Thomas TrompetteandGitHub 6128d660c2 Fix form record picker field (#11817)
- enrich response so the record is available in the step output. Today
this is available in the schema but only the id is set
- make the full record picker clickable instead of the arrow only

<img width="467" alt="Capture d’écran 2025-04-30 à 16 08 04"
src="https://github.com/user-attachments/assets/db74b9a6-7f1d-4e54-bf06-9be3d67ee398"
/>
2025-05-05 12:58:11 +00:00
Paul RastoinandGitHub c9eff401df Preview env dispatch using -paths syntax (#11869)
# Introduction
Using changed-files from a forked repo with `pull_request_target`
results in invalid checkout issue
Used the native paths GitHub Actions syntax to handle workflow
triggering

[Paths
syntax](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onpushpull_requestpull_request_targetpathspaths-ignore)
2025-05-05 14:30:16 +02:00
e5bfca2b1d Fix crash when hiding a column in Kanban view (#11847)
### Problem
When hiding a kanban view column, users encountered the following error:
`Instance id is not provided and cannot be found in context.`

This was caused by the `SelectableListItem` for the "HiddenGroups" menu
item not being wrapped in a `SelectableList`. As a result, the required
context (specifically, the selectableListInstanceId) was missing,
leading to errors in recoil state management.

### Solution
This PR wraps the "HiddenGroups" `SelectableListItem` in its own
`SelectableList` component, providing the necessary context and ensuring
that the component family selectors work as expected.


https://github.com/user-attachments/assets/19e030d0-a28a-4993-b952-99d10b6e7a92

Closes #11828

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-05-05 13:46:00 +02:00
EtienneandGitHub 521e75981a Fix calendar events & messages fetching + fix timeline design (#11840)
Preview : 

<img width="501" alt="Screenshot 2025-05-02 at 16 24 34"
src="https://github.com/user-attachments/assets/0c649df1-0e26-4ddc-8e13-ebd78af7ec09"
/>


Done : 
- Fix getCalendarEventsFromPersonIds and getCalendarEventsFromCompanyId
(include accountOwner check)
- Fix permission check on pre-hook - Pre-hook seems useless, calendar
events are always on METADATA or SHARE_EVERYTHING visibility, else post
hook always has the responsibility of returning the data user can
access. >> To delete or to keep in case other visibility options are
added ?
- Add post hook to secure finOne / findMany calendarEvents resolver
- Update design

To do :
- same on messages (PR to arrive)

closes : https://github.com/twentyhq/twenty/issues/9826
2025-05-05 13:12:16 +02:00
Paul RastoinandGitHub d0d872fdd0 Upgrade guide fix docs (#11867)
# Introduction
Related to https://github.com/twentyhq/twenty/pull/11834
2025-05-05 13:11:10 +02:00
Baptiste DevessierandGitHub 1543c900ae Migrate workflow states to component states (#11773)
- Migrated all workflow Recoil states to component states to isolate
each workflow visualizer instance. The use case of having two workflow
visualizers displayed at the same time appeared recently and will grow
in the near future.
- We chose to use the `recordId` as the value for the `instanceId` of
the component states. Currently, there are a few cases where two
workflows or two workflow runs are rendered at the same time. As a
consequence, relying on the `recordId` is enough for the moment.
- However, there is one case where it's necessary to have a component
state scoped to a workflow visualizer instance: the
`workflowVisualizerStatusState`. This component is tightly coupled to
the `<Reactflow />` component instance rendered in the workflow
visualizer, and it must be set to its default value when the component
first renders. I achieved that by using another component instance
context whose instanceId is an identifier returned by the `useId()` hook
in the Workflow Run Card component.
2025-05-05 10:58:11 +02:00
8b68dce795 i18n - translations (#11863)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-05 10:37:51 +02:00
ee1fe3564a fix: Restoring record results in blank line in TimelineActivity (#11679) (#11856)
Fixes issue #11679 
There were no case of restored so it was defaulting to null thus showing
the blank line

Handled case for restored so it doesn't default to null 

Image shows record restored by the user and restored by other user
![Screenshot 2025-05-03
011257](https://github.com/user-attachments/assets/8b848992-4250-4266-9a3e-1ca89e1a06b8)

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-05-05 10:25:12 +02:00
a570be0ad1 i18n - translations (#11861)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-05-04 14:42:30 +02:00
Félix MalfaitGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
49b7f5255f Update what is being audit logged (#11833)
No need to audit log workflow runs as it's already a form of audit log.
Add more audit log for other objects
Rename MessagingTelemetry to MessagingMonitoring
Merge Analytics and Audit in one (Audit)

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-05-04 14:35:41 +02:00
Matt DrolletteandGitHub b1994f3707 Use correct env var name in podman-compose (#11858)
The example .env file uses `PG_DATABASE_PASSWORD` so this makes it
consistent. Currently, the podman-compose directions will fail on first
run unless you manually change the env var name.
2025-05-04 12:23:02 +02:00
EtienneandGitHub 9d5f4bf8fd fix relation creation bug (#11848)
Context : In `RelationToOneFieldDisplay`, the `objectNameSingular` used
for the chip calculation was incorrect - it was using the value from the
opposite side of the relationship. Then, labelIdentifier based on
composite fields were causing errors (People and WorkspaceMembers with
name)


<img width="300" alt="Screenshot 2025-05-03 at 08 03 46"
src="https://github.com/user-attachments/assets/8d034700-5244-4b1b-978e-f77ae78b6ceb"
/>


Tested everywhere FieldDisplay is used. 
Tested for each both relation type. 

closes https://github.com/twentyhq/twenty/issues/11826
2025-05-03 06:21:33 +00:00
Paul RastoinandGitHub ea0f45e782 Scope permissions to dispatch reusable workflow invokation (#11843)
# Introduction

Fixes `preview-dispatch` for external contributors such as this run 
FAILING =
https://github.com/twentyhq/twenty/actions/runs/14796579485/job/41545030774
NOW SUCCEEDING =
https://github.com/twentyhq/twenty/actions/runs/14797811684?pr=11827
2025-05-02 17:32:49 +02:00
Lucas BordeauandGitHub 5946b37712 Refactored object filter dropdown input state management (#11838)
This PR refactors the generic module object dropdown filter input.

We have multiple components for each filter type and each one was using
selectedFilterState and the applyRecordFilter hook to read and set its
value.

The main issue was that each component was forced to pass every property
of a RecordFilter to applyRecordFilter to only modify the value
property, thus creating a lot of unnecessary dependencies and tight
coupling between every component and hook that used the record filters.

Now we have each component only reading from a new
objectFilterDropdownCurrentRecordFilterComponentState, scoped to a
ObjectFilterDropdownComponentInstanceContext, thus whether we're in a
view bar dropdown, an editable filter chip dropdown or an advanced
filter dropdown, we know where to read the filter value from.

This component state might even be simplified by only storing the record
filter id, thus avoiding having to synchronize this state with its
counterpart in currentRecordFilterComponentState, but we should try
after the main refactor effort, as those two states aren't in the same
instance context.

We implement a new applyObjectFilterDropdownFilterValue hook to handle
the value setting from an object filter dropdown input component.
There's also a new useApplyObjectFilterDropdownOperand for doing the
same but for operand.

Another important thing that had to be done to keep a synchronous code
path was to set the states of each advanced filter row at the advanced
filter dropdown onOpen event, using useSetAdvancedFilterDropdownStates.

Finally we remove : useApplyRecordFilter, useSelectFilterUsedInDropdown
and selectedFilterComponentState which were making all of this zone
difficult to work with.

Closes https://github.com/twentyhq/core-team-issues/issues/718
Closes https://github.com/twentyhq/core-team-issues/issues/720
2025-05-02 17:28:45 +02:00
Abdul RahmanandGitHub aa2b27dcbe Fix unwanted right padding in Options view menu (#11841)
<img width="235" alt="Screenshot 2025-05-02 at 7 46 04 PM"
src="https://github.com/user-attachments/assets/94275278-ff14-44fd-a09a-776755ad1fa8"
/>

Closes #11839
2025-05-02 16:51:15 +02:00
Paul RastoinandGitHub abc05fafd7 Redis max memory limit and eviction policy (#11836)
# Introduction
Redis [eviction
policy](https://redis.io/docs/latest/operate/rs/databases/memory-performance/eviction-policy/)
and [Key
eviction](https://redis.io/docs/latest/develop/reference/eviction/)
[Bullmq eviction
recommendations](https://docs.bullmq.io/guide/going-to-production#max-memory-policy)


We might need a dedicated bullmq redis instance, as sharing
engine/metadata keys and bull will someday become problematic

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

About to open a PR for our internal IaC

Ps: Did not set a `--maxmemory` that could be leading to undetermined
OOOM errors at runtime. Should be user provided or should define a
default value ?
2025-05-02 16:40:56 +02:00
Gitesh SarvaiyaandGitHub 48011ac012 fix: do not report EmailNotVerifiedError to Sentry (#11753) (#11835)
This PR prevents EmailNotVerifiedError from being reported to Sentry, as
discussed in issue #11753.

edit:
close #11753
2025-05-02 15:35:05 +02:00
Paul RastoinandGitHub 9a504606b8 Migrate/upgrade every time dockerfile entrypoint.sh (#11834)
# Introduction
`upgrade` and `migrate` are not run every time even, but only once on
database creation, tho we're suggesting users they do as not requiring
manual run anymore since `0.50`

close https://github.com/twentyhq/twenty/issues/11671
2025-05-02 14:35:45 +02:00
Paul RastoinandGitHub 3e1b4ace37 Standardize isDefined usage for metadata version assertions (#11829)
# Introduction
`!value` is risky as `!falsy` would return `true`
2025-05-02 11:07:12 +02:00
9df4778954 Fix: Reset password flow fails when user is signed in (#11811)
### Demo


https://github.com/user-attachments/assets/9589c7cc-f6ba-484a-b002-615c11a92729

Note: For the demo video, I hardcoded the email and manually set the
isTokenValid state to true.

Closes #11689

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: prastoin <paul@twenty.com>
2025-05-02 10:04:44 +02:00
Félix MalfaitandGitHub 8c3a2d8640 Verify seed users and change AppleCar password (#11825)
isEmailVerified was set to false which was annoying in the staging
environment

Also updated password for tim@apple.dev from AppleCar2025 to just
tim@apple.dev since the joke is outdated
2025-04-30 16:59:13 +00:00
Paul RastoinandGitHub 17334f8800 Fix undefined read attempt (#11816)
# Introduction
Followup of https://github.com/twentyhq/twenty/pull/11784
Again some propaganda for the
[noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig/#noUncheckedIndexedAccess)
that involved this @charlesBochet 👀
That's very risky to have this setup to false especially in the backend
regarding the twenty-server metadata nature

Also suggested that we do some integration testing ( e2e nestsJs tests )
on a related endpoint that could related we always retrieve the same
form result output

We could also do some unit testing of the method but like the idea to
ship it through the api itself
2025-04-30 17:58:27 +02:00
EtienneandGitHub c657caf74f force cache refresh for views after new object creation (#11806)
**Context** 
When creating a new object, it creates the "All ...." view associated.
After new object is created, in `PrefetchRunViewQueryEffect`,
findManyViews returns cached results WITHOUT the new view.

git bisect - regression introduced with
https://github.com/twentyhq/twenty/pull/10272

**Attempt** : Update to 'network-only' fetch policy in
`PrefetchRunViewQueryEffect` -> not working on useQuery apollo hook (🤯)
: query is handle by cache and not network

**Solution** 
Based on pattern used for view creation
(`useCreateViewFromCurrentView`), refreshing the view cache with a
`useLazyFindManyRecords` solves the issue. Then, `prefetchViewsState` is
updated in `PrefetchRunViewQueryEffect`


closes : https://github.com/twentyhq/core-team-issues/issues/845
2025-04-30 17:54:48 +02:00
EtienneandGitHub 6b9128d1ae fix rich text focus (#11821)
Before 


https://github.com/user-attachments/assets/419227fb-fc0e-4d6e-b89a-932b4b76666f

After


https://github.com/user-attachments/assets/e4db323c-2f98-46f6-84e7-8b9bb452e900


Tested in command Menu + table cell edit mode + "plain text" command
menu
2025-04-30 17:28:12 +02:00
4ce7834f94 i18n - translations (#11822)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-30 17:20:54 +02:00
martmullandGitHub 849a35955a 866 refactor cron trigger only one cron each minutes triggers all cron triggers (#11809)
<img width="1123" alt="image"
src="https://github.com/user-attachments/assets/75447922-81dd-4cfc-805d-f511f73cc778"
/>
2025-04-30 17:08:47 +02:00
GuillimandGitHub 357649db95 fix-discord-timeline (#11784)
In some cases, the person is undefined so we fallback on the
workspacemember, and sometimes he is missing the firstname/lastname.

Not sure how this can happen, but one user experiencd such a thing so
better to catch this


![image](https://github.com/user-attachments/assets/c91445fe-365e-4fc9-bf14-69f71d344aa7)

fix https://discord.com/channels/1130383047699738754/1366145144838951022

close https://github.com/twentyhq/core-team-issues/issues/918
2025-04-30 15:11:00 +02:00
Lucas BordeauandGitHub 0439b96eca Implement new parallel code path for object filter dropdown current record filter (#11807)
This PR implements a new clean parallel code path for handling the
filter manipulated in an object filter dropdown.

Remember that the object filter dropdown module is the generic, shared
module, that must be vertically implemented in those places : view bar
filter button, record table column header cell, view bar details filter
chip.

So here we implement, just for the text filter input (for example a
FULL_NAME field type), a new parallel code path logic, that runs on a
new state : objectFilterDropdownCurrentRecordFilterState

We still update the selectedFilter state, that is very close to the new
objectFilterDropdownCurrentRecordFilterState, but in order to be
cautious, and allow us to refactor incrementally, we implement a new
parallel code path and let the rest run on selectedFilterState for now.

The new way of working with the filter in the object filter dropdown,
includes smaller and more specific hooks :
- useApplyObjectFilterDropdownFilterValue instead of applyRecordFilter
which API generates a lot of tech debt
- useObjectFilterDropdownFilterValue to get the current value (might be
later removed if too thin)
- useUpsertObjectFilterDropdownCurrentFilter, to abstract a bit some
duplicated logic in useApplyObjectFilterDropdownFilterValue
- useCreateRecordFilterFromObjectFilterDropdownCurrentStates which
differs from the existing
useCreateEmptyRecordFilterFromFieldMetadataItem in that it uses the
current states instead of creating an empty filter with default values.
Those two logics are still very confusing and duplicated everywhere,
creating specific hooks makes it clear now.

This PR shouldn't cause any change in the behavior of the filtering
feature.

Fixes https://github.com/twentyhq/core-team-issues/issues/717
2025-04-30 14:55:37 +02:00
Félix MalfaitGitHubCopilotgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
cb513bc7a8 Set default locale according to browser locale (#11805)
We didn't get much complaints on Localization so I guess we can expand
it more and make it the default behavior to use the browser's locale
when you signup

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-30 13:11:40 +02:00
Félix MalfaitandGitHub e55ff5ac4a Change workflow dispatch permissions (#11812)
It seems that content: write is needed so that external contributors can
dispatch workflows
2025-04-30 13:06:57 +02:00
Félix MalfaitandGitHub 6343eaeb4f Change workflow preview env to pull_request_target (#11810)
It didn't work with external contributors
2025-04-30 12:31:56 +02:00
Abdul RahmanandGitHub 36ddf48ef0 Fix ⌘A selecting records instead of input text when creating a new view (#11783)
### Demo

https://github.com/user-attachments/assets/772e5b45-f55d-4d5f-9256-5a325b027d5d

Closes #11677
2025-04-30 09:40:25 +02:00
ea25498625 Fix dragging behavior below the last card when dragging below the new CTA button (#11781)
- Fixed an issue where dragging an item below the last card didn't work
when the card was dragged below the new CTA button (`destination.index
=== items.length` case).
- Moved the "new record" button outside of the draggable list

### Demo

https://github.com/user-attachments/assets/370f2c1f-4bb2-403b-b8ed-4afda064c98d

Closes #10197

---------

Co-authored-by: prastoin <paul@twenty.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-30 09:34:56 +02:00
e6c1b70d9c i18n - translations (#11801)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-30 09:20:32 +02:00
e957b1acd6 Twenty config admin panel integration (#11755)
closes https://github.com/twentyhq/core-team-issues/issues/761
closes https://github.com/twentyhq/core-team-issues/issues/762

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-30 09:12:59 +02:00
842367f7bb i18n - translations (#11800)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-29 18:48:53 +02:00
69f92a697b i18n - translations (#11799)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-29 18:37:01 +02:00
2367ffd452 i18n - translations (#11798)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-29 18:21:20 +02:00
Thomas des FrancsGitHubFélix Malfaitgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
df95ce9ed8 Updated several emails template styles (#11797)
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-29 18:08:45 +02:00
Lucas BordeauandGitHub d52cb26599 Refactored ObjectFilterDropdown into ViewBarFilterDropdown (#11794)
This PR refactors the non-generic part around ObjectFilterDropdown which
has been left in statu quo for months.

It also removes unused components. 

Overall this PR is doing renaming and it re-organizes files into their
relevant modules.

This clarifies a lot what's at the intersection between
object-filter-dropdown and views modules.

This PR was originally about removing any remaining useEffect around
ObjectFilterDropdown but there wasn't any.

## Details

### Removed unused files

- GenericEntityFilterChip
- SingleEntityObjectFilterDropdownButton (was used for the Task/Note
standalone page which doesn't exist anymore)

### Re-organized non-generic components into ViewBarFilterDropdown

- Use VIEW_BAR_FILTER_DROPDOWN_ID instead of OBJECT_FILTER_DROPDOWN_ID
- Use FILTER_FIELD_LIST_ID for selectable list
- Refactored ObjectFilterDropdownButton into a simple
ViewBarFilterDropdown
- Renamed MultipleFiltersDropdownContent to ViewBarFilterDropdownContent
- Renamed MultipleFiltersButton to ViewBarFilterButton
- Integrated MultipleFiltersDropdownButton to ViewBarFilterDropdown
- Renamed AdvancedFilterButton to ViewBarDetailsAddFilterButton

### Tests 

Fixed storybook test for ViewBarFilterDrodpown
2025-04-29 18:05:12 +02:00
Thomas TrompetteandGitHub d8b2e1fb34 Start using next step ids (#11683)
- update workflow executor
- update next step ids on step creation/deletion
- use these in workflow run
- use these in variables
2025-04-29 16:29:25 +02:00
Baptiste DevessierandGitHub 19f46a0091 Fix e2e tests (#11792) 2025-04-29 15:51:59 +02:00
Thomas TrompetteandGitHub fef627b7c2 Fix output schema type not defined (#11788)
Fixes https://github.com/twentyhq/twenty/issues/11778
2025-04-29 11:29:11 +00:00
MarieandGitHub 2482271545 Fix filter with empty field (#11787)
Attempt to fix https://github.com/twentyhq/core-team-issues/issues/899

Could not reproduce but that's the only place in the code where I found
that we build filters as such, with values for "in" being equal to
select options and not recordIds, as it seems to be the case from the
sentries (ex:
<img width="174" alt="Capture d’écran 2025-04-29 à 11 13 56"
src="https://github.com/user-attachments/assets/a0b62de1-fe23-4394-9f86-a205ee32b56c"
/>
)
2025-04-29 09:56:14 +00:00
Lucas BordeauandGitHub fda793ced2 Fix formatDateString test (#11786)
This PR fixes a broken test that makes the CI crash.

This is due to the library `date-fns` which now doesn't use the word
"about" in its relative date formatting, if we're not precisely on minus
2 months, which can change for example today the 29th of April, where
the 29th of February doesn't exist.

So instead of using months and falling into hard to test cases, we use
days instead, which is an easy and predictable relative computation.
2025-04-29 11:45:58 +02:00
GuillimandGitHub 4833ee2914 fix-default-picture-url (#11779)
Fixing the default avatar picture in /settings/profile
2025-04-29 10:30:05 +02:00
MarieandGitHub 23d71915f6 Improve metadata version caching (#11775)
Investigating https://github.com/twentyhq/core-team-issues/issues/756, I
found that the error actually stemmed from "Object metadata collection
not found" error.

While this is planned to be fixed by metadata performance improvements
(as stated in [sentry-boss
doc](https://docs.google.com/document/d/1ytbC5W6ZFUSJ3PoJ4IfKi2IehKZYw65mqCnc24aP4RM/edit?tab=t.0)
in "known issues"), I tried some easy improvements to reduce the number
of errors.
2025-04-29 09:53:19 +02:00
Raphaël BosiandGitHub 7be56862e4 Fix object metadata not found for id (#11777)
Fixes https://github.com/twentyhq/twenty/issues/11668

Fixed an error due to falling back to the main context store object
metadata when the one in the context store wasn't defined.

When closing the command menu, the
`contextStoreCurrentObjectMetadataItemIdComponentState` is reset, but
the ActionMenuContextProvider was falling back to the main context store
object metadata id, so the action components were mounted. But they
still tried to access the
`contextStoreCurrentObjectMetadataItemIdComponentState` which is
`undefined`, which lead to an error being thrown.

Fix:
- Removed the fallback to the main context store object metadata item
2025-04-28 18:18:15 +02:00
Lucas BordeauandGitHub 7563b8b919 Refactored editable filter chip dropdown opening (#11765)
This PR is refactoring a part of the ongoing filter refactor that was
blocking other refactor in that area.

Precisely, the dropdown filter that was used with the editable filter
chip was initialized by two conflicting useEffect, causing many unwanted
and hard to tackle bugs when modifying other places in the code that
used the same dropdown.

We also remove a difficult to maintain pattern around
onToggleColumnFilterComponentState, which was storing a click handler in
a state, we want to avoid this pattern.

The hook useHandleToggleColumnFilter is also removed and replaced by
useOpenRecordFilterChipFromTableHeader.

The code is now synchronous and starts from the user click event that is
triggered on a table cell header filter button click.

Also : 

- Created a useSetEditableFilterChipDropdownStates that allows to
separate the code path of filter chip dropdown from the code path of
view bar global filter dropdown (will be continued in another refactor)
- Added useCreateEmptyFilterFromFieldMetadataItem to abstract empty
filter creation when opening a filter dropdown (will be used for other
refactor)
- Created a useOpenDropdownFromOutside hook that will also be used for
other refactor on filter
- Deleted EditableFilterDropdownButtonEffect
- Removed call to ViewBarFilterEffect (will be completely removed in
other refactors)
2025-04-28 17:36:48 +02:00
Raphaël BosiandGitHub 6cf44ef3c2 Fix open record in menu (#11772)
Fix open record in menu
2025-04-28 16:39:44 +02:00
Thomas TrompetteandGitHub b182a676d7 Fix next step ids backfill command (#11769)
Twenty prod DB has been exported for testing.

Main updates:
- do not process workflow runs with less than 2 steps. Nothing to do.
- update runs by batches of 500. Will avoid java heap space issue
- add more logs
2025-04-28 16:24:15 +02:00
MarieGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
0881e35d64 Throw error if attempting to open RecordPage without recordId (#11768)
Closes https://github.com/twentyhq/core-team-issues/issues/857

The issue was caused by the fact that the preview chip was accidentally
made clickable while not linked to any record id:
<img width="763" alt="Capture d’écran 2025-04-28 à 15 17 32"
src="https://github.com/user-attachments/assets/c1d9bf61-edcb-442f-a914-eccc627ee190"
/>
this was fixed by [this
PR](https://github.com/twentyhq/twenty/pull/11745) (@etiennejouan)

It was causing the side panel to open while the record id was empty,
while this recordId is used in query filters (as it should be to fetch
record data), leading the queries to fail.
Let's early return with an error instead as it does not make sense to
open the record page with an empty recordId.

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-28 13:36:19 +00:00
EtienneandGitHub 2586d0ec4f fix workflow chips not clickable (#11767)
bug introduced in this PR https://github.com/twentyhq/twenty/pull/1174
2025-04-28 15:30:26 +02:00
14afa57699 i18n - translations (#11758)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-27 19:01:13 +02:00
Abdul RahmanandGitHub 902cef78a1 Add Logout Confirmation Popup When Changing Workspace Subdomain (#11756)
This PR implements a confirmation popup on the Domain settings page when
a user attempts to save a subdomain change.
- When the user saves the updated subdomain, a confirmation modal is
shown.
- The modal informs the user that changing the subdomain will log them
and all other users out.
- If the user confirms, the subdomain change proceeds as normal.
- If the user cancels, the update is aborted and no changes are made.

### Demo


https://github.com/user-attachments/assets/dcea51c8-ffd2-40ca-bc75-0c0228df5344


Related Issue
Closes #11741
2025-04-27 18:47:06 +02:00
a15b87649a Twenty config core implementation (#11595)
closes https://github.com/twentyhq/core-team-issues/issues/760

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-26 09:21:59 +02:00
Félix MalfaitandGitHub bb8fa02899 Remove server preconnect (#11752)
Fixes #11738
2025-04-26 08:23:28 +02:00
7752b8b06f i18n - translations (#11750)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-25 19:45:48 +02:00
Lucas BordeauandGitHub 50cb32d122 Implement sub-field filtering on CURRENCY field type (#11726)
This PR implements sub-field filtering on CURRENCY field type and
improves many related zones.

- Created a ObjectFilterDropdownCurrencySelect dropdown component for
filtering on multiple currencies
- Added currencyCode sub-field to CurrencyFilter type
- Created getDefaultSubFieldNameForCompositeFilterableFieldType to avoid
situation where we don't have any sub field name in sub field filtering
situations.
- Implemented filtering for currencyCode in
computeFilterRecordGqlOperationFilter
- Implemented CURRENCY type in getRecordFilterOperands
- Implemented isMatchingCurrencyFilter for using in
isRecordMatchingFilter for proper optimistic rendering
- Created turnCurrencyIntoSelectableItem to help
ObjectFilterDropdownCurrencySelect

Testing : 
- Added test for currency sub fields in getOperandsForFilterType
- Completely reworked isMatchingCurrencyFilter test

Improvements : 
- Created a unique CURRENCIES constant to avoid re-creating it at
various places
- Derive the type FilterableFieldType from a constant array
FILTERABLE_FIELD_TYPES, so it's easier to work with
- Added areCompositeTypeSubFieldsFilterable
- Fixed a bug with empty value '[]' that was preventing the auto-removal
of a filter chip

Miscellaneous : 
- Created isExpectedSubFieldName util to do a type-safe check of a
subFieldName
- Better naming : renamed isCompositeField to isCompositeFieldType
- Created isCompositeTypeFilterableWithAny to specify which field types
are filterable by any sub field
- Better naming : renamed
ObjectFilterDropdownFilterSelectCompositeFieldSubMenu to
ObjectFilterDropdownSubFieldSelect
- Better naming : renamed ObjectFilterDropdownFilterSelect to
ObjectFilterDropdownFieldSelect
- Created isEmptinessOperand util instead of duplicating the same
hard-coded check in multiple places
- Better naming : used subFieldName instead of compositeFieldName for
consistency
- UseEffect removal : removed unnecessary useEffect in
MultipleSelectDropdown

Fixes a bug where Empty and Not weren't appearing in filter chip in
particular cases
Fixes https://github.com/twentyhq/core-team-issues/issues/498
Fixes https://github.com/twentyhq/twenty/issues/7558
2025-04-25 17:33:00 +00:00
f201091c68 512 Ability to navigate dropdown menus with keyboard (#11735)
# Ability to navigate dropdown menus with keyboard

The aim of this PR is to improve accessibility by allowing the user to
navigate inside the dropdown menus with the keyboard.
This PR refactors the `SelectableList` and `SelectableListItem`
components to move the Enter event handling responsibility from
`SelectableList` to the individual `SelectableListItem` components.
Closes [512](https://github.com/twentyhq/core-team-issues/issues/512)

## Key Changes:
- All dropdowns are now navigable with arrow keys

## Technical Implementation:
- Each `SelectableListItem` now has direct access to its own `Enter` key
handler, improving component encapsulation
- Removed the central `Enter` key handler logic from `SelectableList`
- Added `SelectableList` and `SelectableListItem` to all `Dropdown`
components inside the app
- Updated all component implementations to adapt to the new pattern:
  - Action menu components (`ActionDropdownItem`, `ActionListItem`)
  - Command menu components
  - Object filter, sort and options dropdowns
  - Record picker components
  - Select components

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-04-25 18:55:39 +02:00
0b1b81429e fix relation fields preview in settings (#11745)
Fixes :
- display relation fields in preview settings
- display note and task relation field in preview settings - 
- fix design (align and background color)

closes https://github.com/twentyhq/twenty/issues/7084

---------

Co-authored-by: guillim <guigloo@msn.com>
2025-04-25 18:26:27 +02:00
MarieGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
11d9d964cc Add upgrade instructions since v0.50.0 (#11748)
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-25 18:22:59 +02:00
GuillimandGitHub 95808b06b9 Messaging-logging (#11723)
parseBatchResponse:
we need more logs to understand why we have some empty repsonse in the
body.

For anothe PR:  
~~UNKNOWN_NETWORK_ERROR : moving from handleUnknownException to
handleTemporaryException. This is important since in the logs I saw "The
service is currently unavailable" which makes me think we should handle
this type of error with as temporary~~
2025-04-25 18:01:53 +02:00
Félix MalfaitandGitHub dd446ef441 Fix CSV upload (#11749)
I inadvertently broke the upload button on the CSV import
2025-04-25 17:49:50 +02:00
Thomas des FrancsandGitHub 904558e7bb 0.52.0 changelog (#11743) 2025-04-25 17:20:30 +02:00
Raphaël BosiandGitHub 5207836566 Table hover and click outside fixes (#11737)
# Table hover and click outside fixes

This PR improves table interaction behavior by refining cell hover
states and click-outside handling in the record table component.

## Changes

### Click Outside Handling
- Removed conditional rendering of
`RecordTableBodyFocusClickOutsideEffect`

### Hover State Management
Implemented hover state cleanup in multiple components:
- Added `recordTableHoverPosition` state reset in `useLeaveTableFocus`
hook
- Integrated mouse leave handler in `RecordTableBodyDroppable` to clear
hover position

### Fixes double focus bug
- Reset the focus and the hover when the table data changes

## Videos

### Before


https://github.com/user-attachments/assets/f815b65c-c545-4841-a0d9-04c58771e69f

### After


https://github.com/user-attachments/assets/046cc7df-18b8-46ca-b2cc-bdfa3125311b
2025-04-25 16:50:48 +02:00
Félix MalfaitandGitHub 535a8d4410 Fix workflow preview environment repository dispatch (#11739)
This is hard to test without merging PRs unfortunately

Goal of this PR is to replace the action I had introduced since there
was already a similar one in the codebase
2025-04-25 15:52:12 +02:00
Félix MalfaitandGitHub 3fc498dba7 Attempt to add preview environments (#11734)
Just doing a quick test
2025-04-25 15:42:40 +02:00
GuillimandGitHub 1ff9f35b35 Record name missing when being created from a filter (#11733)
name of record not appearing when being created from a filter

Before :  
<img width="223" alt="Screenshot 2025-04-25 at 10 48 27"
src="https://github.com/user-attachments/assets/e3c7cc05-8664-4c14-bcaa-d5b045eb8311"
/>

After :  
<img width="236" alt="Screenshot 2025-04-25 at 10 48 53"
src="https://github.com/user-attachments/assets/778e02e0-0451-4125-b13e-0c2ac222ef41"
/>
2025-04-25 12:59:15 +00:00
Félix MalfaitandGitHub c66b7afefb Update cache policy (#11732)
I couldn't reproduce
https://github.com/twentyhq/twenty/issues/9299#issuecomment-2576868142
anymore

Closes #4914
2025-04-25 11:18:48 +02:00
Charles BochetandGitHub 0c8eb149e6 Refactor new relation sync (#11711)
In this PR:
- this should fix the sync metadata for new relation system

This goes with the recent PR:
https://github.com/twentyhq/twenty/pull/11725

What we want:
- ONE_TO_MANY relations should have no joinColumn and no onDelete
- MANY_TO_ONE should have both
2025-04-25 01:02:49 +02:00
9fb7ef5d47 Automatically Apply Values on Filtered Views (#11717)
Issue : When I create a task in the "Assigned to me" task view, it will
disappear from the view because the Assignee field isn't automatically
populated.

Solution :
We created a "buildRecordInputFromFilters" funciron that will convert
filtered into their corresponding values for the input.


Fixes https://github.com/twentyhq/core-team-issues/issues/708

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-24 19:02:03 +02:00
martmullandGitHub 4d7dbb1991 Fix missing on delete cascade for relation (#11725)
Follow up from https://github.com/twentyhq/twenty/pull/10217
Adding onDelete action on Many_to_one sides
2025-04-24 18:32:14 +02:00
c0df96b383 i18n - translations (#11727)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-24 18:21:21 +02:00
MarieandGitHub e750ef28a1 [permission] Override query builders db-executing methods (#11714)
closes https://github.com/twentyhq/core-team-issues/issues/843
2025-04-24 18:20:21 +02:00
WeikoandGitHub e55ecb4dcd object level override form (#11672) 2025-04-24 18:15:43 +02:00
Baptiste DevessierandGitHub 48e2581581 Stop persisting JSON fields in workflow runs (#11715)
## Before


https://github.com/user-attachments/assets/903c5771-ac15-49a6-9175-40c8b027655b

## After


https://github.com/user-attachments/assets/26aedf77-31ac-439a-a39c-57a274010f3f
2025-04-24 17:02:26 +02:00
6a75420285 i18n - translations (#11724)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-24 17:01:09 +02:00
Paul RastoinandGitHub 8b63d45b70 Fix missing ObjectRecordId param (#11721)
# Introduction
Fixes https://github.com/twentyhq/twenty/issues/11718

From having
[noUncheckedIndexedAccess](https://www.typescriptlang.org/tsconfig/#noUncheckedIndexedAccess)
set to false we have a flakiness resulting in a such bug right here as
the below operation can return `undefined` but not type as it should:
```ts
  const recordId = allRecordIds[position.row];
```

About to create a Tech project about the topic, activating the flag ends
in 1500 typescript erros from the style solution compilation ( which
means can contains several duplicated errors )
2025-04-24 16:49:56 +02:00
Félix MalfaitandGitHub 5343dd62d6 Update readme with partner logos (#11722)
Recognize the role of Greptile/Sentry/Crowdin/Chromatic which give
generous open source plans + some cleanup
2025-04-24 16:09:43 +02:00
Raphaël BosiandGitHub 4a61956087 Fixes on record title input (#11720)
- Fix record creation title cell opening
- Fix full name input hotkey scope
2025-04-24 15:29:21 +02:00
Paul RastoinandGitHub b545ebc53b Hide toggle isSyncLabelName for standardObject field edition (#11713)
# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/880
2025-04-24 13:51:10 +02:00
Baptiste DevessierandGitHub cc211550ae Workflow runs in side panel (#11669)
Vidéo explicative : https://share.cleanshot.com/VsvWknlW

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

Known issues to fix later:

- https://github.com/twentyhq/core-team-issues/issues/879
2025-04-24 11:33:17 +02:00
Paul RastoinandGitHub 0083569606 Fix object model settings label synchronization (#11708)
# Introduction
Closes https://github.com/twentyhq/twenty/issues/11150
2025-04-24 10:58:59 +02:00
EtienneandGitHub ccc6d968aa update price on subscription - command (#11698) 2025-04-24 09:32:03 +02:00
Félix MalfaitandGitHub 0b729cb000 Fix json type in clickhouse migrations (#11710)
Settings in clickhouse are only set for the duration of the session so
we need to keep the same client
2025-04-23 22:08:52 +02:00
Félix MalfaitandGitHub cec17a3ebe Fix clickhouse migration not in dist (#11709)
Clickhouse migrations were not correctly copied to the dist folder (for
command yarn clickhouse:migrate:prod)
2025-04-23 21:16:30 +02:00
2090 changed files with 60774 additions and 21579 deletions
+1 -1
View File
@@ -39,7 +39,7 @@ jobs:
run: npx nx build twenty-chrome-extension
ci-chrome-extension-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, chrome-extension-build]
steps:
+1 -1
View File
@@ -124,7 +124,7 @@ jobs:
retention-days: 30
ci-e2e-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, test]
steps:
+1 -1
View File
@@ -53,7 +53,7 @@ jobs:
kill $SERVER_PID
ci-emails-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: depot-ubuntu-24.04-8
needs: [changed-files-check, emails-test]
steps:
+1 -1
View File
@@ -189,7 +189,7 @@ jobs:
key: ${{ steps.restore-task-cache.outputs.cache-primary-key }}
ci-front-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: depot-ubuntu-24.04-8
needs:
[
+1 -1
View File
@@ -232,7 +232,7 @@ jobs:
path: reset-logs.log
ci-server-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: depot-ubuntu-24.04-8
needs: [changed-files-check, server-setup, server-test, server-integration-test]
steps:
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
tasks: ${{ matrix.task }}
ci-shared-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, shared-test]
steps:
@@ -84,7 +84,7 @@ jobs:
working-directory: ./packages/twenty-docker/
ci-test-docker-compose-status-check:
if: always() && !cancelled()
timeout-minutes: 1
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, test]
steps:
+1 -1
View File
@@ -62,7 +62,7 @@ jobs:
NEXT_PUBLIC_KEYSTATIC_GITHUB_APP_SLUG: xxx
ci-website-status-check:
if: always() && !cancelled()
timeout-minutes: 10
timeout-minutes: 5
runs-on: ubuntu-latest
needs: [changed-files-check, website-build]
steps:
@@ -0,0 +1,36 @@
name: 'Preview Environment Dispatch'
on:
# Using pull_request_target instead of pull_request to have access to secrets for external contributors
# Security note: This is safe because we're only using the repository-dispatch action with limited scope
# and not checking out or running any code from the external contributor's PR
pull_request_target:
types: [opened, synchronize, reopened, labeled]
paths:
- packages/twenty-docker/**
- packages/twenty-server/**
- packages/twenty-front/**
- .github/workflows/preview-env-dispatch.yaml
- .github/workflows/preview-env-keepalive.yaml
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
trigger-preview:
permissions:
contents: write
actions: write
pull-requests: read
if: github.event.action == 'opened' || github.event.action == 'synchronize' || github.event.action == 'reopened' || (github.event.action == 'labeled' && github.event.label.name == 'preview-app')
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- name: Trigger preview environment workflow
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
event-type: preview-environment
client-payload: '{"pr_number": "${{ github.event.pull_request.number }}", "pr_head_sha": "${{ github.event.pull_request.head.sha }}", "repo_full_name": "${{ github.repository }}"}'
@@ -0,0 +1,150 @@
name: 'Preview Environment Keep Alive'
on:
repository_dispatch:
types: [preview-environment]
jobs:
preview-environment:
timeout-minutes: 310
runs-on: ubuntu-latest
steps:
- name: Checkout PR
uses: actions/checkout@v4
with:
ref: ${{ github.event.client_payload.pr_head_sha }}
- name: Run compose setup
run: |
echo "Patching docker-compose.yml..."
# change image to localbuild using yq
yq eval 'del(.services.server.image)' -i packages/twenty-docker/docker-compose.yml
yq eval '.services.server.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml
yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml
yq eval 'del(.services.worker.image)' -i packages/twenty-docker/docker-compose.yml
yq eval '.services.worker.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml
yq eval '.services.worker.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml
echo "Setting up .env file..."
cp packages/twenty-docker/.env.example packages/twenty-docker/.env
echo "Generating secrets..."
echo "# === Randomly generated secrets ===" >> packages/twenty-docker/.env
echo "APP_SECRET=$(openssl rand -base64 32)" >> packages/twenty-docker/.env
echo "PG_DATABASE_PASSWORD=$(openssl rand -hex 16)" >> packages/twenty-docker/.env
echo "SIGN_IN_PREFILLED=true" >> packages/twenty-docker/.env
echo "Docker compose build..."
cd packages/twenty-docker/
docker compose build
working-directory: ./
- name: Create Tunnel
id: expose-tunnel
uses: codetalkio/expose-tunnel@v1.5.0
with:
service: bore.pub
port: 3000
- name: Start services with correct SERVER_URL
run: |
cd packages/twenty-docker/
# Update the SERVER_URL with the tunnel URL
echo "Setting SERVER_URL to ${{ steps.expose-tunnel.outputs.tunnel-url }}"
sed -i '/SERVER_URL=/d' .env
echo "SERVER_URL=${{ steps.expose-tunnel.outputs.tunnel-url }}" >> .env
# Start the services
echo "Docker compose up..."
docker compose up -d || {
echo "Docker compose failed to start"
docker compose logs
exit 1
}
echo "Waiting for services to be ready..."
count=0
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-db-1) = "healthy" ] || [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
sleep 5
count=$((count+1))
if [ $count -gt 60 ]; then
echo "Timeout waiting for services to be ready"
docker compose logs
exit 1
fi
echo "Still waiting for services... ($count/60)"
done
echo "All services are up and running!"
working-directory: ./
- name: Seed Dev Workspace
run: |
cd packages/twenty-docker/
echo "Seeding full dev workspace..."
if ! docker compose exec -T server yarn command:prod -- workspace:seed:dev; then
echo "❌ Seeding full dev workspace failed. Dumping server logs..."
docker compose logs server
exit 1
fi
working-directory: ./
- name: Output tunnel URL to logs
run: |
echo "✅ Preview Environment Ready!"
echo "🔗 Preview URL: ${{ steps.expose-tunnel.outputs.tunnel-url }}"
echo "⏱️ This environment will be available for 5 hours"
- name: Post comment on PR
uses: actions/github-script@v6
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |
const COMMENT_MARKER = '<!-- PR_PREVIEW_ENV -->';
const commentBody = `${COMMENT_MARKER}
🚀 **Preview Environment Ready!**
Your preview environment is available at: ${{ steps.expose-tunnel.outputs.tunnel-url }}
This environment will automatically shut down when the PR is closed or after 5 hours.`;
// Get all comments
const {data: comments} = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ github.event.client_payload.pr_number }},
});
// Find our comment
const botComment = comments.find(comment => comment.body.includes(COMMENT_MARKER));
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: commentBody
});
console.log('Updated existing comment');
} else {
// Create new comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: ${{ github.event.client_payload.pr_number }},
body: commentBody
});
console.log('Created new comment');
}
- name: Keep tunnel alive for 5 hours
run: timeout 300m sleep 18000 # Stop on whichever we reach first (300m or 5hour sleep)
- name: Cleanup
if: always()
run: |
cd packages/twenty-docker/
docker compose down -v
working-directory: ./
+1 -1
View File
@@ -20,4 +20,4 @@ redis-on-docker:
docker run -d --name twenty_redis -p 6379:6379 redis/redis-stack-server:latest
clickhouse-on-docker:
docker run -d --name twenty_clickhouse -p 8123:8123 -p 9000:9000 -e CLICKHOUSE_PASSWORD=devPassword clickhouse/clickhouse-server:latest
docker run -d --name twenty_clickhouse -p 8123:8123 -p 9000:9000 -e CLICKHOUSE_PASSWORD=clickhousePassword clickhouse/clickhouse-server:latest \
+45 -34
View File
@@ -1,28 +1,28 @@
<br>
<br />
<p align="center">
<a href="https://www.twenty.com">
<img src="./packages/twenty-website/public/images/core/logo.svg" width="100px" alt="Twenty logo" />
</a>
</p>
<h2 align="center" >The #1 Open-Source CRM </h3>
<h2 align="center" >The #1 Open-Source CRM </h2>
<p align="center"><a href="https://twenty.com">🌐 Website</a> · <a href="https://twenty.com/developers">📚 Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a><p>
<p align="center"><a href="https://twenty.com">🌐 Website</a> · <a href="https://twenty.com/developers">📚 Documentation</a> · <a href="https://github.com/orgs/twentyhq/projects/1"><img src="./packages/twenty-website/public/images/readme/planner-icon.svg" width="12" height="12"/> Roadmap </a> · <a href="https://discord.gg/cx5n4Jzs57"><img src="./packages/twenty-website/public/images/readme/discord-icon.svg" width="12" height="12"/> Discord</a> · <a href="https://www.figma.com/file/xt8O9mFeLl46C5InWwoMrN/Twenty"><img src="./packages/twenty-website/public/images/readme/figma-icon.png" width="12" height="12"/> Figma</a></p>
<br />
<p align="center">
<a href="https://www.twenty.com">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/preview-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/preview-light.png">
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/preview-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/preview-light.png" />
<img src="./packages/twenty-docs/static/img/preview-light.png" alt="Companies view" />
</picture>
</a>
</p>
<br>
<br />
# Installation
@@ -40,7 +40,7 @@ We built Twenty for three reasons:
**We believe in Open-source and community.** Hundreds of developers are already building Twenty together. Once we have plugin capabilities, a whole ecosystem will grow around it.
<br>
<br />
# What You Can Do With Twenty
We're currently developing Twenty's beta version.
@@ -60,8 +60,8 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/index-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/index-light.png">
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/index-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/index-light.png" />
<img src="./packages/twenty-docs/static/img/visualise-customer-light.png" alt="Companies view" />
</picture>
</p>
@@ -70,9 +70,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/kanban-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/kanban-light.png">
<img src="./packages/twenty-docs/static/img/follow-your-deals-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/kanban-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/kanban-light.png" />
<img src="./packages/twenty-docs/static/img/follow-your-deals-light.png" alt="Opportunities view" />
</picture>
</p>
@@ -80,9 +80,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/emails-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/emails-light.png">
<img src="./packages/twenty-docs/static/img/rich-notes-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/emails-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/emails-light.png" />
<img src="./packages/twenty-docs/static/img/emails-light.png" alt="Emails" />
</picture>
</p>
@@ -90,9 +90,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/data-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/data-light.png">
<img src="./packages/twenty-docs/static/img/rich-notes-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/data-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/data-light.png" />
<img src="./packages/twenty-docs/static/img/data-light.png" alt="Data model" />
</picture>
</p>
@@ -100,9 +100,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/notes-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/notes-light.png">
<img src="./packages/twenty-docs/static/img/rich-notes-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/notes-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/notes-light.png" />
<img src="./packages/twenty-docs/static/img/notes-light.png" alt="Rich notes" />
</picture>
</p>
@@ -110,9 +110,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/tasks-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/tasks-light.png">
<img src="./packages/twenty-docs/static/img/create-tasks-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/tasks-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/tasks-light.png" />
<img src="./packages/twenty-docs/static/img/create-tasks-light.png" alt="Tasks" />
</picture>
</p>
@@ -120,9 +120,9 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/keyboard-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/keyboard-light.png">
<img src="./packages/twenty-docs/static/img/shortcut-navigation-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/keyboard-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/keyboard-light.png" />
<img src="./packages/twenty-docs/static/img/keyboard-dark.png" alt="Keyboard shortcuts" />
</picture>
</p>
@@ -130,22 +130,33 @@ Below are a few features we have implemented to date:
<p align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/api-dark.png">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/api-light.png">
<img src="./packages/twenty-docs/static/img/shortcut-navigation-light.png" alt="Companies view" />
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/api-dark.png" />
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/twentyhq/twenty/v0.12.0/packages/twenty-docs/static/img/api-light.png" />
<img src="./packages/twenty-docs/static/img/api-light.png" alt="API" />
</picture>
</p>
<br>
<br />
# Stack
- [TypeScript](https://www.typescriptlang.org/)
- [Nx](https://nx.dev/)
- [NestJS](https://nestjs.com/), with [BullMQ](https://bullmq.io/), [PostgreSQL](https://www.postgresql.org/), [Redis](https://redis.io/)
- [React](https://reactjs.org/), with [Recoil](https://recoiljs.org/) and [Emotion](https://emotion.sh/)
- [Greptile](https://greptile.com) for code reviews.
- [Lingui](https://lingui.dev/) and [Crowdin](https://twenty.crowdin.com/twenty) for translations.
- [React](https://reactjs.org/), with [Recoil](https://recoiljs.org/), [Emotion](https://emotion.sh/) and [Lingui](https://lingui.dev/)
# Thanks
<p align="center">
<a href="https://www.chromatic.com/"><img src="./packages/twenty-website/public/images/readme/chromatic.png" height="30" alt="Chromatic" /></a>
<a href="https://greptile.com"><img src="./packages/twenty-website/public/images/readme/greptile.png" height="30" alt="Greptile" /></a>
<a href="https://sentry.io/"><img src="./packages/twenty-website/public/images/readme/sentry.png" height="30" alt="Sentry" /></a>
<a href="https://crowdin.com/"><img src="./packages/twenty-website/public/images/readme/crowdin.png" height="30" alt="Crowdin" /></a>
</p>
Thanks to these amazing services that we use and recommend for UI testing (Chromatic), code review (Greptile), catching bugs (Sentry) and translating (Crowdin).
# Join the Community
+1 -1
View File
@@ -77,6 +77,7 @@
"bytes": "^3.1.2",
"class-transformer": "^0.5.1",
"clsx": "^2.1.1",
"cron-parser": "^5.1.1",
"cron-validate": "^1.4.5",
"cross-env": "^7.0.3",
"css-loader": "^7.1.2",
@@ -190,7 +191,6 @@
"tsup": "^8.2.4",
"type-fest": "4.10.1",
"typescript": "5.3.3",
"use-context-selector": "^2.0.0",
"use-debounce": "^10.0.0",
"uuid": "^9.0.0",
"vite-tsconfig-paths": "^4.2.1",
@@ -1,7 +1,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/icons/android/android-launchericon-48-48.png" />
<link rel="icon" href="images/icons/android/android-launchericon-48-48.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Twenty</title>
</head>
@@ -1,7 +1,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/icons/android/android-launchericon-48-48.png" />
<link rel="icon" href="images/icons/android/android-launchericon-48-48.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Twenty</title>
</head>
@@ -1,7 +1,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/icons/android/android-launchericon-48-48.png" />
<link rel="icon" href="images/icons/android/android-launchericon-48-48.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Twenty</title>
<style>
+4 -20
View File
@@ -1,22 +1,10 @@
name: twenty
services:
change-vol-ownership:
image: ubuntu
user: root
volumes:
- server-local-data:/tmp/server-local-data
- docker-data:/tmp/docker-data
command: >
bash -c "
chown -R 1000:1000 /tmp/server-local-data
&& chown -R 1000:1000 /tmp/docker-data"
server:
image: twentycrm/twenty:${TAG:-latest}
volumes:
- server-local-data:/app/packages/twenty-server/${STORAGE_LOCAL_PATH:-.local-storage}
- docker-data:/app/docker-data
- server-local-data:/app/packages/twenty-server/.local-storage
ports:
- "3000:3000"
environment:
@@ -31,7 +19,6 @@ services:
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
@@ -57,15 +44,13 @@ services:
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on:
change-vol-ownership:
condition: service_completed_successfully
db:
condition: service_healthy
healthcheck:
test: curl --fail http://localhost:3000/healthz
interval: 5s
timeout: 5s
retries: 10
retries: 20
restart: always
worker:
@@ -85,7 +70,6 @@ services:
STORAGE_S3_ENDPOINT: ${STORAGE_S3_ENDPOINT}
APP_SECRET: ${APP_SECRET:-replace_me_with_a_random_string}
# MESSAGING_PROVIDER_GMAIL_ENABLED: ${MESSAGING_PROVIDER_GMAIL_ENABLED}
# CALENDAR_PROVIDER_GOOGLE_ENABLED: ${CALENDAR_PROVIDER_GOOGLE_ENABLED}
# AUTH_GOOGLE_CLIENT_ID: ${AUTH_GOOGLE_CLIENT_ID}
@@ -109,7 +93,7 @@ services:
# EMAIL_SMTP_PORT: ${EMAIL_SMTP_PORT:-465}
# EMAIL_SMTP_USER: ${EMAIL_SMTP_USER:-}
# EMAIL_SMTP_PASSWORD: ${EMAIL_SMTP_PASSWORD:-}
depends_on:
db:
condition: service_healthy
@@ -134,8 +118,8 @@ services:
redis:
image: redis
restart: always
command: ["--maxmemory-policy", "noeviction"]
volumes:
docker-data:
db-data:
server-local-data:
@@ -25,9 +25,10 @@ spec:
- name: redis
image: redis/redis-stack-server:latest
imagePullPolicy: Always
args: ["--maxmemory-policy", "noeviction"]
env:
- name: PORT
value: 6379
value: "6379"
ports:
- containerPort: 6379
name: redis
@@ -7,13 +7,14 @@ services:
environment:
POSTGRES_DB: twenty
POSTGRES_USER: twenty
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PASSWORD: ${PG_DATABASE_PASSWORD}
volumes:
- twenty-db-data:/var/lib/postgresql/data:Z
redis:
container_name: twenty-redis
image: redis:latest
command: ["--maxmemory-policy", "noeviction"]
volumes:
- twenty-redis-data:/data:Z
@@ -23,7 +24,7 @@ services:
environment:
NODE_PORT: "3000"
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
PG_DATABASE_URL: "postgresql://twenty:${PG_DATABASE_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
NODE_ENV: production
@@ -39,7 +40,7 @@ services:
command: yarn worker:prod
environment:
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
PG_DATABASE_URL: "postgresql://twenty:${PG_DATABASE_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
DISABLE_DB_MIGRATIONS: "true"
+2 -2
View File
@@ -77,8 +77,8 @@ COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /ap
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the backend and frontend, ensuring it deploys faster and runs the same way regardless of the deployment environment."
RUN mkdir /app/.local-storage
RUN chown -R 1000 /app
RUN mkdir -p /app/.local-storage /app/packages/twenty-server/.local-storage && \
chown -R 1000:1000 /app
# Use non root user with uid 1000
USER 1000
+20 -14
View File
@@ -1,28 +1,34 @@
#!/bin/sh
set -e
# Check if the initialization has already been done and that we enabled automatic migration
if [ "${DISABLE_DB_MIGRATIONS}" != "true" ] && [ ! -f /app/docker-data/db_status ]; then
echo "Running database setup and migrations..."
setup_and_migrate_db() {
if [ "${DISABLE_DB_MIGRATIONS}" = "true" ]; then
echo "Database setup and migrations are disabled, skipping..."
return
fi
# Creating the database if it doesn't exist
echo "Running database setup and migrations..."
PGUSER=$(echo $PG_DATABASE_URL | awk -F '//' '{print $2}' | awk -F ':' '{print $1}')
PGPASS=$(echo $PG_DATABASE_URL | awk -F ':' '{print $3}' | awk -F '@' '{print $1}')
PGHOST=$(echo $PG_DATABASE_URL | awk -F '@' '{print $2}' | awk -F ':' '{print $1}')
PGPORT=$(echo $PG_DATABASE_URL | awk -F ':' '{print $4}' | awk -F '/' '{print $1}')
PGDATABASE=$(echo $PG_DATABASE_URL | awk -F ':' '{print $4}' | awk -F '/' '{print $2}')
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tc "SELECT 1 FROM pg_database WHERE datname = '${PGDATABASE}'" | grep -q 1 || \
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -c "CREATE DATABASE \"${PGDATABASE}\""
# Run setup and migration scripts
NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
yarn database:migrate:prod
# Creating the database if it doesn't exist
db_count=$(PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -tAc "SELECT COUNT(*) FROM pg_database WHERE datname = '${PGDATABASE}'")
if [ "$db_count" = "0" ]; then
echo "Database ${PGDATABASE} does not exist, creating..."
PGPASSWORD=${PGPASS} psql -h ${PGHOST} -p ${PGPORT} -U ${PGUSER} -d postgres -c "CREATE DATABASE \"${PGDATABASE}\""
# Run setup and migration scripts
NODE_OPTIONS="--max-old-space-size=1500" tsx ./scripts/setup-db.ts
yarn database:migrate:prod
fi
yarn command:prod upgrade
# Mark initialization as done
echo "Successfuly migrated DB!"
touch /app/docker-data/db_status
fi
echo "Successfully migrated DB!"
}
setup_and_migrate_db
# Continue with the original Docker command
exec "$@"
+1 -1
View File
@@ -2,5 +2,5 @@
FRONTEND_BASE_URL=http://localhost:3001
BACKEND_BASE_URL=http://localhost:3000
DEFAULT_LOGIN=tim@apple.dev
DEFAULT_PASSWORD=Applecar2025
DEFAULT_PASSWORD=tim@apple.dev
WEBSITE_URL=https://twenty.com
@@ -24,6 +24,8 @@ export class WorkflowVisualizerPage {
readonly useAsDraftButton: Locator;
readonly overrideDraftButton: Locator;
readonly discardDraftButton: Locator;
readonly seeRunsButton: Locator;
readonly goBackInCommandMenu: Locator;
#actionNames: Record<WorkflowActionType, string> = {
'create-record': 'Create Record',
@@ -31,6 +33,7 @@ export class WorkflowVisualizerPage {
'delete-record': 'Delete Record',
code: 'Code',
'send-email': 'Send Email',
form: 'Form',
};
#createdActionNames: Record<WorkflowActionType, string> = {
@@ -39,6 +42,7 @@ export class WorkflowVisualizerPage {
'delete-record': 'Delete Record',
code: 'Code - Serverless Function',
'send-email': 'Send Email',
form: 'Form',
};
#triggerNames: Record<WorkflowTriggerType, string> = {
@@ -84,6 +88,10 @@ export class WorkflowVisualizerPage {
this.discardDraftButton = page.getByRole('button', {
name: 'Discard Draft',
});
this.seeRunsButton = page.getByRole('link', { name: 'See runs' });
this.goBackInCommandMenu = this.commandMenu
.getByRole('button')
.and(this.commandMenu.getByTestId('command-menu-go-back-button'));
}
async createOneWorkflow() {
@@ -250,29 +258,64 @@ export class WorkflowVisualizerPage {
await expect(this.#page.getByTestId('command-menu')).not.toBeVisible();
}
async goToWorkflowsIndexPage() {
await this.#page.goto('/objects/workflows');
}
async setWorkflowsOpenInMode(mode: 'side-panel' | 'record-page') {
const recordTableOptionsButton = this.#page.getByText('Options');
await recordTableOptionsButton.click();
const layoutButton = this.#page.getByText('Layout');
await layoutButton.click();
const openInButton = this.#page.getByText('Open in');
await openInButton.click();
if (mode === 'side-panel') {
const openInSidePanelOption = this.#page.getByRole('option', {
name: 'Side Panel',
});
await openInSidePanelOption.click();
} else {
const openInRecordPageOption = this.#page.getByRole('option', {
name: 'Record Page',
});
await openInRecordPageOption.click();
}
// Close the dropdown
await recordTableOptionsButton.click();
}
}
export const test = base.extend<{ workflowVisualizer: WorkflowVisualizerPage }>(
{
workflowVisualizer: async ({ page }, use) => {
const workflowVisualizer = new WorkflowVisualizerPage({
page,
workflowName: 'Test Workflow',
});
export const test = base.extend<{
workflowVisualizer: WorkflowVisualizerPage;
}>({
workflowVisualizer: async ({ page }, use) => {
const workflowVisualizer = new WorkflowVisualizerPage({
page,
workflowName: 'Test Workflow',
});
await workflowVisualizer.createOneWorkflow();
await workflowVisualizer.goToWorkflowVisualizerPage();
await workflowVisualizer.createOneWorkflow();
await workflowVisualizer.goToWorkflowVisualizerPage();
await use(workflowVisualizer);
await use(workflowVisualizer);
await deleteWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
await destroyWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
},
await deleteWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
await destroyWorkflow({
page,
workflowId: workflowVisualizer.workflowId,
});
await workflowVisualizer.goToWorkflowsIndexPage();
await workflowVisualizer.setWorkflowsOpenInMode('record-page');
},
);
});
@@ -9,4 +9,5 @@ export type WorkflowActionType =
| 'update-record'
| 'delete-record'
| 'code'
| 'send-email';
| 'send-email'
| 'form';
@@ -56,3 +56,97 @@ test('The workflow run visualizer shows the executed draft version without the l
'Create Record',
);
});
test('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
workflowVisualizer,
page,
}) => {
await workflowVisualizer.createInitialTrigger('manual');
const manualTriggerAvailabilitySelect = page.getByRole('button', {
name: 'When record(s) are selected',
});
await manualTriggerAvailabilitySelect.click();
const alwaysAvailableOption = page.getByText(
'When no record(s) are selected',
);
await alwaysAvailableOption.click();
await workflowVisualizer.closeSidePanel();
const { createdStepId: firstStepId } =
await workflowVisualizer.createStep('form');
await workflowVisualizer.closeSidePanel();
const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
await launchTestButton.click();
const goToExecutionPageLink = page.getByRole('link', {
name: 'View execution details',
});
await expect(goToExecutionPageLink).toBeVisible();
await workflowVisualizer.seeRunsButton.click();
const workflowRunName = `#1 - ${workflowVisualizer.workflowName}`;
const workflowRunNameCell = page.getByRole('cell', { name: workflowRunName });
await expect(workflowRunNameCell).toBeVisible();
await workflowVisualizer.setWorkflowsOpenInMode('side-panel');
// 1. Exit the dropdown
await workflowRunNameCell.click();
// 2. Actually open the workflow run in the side panel
await workflowRunNameCell.click();
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
'Form',
);
await workflowVisualizer.goBackInCommandMenu.click();
const workflowRunNameInCommandMenu =
workflowVisualizer.commandMenu.getByText(workflowRunName);
await expect(workflowRunNameInCommandMenu).toBeVisible();
await workflowVisualizer.triggerNode.click();
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
'Launch manually',
);
await workflowVisualizer.goBackInCommandMenu.click();
const formStep = workflowVisualizer.getStepNode(firstStepId);
await formStep.click();
await workflowVisualizer.goBackInCommandMenu.click();
const openInFullScreenButton = workflowVisualizer.commandMenu.getByRole(
'button',
{ name: 'Open' },
);
await openInFullScreenButton.click();
const workflowRunNameInShowPage = page
.getByText(`#1 - ${workflowVisualizer.workflowName}`)
.nth(1);
await expect(workflowRunNameInShowPage).toBeVisible();
// Expect the side panel to be opened by default on the form.
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
'Form',
);
});
@@ -8,25 +8,19 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
await workflowVisualizer.background.click();
await Promise.all([
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
await workflowVisualizer.activateWorkflowButton.click();
workflowVisualizer.activateWorkflowButton.click(),
]);
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
await Promise.all([
expect(workflowVisualizer.workflowStatus).toHaveText('Draft'),
await workflowVisualizer.createStep('delete-record');
workflowVisualizer.createStep('delete-record'),
]);
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
await workflowVisualizer.background.click();
await workflowVisualizer.closeSidePanel();
await Promise.all([
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
await workflowVisualizer.activateWorkflowButton.click();
workflowVisualizer.activateWorkflowButton.click(),
]);
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
await expect(workflowVisualizer.triggerNode).toContainText(
'Record is Created',
@@ -41,6 +35,8 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
await workflowsLink.click();
await workflowVisualizer.setWorkflowsOpenInMode('record-page');
const recordTableRowForWorkflow = page.getByRole('row', {
name: workflowVisualizer.workflowName,
});
@@ -48,7 +44,7 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
name: workflowVisualizer.workflowName,
});
expect(linkToWorkflow).toBeVisible();
await expect(linkToWorkflow).toBeVisible();
const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
'link',
@@ -69,11 +65,9 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
]);
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
await Promise.all([
page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`),
await workflowVisualizer.useAsDraftButton.click();
workflowVisualizer.useAsDraftButton.click(),
]);
await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
@@ -96,17 +90,13 @@ test('Use an old version as draft while having a pending draft version', async (
await workflowVisualizer.background.click();
await Promise.all([
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
await workflowVisualizer.activateWorkflowButton.click();
workflowVisualizer.activateWorkflowButton.click(),
]);
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
await Promise.all([
expect(workflowVisualizer.workflowStatus).toHaveText('Draft'),
await workflowVisualizer.createStep('delete-record');
workflowVisualizer.createStep('delete-record'),
]);
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
await expect(workflowVisualizer.triggerNode).toContainText(
'Record is Created',
@@ -130,7 +120,7 @@ test('Use an old version as draft while having a pending draft version', async (
const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
name: workflowVisualizer.workflowName,
});
expect(linkToWorkflow).toBeVisible();
await expect(linkToWorkflow).toBeVisible();
const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
'link',
@@ -151,17 +141,13 @@ test('Use an old version as draft while having a pending draft version', async (
]);
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
await Promise.all([
expect(workflowVisualizer.overrideDraftButton).toBeVisible(),
await workflowVisualizer.useAsDraftButton.click();
workflowVisualizer.useAsDraftButton.click(),
]);
await expect(workflowVisualizer.overrideDraftButton).toBeVisible();
await Promise.all([
page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`),
await workflowVisualizer.overrideDraftButton.click();
workflowVisualizer.overrideDraftButton.click(),
]);
await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
+1 -2
View File
@@ -54,8 +54,7 @@ export const emailTheme = {
},
background: {
colors: { highlight: grayScale.gray15 },
radialGradient: `radial-gradient(50% 62.62% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`,
radialGradientHover: `radial-gradient(76.32% 95.59% at 50% 0%, #505050 0%, ${grayScale.gray60} 100%)`,
button: grayScale.gray60,
transparent: {
medium: 'rgba(0, 0, 0, 0.08)',
light: 'rgba(0, 0, 0, 0.04)',
@@ -3,15 +3,16 @@ import { Button } from '@react-email/components';
import { emailTheme } from 'src/common-style';
const callToActionStyle = {
display: 'flex',
display: 'inline-flex',
padding: '8px 32px',
borderRadius: emailTheme.border.radius.md,
border: `1px solid ${emailTheme.background.transparent.light}`,
background: emailTheme.background.radialGradient,
background: emailTheme.background.button,
boxShadow: `0px 2px 4px 0px ${emailTheme.background.transparent.light}, 0px 0px 4px 0px ${emailTheme.background.transparent.medium}`,
color: emailTheme.font.colors.inverted,
fontSize: emailTheme.font.size.md,
fontWeight: emailTheme.font.weight.bold,
width: 'auto',
};
type CallToActionProps = {
@@ -42,10 +42,13 @@ export const CleanSuspendedWorkspaceEmail = ({
<br />
<Trans id="If you wish to use Twenty again, you can create a new workspace." />
</MainText>
<br />
<CallToAction
href="https://app.twenty.com/"
value={i18n._('Create a new workspace')}
/>
<br />
<br />
</BaseEmail>
);
};
@@ -21,7 +21,6 @@ export const PasswordResetLinkEmail = ({
return (
<BaseEmail locale={locale}>
<Title value={i18n._('Reset your password 🗝')} />
<CallToAction href={link} value={i18n._('Reset')} />
<MainText>
<Trans
id="This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
@@ -30,6 +29,10 @@ export const PasswordResetLinkEmail = ({
<br />
<Link href={link} value={link} />
</MainText>
<br />
<CallToAction href={link} value={i18n._('Reset')} />
<br />
<br />
</BaseEmail>
);
};
@@ -41,7 +41,10 @@ export const PasswordUpdateNotifyEmail = ({
<Trans id="If you did not initiate this change, please contact your workspace owner immediately." />
<br />
</MainText>
<br />
<CallToAction value={i18n._('Connect to Twenty')} href={link} />
<br />
<br />
</BaseEmail>
);
};
@@ -18,12 +18,13 @@ export const SendEmailVerificationLinkEmail = ({
return (
<BaseEmail width={333} locale={locale}>
<Title value={i18n._('Confirm your email address')} />
<MainText>
<Trans id="Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address." />
</MainText>
<br />
<CallToAction href={link} value={i18n._('Verify Email')} />
<br />
<br />
<MainText>
<Trans id="Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address." />
</MainText>
</BaseEmail>
);
};
@@ -13,6 +13,8 @@ export const TestEmail = ({ locale }: TestEmailProps) => {
return (
<BaseEmail locale={locale}>
<Title value={i18n._('Test email')} />
<br />
<br />
</BaseEmail>
);
};
@@ -76,6 +76,7 @@ export const SendApprovedAccessDomainValidation = ({
{workspace.name ? <HighlightedText value={workspace.name} /> : <></>}
<CallToAction href={link} value={i18n._('Validate domain')} />
</HighlightedContainer>
<br />
</BaseEmail>
);
};
@@ -54,10 +54,13 @@ export const WarnSuspendedWorkspaceEmail = ({
values={{ remainingDays, dayOrDays }}
/>
</MainText>
<br />
<CallToAction
href="https://app.twenty.com/settings/billing"
value={i18n._('Update your subscription')}
/>
<br />
<br />
</BaseEmail>
);
};
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+13 -8
View File
@@ -90,13 +90,13 @@ msgstr "Confirm your email address"
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgstr "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgstr "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr "Verify Email"
#. js-lingui-explicit-id
#: src/emails/password-update-notify.email.tsx
@@ -125,13 +125,13 @@ msgstr "Reset your password 🗝"
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgstr "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr "Reset"
#. js-lingui-explicit-id
#: src/emails/clean-suspended-workspace.email.tsx
@@ -218,6 +218,11 @@ msgstr "Twenty.com, Public Benefit Corporation"
msgid "San Francisco / Paris"
msgstr "San Francisco / Paris"
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
@@ -90,12 +90,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -125,12 +125,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -218,6 +218,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+9 -4
View File
@@ -95,12 +95,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Verify Email"
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click below to verify your email address."
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
msgid "Verify Email"
msgstr ""
#. js-lingui-explicit-id
@@ -130,12 +130,12 @@ msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "Reset"
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/password-reset-link.email.tsx
msgid "This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:"
msgid "Reset"
msgstr ""
#. js-lingui-explicit-id
@@ -223,6 +223,11 @@ msgstr ""
msgid "San Francisco / Paris"
msgstr ""
#. js-lingui-explicit-id
#: src/emails/send-email-verification-link.email.tsx
#~ msgid "Thanks for registering for an account on Twenty! Before we get started, we just need to confirm that this is you. Click above to verify your email address."
#~ msgstr ""
#. js-lingui-id: 4WPI3S
#: src/emails/send-invite-link.email.tsx
#~ msgid "Accept invite"
+6 -1
View File
@@ -10,6 +10,7 @@ import { mockedUserJWT } from '../src/testing/mock-data/jwt';
import 'react-loading-skeleton/dist/skeleton.css';
import 'twenty-ui/style.css';
import { THEME_DARK, THEME_LIGHT, ThemeContextProvider } from 'twenty-ui/theme';
import { ClickOutsideListenerContext } from '@/ui/utilities/pointer-event/contexts/ClickOutsideListenerContext';
initialize({
onUnhandledRequest: async (request: Request) => {
@@ -46,7 +47,11 @@ const preview: Preview = {
return (
<ThemeProvider theme={theme}>
<ThemeContextProvider theme={theme}>
<Story />
<ClickOutsideListenerContext.Provider
value={{ excludeClassName: undefined }}
>
<Story />
</ClickOutsideListenerContext.Provider>
</ThemeContextProvider>
</ThemeProvider>
);
+3 -2
View File
@@ -6,10 +6,11 @@
<link
rel="icon"
type="image/x-icon"
href="/icons/android/android-launchericon-48-48.png"
href="images/icons/android/android-launchericon-48-48.png"
data-rh="true"
/>
<link rel="apple-touch-icon" href="/icons/ios/192.png" />
<link rel="apple-touch-icon" href="images/icons/ios/192.png" />
<link rel="manifest" href="manifest.json" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="A modern open-source CRM" />

Some files were not shown because too many files have changed in this diff Show More