Compare commits

..
189 Commits
Author SHA1 Message Date
Paul Rastoinandprastoin a771216f6e 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 11:10:24 +02:00
Etienneandetiennejouan fe371eb4c4 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 17:10:41 +02:00
Guillimandguillim 1db92ce662 Critical email sync bug (#11885)
Removing the upsert to avoid the ON CONFLICT
2025-05-06 11:22:09 +02:00
prastoin 6bb0212a70 fix(server): upgrade command 2025-05-05 16:48:10 +02:00
Etienneandetiennejouan 4a543a0e0a 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 08:57:53 +02: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
Charles BochetandGitHub 8076ff5b82 Fix broken metadata sync due to index removal (#11706)
Changing strategy regarding disabling index creation with new relation
system
2025-04-23 18:06:19 +02:00
MarieandGitHub 4257f30f12 Permission checks on twentyORM global manager (#11477)
In this PR we are handling permissions when using
twentyORMGlobalManager,
and handling permissions for rest api and api key
2025-04-23 17:57:48 +02:00
Thomas TrompetteandGitHub 28a1354928 Allow webhook only on active versions (#11705)
- webhook call should only be allow on active versions
- fixing exceptions that are wrongly sent to sentry
2025-04-23 17:28:41 +02:00
Charles BochetandGitHub a2d2db441f Improve Filter chip empty state (#11704)
Cases:

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/06da3efc-b878-499f-97de-570317caa9b7"
/>

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/40114c16-2810-489d-a60f-2579e2916691"
/>

<img width="477" alt="image"
src="https://github.com/user-attachments/assets/fa80d7cf-7c2d-4c19-919e-2d4c78a9202b"
/>
2025-04-23 16:54:11 +02:00
Charles BochetandGitHub a4882089b1 Add is relation enabled to default feature flags (#11703) 2025-04-23 16:26:53 +02:00
Paul RastoinandGitHub f2828883ad Fix click outside dropdown content confirmation modal (#11702)
# Introduction
Closes https://github.com/twentyhq/twenty/issues/11674
2025-04-23 14:23:15 +00:00
Thomas TrompetteandGitHub 1333c64d98 Add diff in workflow update events + fix existing (#11700)
Closes https://github.com/twentyhq/twenty/issues/11676.

Diff should be available for objects displaying timeline activities. It
should also fit the existing type.
2025-04-23 15:43:41 +02:00
Félix MalfaitandGitHub e1054b0474 Fix clickhouse migration (#11699)
It looks like Clickhouse Cloud uses a different config var than the docs
2025-04-23 15:09:23 +02:00
Charles BochetandGitHub 457c6ed113 Improve storybook stories (#11694)
## Improvements

### TaskGroups

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/0dbd71fe-3999-4cf5-870e-565b8e2df1b9"
/>

### EventCardMessage

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/b41cddc1-3ff2-411f-9ac6-8d4035579e54"
/>

### Blocklist stories

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/e997a0c1-e7e2-4ea4-9253-f31609ee44df"
/>

### WorkflowEditActionUpdateRecord

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/275dab17-ad33-4174-8671-31ba455c20a4"
/>
2025-04-23 13:20:13 +02:00
Félix MalfaitandGitHub 93c2ba153b Add clickhouse prod migration command (#11695)
Add a missing command to launch clickhouse migrations the same way we
launch postgres migrations
2025-04-23 13:02:00 +02:00
martmullandGitHub b6e8103df7 Mime encode names in email headers (#11691)
# Before
<img width="618" alt="image"
src="https://github.com/user-attachments/assets/e6d7c0ac-10f8-4d2e-abe4-05bf86a2ea9e"
/>

# After
<img width="504" alt="image"
src="https://github.com/user-attachments/assets/db147cb9-be19-4d08-b357-cb554dc2a4ae"
/>

Fixes also Emojis encoding in Subject ->
<img width="540" alt="image"
src="https://github.com/user-attachments/assets/8c27743f-3a50-46eb-b0f3-492219bbd646"
/>

 Works with microsoft accounts
<img width="360" alt="image"
src="https://github.com/user-attachments/assets/d924440f-c107-4c1c-ad4d-b4b27016f102"
/>


Fixes https://github.com/twentyhq/twenty/issues/9194
2025-04-23 11:37:40 +02:00
EtienneandGitHub ea850f323a Fix inline cell interactions (#11686)
@bosiraphael I've slightly updated [your recent
pr](https://github.com/twentyhq/twenty/pull/11654)
- before
<img width="490" alt="Screenshot 2025-04-22 at 17 48 26"
src="https://github.com/user-attachments/assets/604d65df-5433-4524-bdc5-6f5083b3c045"
/>

- after
<img width="488" alt="Screenshot 2025-04-22 at 17 47 41"
src="https://github.com/user-attachments/assets/21273372-538e-454e-947b-09373d9e0d6d"
/>


closes https://github.com/twentyhq/core-team-issues/issues/831 and
https://github.com/twentyhq/core-team-issues/issues/828
2025-04-23 08:46:10 +00:00
Charles BochetandGitHub fa5f758228 Fix storybook / chromatic tests flakyness and integration tests (#11687)
## Storybook flakyness

### Actor Display image flakyness

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/875c0738-5e31-4aba-9231-4ba5f78d1355"
/>

**Fix:** stop using a random usage

### Task Groups broken

<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/c67e47a1-a027-43f1-9601-68d61a8052b4"
/>

**Fix:** add missing TabListComponentInstance

## Flaky dates

Add https://github.com/k35o/storybook-addon-mock-date

## Integration tests

Fix broken tests due to relation refactoring
2025-04-23 01:57:36 +02:00
Félix MalfaitandGitHub 8694840b92 Rename webhook and open api urls (#11684)
We want to have fewer base path for routing.

We will have:
- /files
- /webhooks
- /graphql
- /metadata
- /rest
- /auth
- /healthz

I'm moving /open-api under /rest, and centralizing the webhooks
(removing /stripe and /cloudflare)
2025-04-22 22:24:26 +02:00
Paul RastoinandGitHub fba9ae6dfe Fallback undefined recordDataChip record name to empty string (#11685)
# Introduction
Closes #11682 

This seems to always has been quite flaky but this latest
[update](https://github.com/twentyhq/twenty/commit/f0de6d31b7b3b84671c3a5af8fd047ef7432666f#diff-63704155b77d9690a87a1ebd9f364bab7e7bb12afed7cc5a5516561ec3798f29L20)
seems to made the name optional.

As previously `undefined` being transpiles to a string results in
`"undefined"` which not a good thing neither 🙃 but wouldn't throw before
2025-04-22 20:17:44 +02:00
cc29c25176 feat: new relation sync-metadata, twenty-orm, create/update (#10217)
Fix
https://github.com/twentyhq/core-team-issues/issues/330#issue-2827026606
and
https://github.com/twentyhq/core-team-issues/issues/327#issue-2827001814

What this PR does when `isNewRelationEnabled` is set to `true`:
- [x] Drop the creation of the  foreign key as a `FieldMetadata`
- [x] Stop creating `RelationMetadata`
- [x] Properly fill `FieldMetadata` of type `RELATION` during the sync
command
- [x] Use new relation settings in TwentyORM
- [x] Properly create `FieldMetadata` relations when we create a new
object
- [x] Handle `database:reset` with new relations

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-22 19:01:39 +02:00
Paul RastoinandGitHub de1489aabb Time line activity wrong type (#11673)
# Introduction
Closes https://github.com/twentyhq/core-team-issues/issues/874

`TimeLineActivity` fields `` and `` were typed as required whereas in
reality are nullable, resulting in the related sentry error.
Refactored the type then the related components in order to handle
nullable use case
2025-04-22 15:17:08 +00:00
Baptiste DevessierandGitHub efab98a8f8 Get all first depth fields in the table and the board (#11650)
After discussing it with the team, we now want to query all fields in
the table and the board by default. Feeding the cache with exhaustive
data will make the side panel's life easier, as it needs all the record
fields to determine the actions to enable.
2025-04-22 16:45:36 +02:00
Thomas TrompetteandGitHub 0b7024c94a Perform batch update on workflow runs (#11680)
Command times out on workflow versions with too many runs. Performing
batch update instead
2025-04-22 16:07:29 +02:00
EtienneandGitHub 5250d5c8d6 fix subscription item update (#11648)
closes
https://twenty-v7.sentry.io/issues/6550388239/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&stream_index=6
2025-04-22 14:01:36 +02:00
Raphaël BosiandGitHub 87083cb414 834 Design Adjustments for the Record Page Breadcrumb (#11670)
# Design Adjustments for the Record Page Breadcrumb

Closes [834](https://github.com/twentyhq/core-team-issues/issues/834)
and [826](https://github.com/twentyhq/core-team-issues/issues/826)

## Description

- Added the breadcrumb to every object (not just the workflows)
- Fixed spacings
- Changed icon color from primary to tertiary for proper visual
hierarchy
- Displayed pagination information (current/total)
- Close button has been removed to simplify the UI
- Navigate to index page when the breadcrumb is clicked
- Fixed problems when two record title cells were displayed at the same
time (in the header and in the record page)

## Before

<img width="247" alt="Capture d’écran 2025-04-22 à 12 15 34"
src="https://github.com/user-attachments/assets/5ca2aca7-ffb0-49ea-8d3a-4bd621d78f8d"
/>

## After

<img width="233" alt="Capture d’écran 2025-04-22 à 12 15 06"
src="https://github.com/user-attachments/assets/cbcb5dfe-d616-47c9-8017-71dd4d388534"
/>
2025-04-22 13:52:56 +02:00
Raphaël BosiandGitHub 251a7b126b 838 design adjustments on table kanban and inline fields (#11654)
Closes [#838]( https://github.com/twentyhq/core-team-issues/issues/838)
Design adjustments on table kanban and inline fields.

The table row border selection will be done later since it is harder
than initially thought.
2025-04-22 11:15:53 +02:00
Thomas TrompetteandGitHub 33e0794da9 Update workflow statuses in real time (#11653)
Statuses are maintained by an async job. Those are calculations that we
would like to avoid using in both frontend and backend. Using push
updates are an easier way.



https://github.com/user-attachments/assets/31e44a82-08a8-4100-a38e-c965d5c73ee8
2025-04-22 11:03:12 +02:00
Ken LynchandGitHub 3ce3793129 Update glossary.mdx (#11661)
Remove extraneous AI response. :)
2025-04-22 10:17:16 +02:00
Félix MalfaitandGitHub aa2f3438fa Fix email verification (#11660)
Email verification modal had been broken and looked bad

I also added stories to make it more evident if this happens again
2025-04-20 14:18:43 +02:00
Félix MalfaitandGitHub 24873d0c1d Remove versions from package.json (#11658)
Now the source of truth for the version is set during the build process.
We set it as an environment variable from the tags.
We could add it back to the package.json during the build process (from
the git tag), but there is not use for it at the moment since it's not
npm packages.
2025-04-19 23:03:06 +02:00
Antoine MoreauxandGitHub 83434deb22 refactor(auth): optimize work email handling in sign-up flow (#11655)
Extracted isWorkEmail check into a variable for reusability and adjusted
subdomain generation to conditionally include email. This enhances code
readability and maintains logic consistency.
2025-04-19 15:28:41 +02:00
Baptiste DevessierandGitHub 826889715b Fix e2e tests (#11656)
After @bosiraphael's updates on the table, cells are duplicated when
they get the hover/focus. Playwright has a hard time finding which
element to click on.
I dislike my solution because it doesn't mimic how a real user would use
the application, but I couldn't find a better solution that wasn't
flaky.
2025-04-18 18:39:43 +02:00
MarieandGitHub f8b9e4d780 ignoreLock when recomputing rolePermissions when creating datasource (#11657)
[sentry](https://twenty-v7.sentry.io/issues/6545999328/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&sort=date&stream_index=2)

Our workers have failing jobs because they are concurrently creating
datasources on different pods
While the datasources are independent, they read from the same redis
cache, with the same `RolesPermissionsOngoingCachingLock` value in
redis.
<img width="852" alt="Capture d’écran 2025-04-18 à 18 00 20"
src="https://github.com/user-attachments/assets/42ce8479-acc1-462b-af4c-b547cc2bb0b8"
/>
As a consequence they can fail to create a datasource: the first
datasource computes the permissions and sets ongoingCachingLock to true,
then the second arrives, there are still no available permissions in the
cache, but because of the lock it early returns without permissions and
fails. This behavior goes unnoticed on the product and helps
performances, but is annoying for workers as jobs are failing.

Let's remove the cache lock when creating the datasource !
2025-04-18 18:16:34 +02:00
8512904c0a refacto clickoutside componentv2 (#11644)
Switch to ComponentV2

Friday morning refacto & chill with @charles

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-18 17:48:30 +02:00
Félix MalfaitandGitHub cf5649a1df Deprecate Sentry release (#11651)
Let's deprecate Sentry Release and use APP_VERSION instead. 

It'll make it more clear in the interface to use named version for bug
analysis, than commit sha
2025-04-18 15:48:48 +02:00
martmullandGitHub fba4192d4b Fix rest api integration tests (#11645)
as title
2025-04-18 15:23:36 +02:00
16bd0425e0 i18n - translations (#11647)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-18 14:22:25 +02:00
MarieandGitHub fd750c7c0e Fix metadata cache flush (#11646)
Attempt to fix
https://twenty-v7.sentry.io/issues/6545999328/?environment=prod&project=4507072499810304&query=is%3Aunresolved%20issue.priority%3A%5Bhigh%2C%20medium%5D&referrer=issue-stream&sort=date&stream_index=2
2025-04-18 12:02:36 +00:00
Thomas TrompetteandGitHub 8112c3aab3 Fix workflow run executed by empty (#11642)
Workflow run executed by should not be empty when the workflow is
unamed. Adding Workflow as fallback

<img width="1072" alt="Capture d’écran 2025-04-17 à 19 17 12"
src="https://github.com/user-attachments/assets/e4cc3360-06e5-47e8-ba05-28a0eafab994"
/>
2025-04-18 09:26:51 +00:00
Antoine MoreauxandGitHub 8a2a004fb5 feat(settings): add domain validation effect and delete functionality (#11643)
Introduced a new effect component to validate custom domain DNS records
on mount, centralizing logic. Added a button to reset the custom domain
field, improving user control and form handling. Refactored related code
for maintainability and enhanced UI structure.

Fix https://github.com/twentyhq/core-team-issues/issues/853
2025-04-18 08:18:36 +00:00
oliverGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>Félix MalfaitFélix Malfait
53042cc9dc Date field format display (#11384)
## Introduction

This PR enables functionality discussed in [Layout Date
Formatting](https://github.com/twentyhq/core-team-issues/issues/97).

### TLDR;
It enables greater control of date formatting at the object's field
level by upgrading all DATE and DATE_TIME fields' settings from:

```ts
{
    displayAsRelativeDate: boolean
}
```

to:

```ts

type FieldDateDisplayFormat = 'full_date' | 'relative_date' | 'date' | 'time' | 'year' | 'custom'

{
    displayFormat: FieldDateDisplayFormat
}
```

PR also includes an upgrade command that will update any existing DATE
and DATE_TIME fields to the new settings value

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
2025-04-18 07:00:02 +00:00
Raphaël BosiandGitHub dd0ea2366f 839 Table focus refactoring (#11629)
# Table Focus Refactoring

This pull request implements the table focus refactoring requested in
[#839](https://github.com/twentyhq/core-team-issues/issues/839),
dissociating hover and focus behaviors in the table component to improve
keyboard navigation.

## Technical Implementation

- Created separate component states to handle focus and hover
independently.
- Updated all relevant hooks and functions to use the new focus
mechanism.
- Removed deprecated states and hooks.
- Introduced dedicated portal components to improve the table
performance (the table cells are much simpler and the more complex logic
is handled via the portals)

## Key Behavior Changes

- Performance improvements
- Focus is now handled exclusively with keyboard navigation
- Clicking on a cell or inline-cell now sets the focus to that cell
- Hover state is managed separately from focus, improving user
experience and accessibility
- The table scrolls when the focused cell changes

## Video



https://github.com/user-attachments/assets/9966beac-3b0f-4433-a87a-299506d83353
2025-04-17 16:40:24 +00:00
Thomas TrompetteandGitHub 18a89b5152 Set error on number field and prevent form from being submitted (#11637)
<img width="943" alt="Capture d’écran 2025-04-17 à 18 14 46"
src="https://github.com/user-attachments/assets/1208075e-937f-4224-886c-be578264d448"
/>
2025-04-17 18:39:18 +02:00
WeikoandGitHub 19da80d2e4 Fix logs in integration tests for unhandled exceptions without removing logger (#11635)
Setting a global exception filter for unhandled exceptions to avoid the
default Nest ExceptionsHandler being called (and logging exceptions)
2025-04-17 18:35:21 +02:00
WeikoandGitHub 3fe12cd8b5 Fix select default value not in options (#11622)
Also fixing a bunch of places where validation exceptions were not
properly handled
2025-04-17 18:34:31 +02:00
EtienneandGitHub dd1ac4deee Fix mismatching stripe subscription metadata plan/planKey (#11634)
for later : https://github.com/twentyhq/core-team-issues/issues/867
2025-04-17 18:21:35 +02:00
martmullandGitHub e4150ff3cb Fix logs in integration tests (#11632)
## Before
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/3e8be2e0-ac16-4735-8783-69c800bf0aaf"
/>

## After
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/1a83e7ce-d70a-43c4-a6cd-89dd456d80c1"
/>
2025-04-17 15:05:10 +00:00
Lucas BordeauGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
caf44207fd Implemented filter on FULL_NAME sub-fields (#11628)
This PR implements what's missing to have sub-field filtering.

There is a backend modification to save subFieldName, we just add this
field on view filter workspace entity.

This PR adds subFieldName where missing in frontend, notably in
applyFilter calls, that will be refactored soon.

Also fixes a bug in ViewBar where Add Filter button was at the right
side of the ViewBar, while it should be right after the chips section.

Another bug fixed where we wouldn't delete an empty record filter on
dropdown click outside from the view bar, which was already the case
where using the filter chip dropdown.

<img width="512" alt="image"
src="https://github.com/user-attachments/assets/e9a2f8d2-a66f-4800-853a-4df5c6b627a9"
/>

<img width="495" alt="image"
src="https://github.com/user-attachments/assets/7542697b-0689-4095-9c3c-b5e47875355f"
/>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-17 15:03:56 +00:00
Baptiste DevessierandGitHub 1ba0c24071 Set the page hotkey scope only once (#11626)
The `useEffect` in the `PageChangeEffect` component that sets the page's
hotkey scope is run 4-5 times every time the page changes. It should be
executed only once when the location changes. The re-runs are due to
unstable dependencies that shouldn't re-trigger the `useEffect`.

This PR minimizes the re-runs of the `useEffect`. In the following
video, I discuss a more global pattern.

The documentation for the `useEffectEvent` hook:
https://react.dev/learn/separating-events-from-effects#extracting-non-reactive-logic-out-of-effects.


https://github.com/user-attachments/assets/8c0c238b-f1c4-4bbb-b083-0825f7176599
2025-04-17 16:57:49 +02:00
Antoine MoreauxandGitHub 21c3edf8d6 fix(integration-tests): auth with multiworkspace and skip clickhouse … (#11630)
…tests
2025-04-17 14:49:57 +00:00
EtienneandGitHub a7b75c61e8 fix billing command - add workflow subscription item (#11631)
to migrate user with trialing or paused subscription status with trial
end behaviour 'paused'
2025-04-17 16:23:03 +02:00
f40aafb89f fix: reflect on #10521 changes to order-by-input-factory.ts file (#10662)
# This PR

Fixes an error on the FindMany REST API
I was getting the following error:
```
{
  "statusCode": 400,
  "error": "TypeError",
  "messages": [
    "Cannot read properties of undefined (reading 'fields')"
  ]
}
```
Now, it's working as expected
Related to #10521

cc: @Weiko @ijreilly

---------

Co-authored-by: Weiko <corentin@twenty.com>
2025-04-17 16:06:53 +02:00
42e060ac74 Ws poc (#11293)
related to https://github.com/twentyhq/core-team-issues/issues/601

## Done
- add a `onDbEvent` `Subscription` graphql endpoint to listen to
database_event using what we have done with webhooks:
- you can subscribe to any `action` (created, updated, ...) for any
`objectNameSingular` or a specific `recordId`. Parameters are nullable
and treated as wildcards when null.
  - returns events with following shape
```typescript
  @Field(() => String)
  eventId: string;

  @Field()
  emittedAt: string;

  @Field(() => DatabaseEventAction)
  action: DatabaseEventAction;

  @Field(() => String)
  objectNameSingular: string;

  @Field(() => GraphQLJSON)
  record: ObjectRecord;

  @Field(() => [String], { nullable: true })
  updatedFields?: string[];
```
- front provide a componentEffect `<ListenRecordUpdatesEffect />` that
listen for an `objectNameSingular`, a `recordId` and a list of
`listenedFields`. It subscribes to record updates and updates its apollo
cached value for specified `listenedFields`
- subscription is protected with credentials

## Result

Here is an application with `workflowRun`


https://github.com/user-attachments/assets/c964d857-3b54-495f-bf14-587ba26c5a8c

---------

Co-authored-by: prastoin <paul@twenty.com>
2025-04-17 16:03:51 +02:00
Thomas TrompetteandGitHub b112d06f66 Fix onClick on forms (#11624)
As title
2025-04-17 13:53:40 +00:00
Charles BochetandGitHub 56874bf84b Fix aggregate bar (#11620)
Closes https://github.com/twentyhq/twenty/issues/10943

Also adds stories:
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/377059b1-f6b5-4d8c-b7d1-e74e70448445"
/>
2025-04-17 15:29:20 +02:00
Thomas TrompetteandGitHub d2881bb4a2 Allow workflow field update when custom (#11619)
- Allow workflow field update when custom
- Also handle the case where object name is not defined in actions
2025-04-17 15:01:18 +02:00
GuillimandGitHub 1401f80081 Messaging : better logging (#11621)
Better error logging for messaging import exception handler.

Goal is to have better info on why Unknown errors are thrown and avoid
such messages `Unknown error occurred while importing messages for
message channel XXXXXXXX in workspace YYYYYYYYYY: Unknown error occurred
while importing messages for message channel XXXXXXXX...`
2025-04-17 14:16:05 +02:00
EtienneandGitHub 71dbd1d66b fix: re-init subscription items when user ends his trial period (#11616) 2025-04-17 13:53:37 +02:00
GuillimandGitHub 6e7956b990 logs removal (#11618)
view with Martin, not necessary any longer
2025-04-17 10:01:05 +00:00
martmullandGitHub 0469aba90b Improve from in send email action (#11581)
## Before
<img width="701" alt="image"
src="https://github.com/user-attachments/assets/77184775-5b06-4777-9276-1338cc457070"
/>

## After
<img width="705" alt="image"
src="https://github.com/user-attachments/assets/9528eb0e-54c3-452c-8297-27796ccc75a1"
/>
2025-04-17 11:34:55 +02:00
Antoine MoreauxandGitHub e457ade362 chore(constants): add TrackAnalytics to excluded operations (#11617)
Included TrackAnalytics in the list of excluded middleware operations.
This ensures consistent handling of operations that bypass middleware
processing.
2025-04-17 11:24:45 +02:00
Vaibhav DevereandGitHub 6023bda579 Drop await usage for now-synchronous encodeFileToken() (#11612)
### Remove unnecessary `await` from `encodeFileToken` calls (now
synchronous) #11611

####  Context

In [PR #11385 – commit
26c17f3](https://github.com/twentyhq/twenty/pull/11385/commits/26c17f3205eb0cf4b93dd37cfec97638596ed263),
`FileService.encodeFileToken()` was updated to be a **synchronous**
method. However, several places in the codebase were still calling it
using `await`.

####  Changes 
This PR cleans up those redundant `await` usages to:
- Improve clarity
- Avoid confusion (no longer awaiting a non-Promise)
- Slightly reduce overhead in affected functions
- Removed `await` from calls to `this.fileService.encodeFileToken(...)`
2025-04-17 10:55:54 +02:00
9e9ba73a43 better handling the function argument without touching it (#11614)
leave intact the `input` argument to avoid side effects on the parent
caller

---------

Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-17 08:54:56 +00:00
nitinandGitHub d89474d43b Fix tab icon alignment issue (#11613)
before:
![Screenshot 2025-04-17 at 13 40
00](https://github.com/user-attachments/assets/b29b3e6b-0185-4289-950c-37a24b63cb65)

after:
![Screenshot 2025-04-17 at 13 39
49](https://github.com/user-attachments/assets/af2efe6f-3908-40d6-acde-d2839a5a8ba2)
2025-04-17 10:29:51 +02:00
GuillimandGitHub b5e6600c73 Capitalize labels objectmetadata (#11609)
Capitalize labels singular and plural from objectmetadata

Fixes [#664](https://github.com/twentyhq/core-team-issues/issues/664)
2025-04-16 21:02:12 +00:00
thomasdnGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
3ad110da33 Added support for podman deployment (#11600)
Added files needed to deploy twenty on podman using podman-compose.

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-16 22:08:14 +02:00
Antoine MoreauxandGitHub 587281a541 feat(analytics): add clickhouse (#11174) 2025-04-16 16:33:10 +00:00
b6901a49bf Fix-inline-height (#11608)
Follow up from inline height #11553 related to PR #11442


we had some issues with hover styles

Fixes
https://github.com/twentyhq/twenty/issues/11442#issuecomment-2805893663

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-16 17:49:04 +02:00
e1b99a6f39 Fix Account Owner Dropdown to Display Team Member Profile Pictures #11370 (#11385)
#11370  & #11402
### Changes made:
1. Updated search.service.ts to properly handle workspace member avatar
and Person Avatar URLs with authentication tokens
2. Integrated FileService for token generation
3. Added FileModule to SearchModule for dependency injection

### Implementation details:
- Used getImageUrlWithToken to append authentication tokens to avatar
URLs specifically for workspace members

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-16 17:46:37 +02:00
MarieandGitHub 4d78f5f97f [permissions] Improve performances using a cache for userWorkspaces roles (#11587)
In this PR we are 

- introducing a cached map `{ userworkspaceId: roleId } `to reduce calls
to get a userWorkspace's role (we were having N+1 around that with
combinedFindMany queries and generally having a lot of avoidable
queries)
- using the roles permissions cache (`{ roleId: { objectNameSingular:
{ canRead: bool, canUpdate: bool, ...} } `) in Permissions V1's
userHasObjectPermission, in order to 1) improve performances to avoid
calls to get roles 2) start using our permissions cache
2025-04-16 17:07:43 +02:00
Félix MalfaitandGitHub ab277476a8 Remove Sentry fingerprint (#11602)
As discussed this @ijreilly, Fingerprinting is probably not needed and
Sentry will do a better job by itself
2025-04-16 16:25:40 +02:00
nitinandGitHub c95a84c8e5 update KeyValuePairType enum and add IS_CONFIG_VAR_IN_DB_ENABLED config var (#11596)
closes https://github.com/twentyhq/core-team-issues/issues/758
2025-04-16 16:23:57 +02:00
Thomas TrompetteandGitHub 78e10b2da5 Update next step ids on step update (#11605)
When inserting a new step between step 1 et step 2, then step 1 should
have the new step as next step id, add stop having step 2.

When deleting a step, we link the parent and next steps together. It may
change in the future
2025-04-16 15:30:05 +02:00
bf704bd1bc Improve CSV import sub-field selection (#11601)
This PR adds a better UX for selecting sub-fields when importing CSV
files.

Before : 

<img width="395" alt="image"
src="https://github.com/user-attachments/assets/5a599e7d-ed07-4531-8306-9d70e7cfa37d"
/>

After : 

<img width="298" alt="image"
src="https://github.com/user-attachments/assets/2be8a1df-d089-4341-970e-6db2b269141e"
/>

<img width="296" alt="image"
src="https://github.com/user-attachments/assets/584285f4-4e71-4abd-9adf-11819cab0dc5"
/>

- A util `getSubFieldOptionKey` has been made to be able to reference
the sub field in the `options` object of the spreadsheet import.
- New components have been created :
`MatchColumnSelectFieldSelectDropdownContent`,
`MatchColumnSelectSubFieldSelectDropdownContent` and
`MatchColumnSelectV2`
- Extracted the hard-coded option do not import into a constant
`DO_NOT_IMPORT_OPTION_KEY`
- Passed `availableFieldMetadataItems` to spreadsheet global options so
it's available anywhere in the hierarchy of components.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
2025-04-16 15:08:24 +02:00
Baptiste DevessierandGitHub b1c0613514 Fix execution permissions (#11604)
The PR https://github.com/twentyhq/twenty/pull/11400 introduced changes
to the execution permissions of many executable files. These changes
aren't correct and must be reverted.

cc. @charlesBochet
2025-04-16 11:46:37 +02:00
GuillimandGitHub db8a60fe6f more logging to look at calendar errors (#11603)
Adding more logs to look at calendar errors that we have currently

Should help investigation on
https://twenty-v7.sentry.io/issues/5182547220/events/7e8b168887384ede8397e79c15adeb50/?project=4507072499810304
2025-04-16 11:46:02 +02:00
b7cfe89b14 Onboarding doc update (#11599)
Co-authored-by: Weiko <corentin@twenty.com>
2025-04-16 09:55:57 +02:00
madanlal mohanrao nikaljeandGitHub 4c2c9e4273 Refactor webhook event name generation in OpenApiService (#11592)
Fixes - #11589
POT - 
![Screenshot 2025-04-16 at 12 39
11 AM](https://github.com/user-attachments/assets/43802e1a-1ece-4b44-831f-35d70285c5fb)
2025-04-16 08:03:47 +02:00
Charles Bochet 981b1bd767 Fix stories 2025-04-15 23:41:30 +02:00
Charles Bochet 53c6ddb2ad Fix stories 2025-04-15 19:05:14 +02:00
EtienneandGitHub 6f78a51da4 fix query param init before workspace redirection (#11590) 2025-04-15 18:47:26 +02:00
WeikoandGitHub 43af5ceb5e Add object level permission permissions to role page (ReadOnly) (#11568)
## Context
This PR adds the display of object-level permissions. A following PR
will add the ability to update those permissions.
The PR contains the SettingsRoleObjectLevel page but it's not fully
implemented yet (save won't trigger the corresponding mutation)

<img width="616" alt="Screenshot 2025-04-14 at 18 02 40"
src="https://github.com/user-attachments/assets/f8c58193-31f3-468a-a96d-f06a9f2e1423"
/>
2025-04-15 18:46:36 +02:00
Baptiste DevessierandGitHub c23942ce6f Order the workflow run's output properly in the JsonFieldDisplay (#11583)
In this PR:

- Order the workflow run's output in the JsonField Display; the order
should be: error, stepsOutput, flow
- Ensure the special characters are hidden in the JSON visualizer
- Add missing scenarios to Json Tree's stories as it ensures Chromatic
checks them


https://github.com/user-attachments/assets/2ca5ae1d-fdba-4327-bad2-246fd9d23cb9

Closes https://github.com/twentyhq/core-team-issues/issues/804
2025-04-15 18:40:53 +02:00
8bd7b78825 Moved Select Options to External Files (#11400)
This is a minor rework of PR #10738.

I noticed an inconsistency with how Select options are passed as props.
Many files use constants stored in external files to pass options props
to Select objects. This allows for code reusability. Some files are not
passing options in this format.

I modified more files so that they use this method of passing options
props. I made changes to:
- WorkerQueueMetricsSection.tsx 
- SettingsDataModelFieldBooleanForm.tsx 
- SettingsDataModelFieldTextForm.tsx 
- SettingsDataModelFieldNumberForm.tsx 
- PlaygroundSetupForm.tsx 
- ViewPickerContentCreateMode.tsx 

I also noticed that some of these files were incorrectly using
useLingui(), so I fixed the import and usage where needed.

---------

Co-authored-by: Beau Smith <bsmith26@iastate.edu>
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-15 18:31:17 +02:00
EtienneandGitHub 797bb0559a create stripe customer before checking out + update on command (#11578)
two distincts fix in this PR

- add billing threshold for current users (in migration command)
- create stripe customer before checking out in order to enable cloud
user to create multiple workspaces (with associated stripe customer -
closes https://github.com/twentyhq/core-team-issues/issues/852)
2025-04-15 18:02:35 +02:00
Charles BochetandGitHub dee779179b Remove user action from waitFor in stories (#11588)
As per title:
- waitFor is a loop that waits for a condition to be filled, it should
be use to expect or in rare case to wait for element to be present in
the page (in most cases, you can use findByXXX)
- user actions should not be in this loop, otherwise they will be
triggered multiple times
2025-04-15 17:34:28 +02:00
Thomas TrompetteGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
c40baf036c Add command to backfill next step id on version and run steps (#11579)
- add next step id on step
- backfill next step id on step, except for the last one
- backfill flow for workflow run, when it exists

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2025-04-15 15:26:58 +00:00
GuillimandGitHub d3922a7f5b removing RecordTableEmptyStateByGroupNoRecordAtAll (#11584)
We found out that `RecordTableEmptyStateByGroupNoRecordAtAll` was used
only when `hasRecordGroups` was true in "RecordTableEmptyState"

However the only parent component is RecordTableEmpty and called
RecordTableEmptyState when `hasRecordGroups` was false

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

Meaning never called at all
2025-04-15 16:52:09 +02:00
Charles BochetandGitHub 3c189688d0 Fix stories (#11585)
<img width="1512" alt="image"
src="https://github.com/user-attachments/assets/f77a006c-9538-4734-b80e-b58b9f5e7835"
/>
2025-04-15 16:11:31 +02:00
Lucas BordeauandGitHub aa399ca91e Fix a bug that overwrites currentRecordFilters when using URL filtered view (#11525)
This PR fixes a bug that happened when navigating to a filtered view
from a record show page related record section, clicking on 'All'.

The problem was that the QueryParamsFiltersEffect effect component was
overwriting the currentRecordFilter of a different object metadata item
than the current view.

Which when we navigated back on the original view, had emptied the
filters, while they shouldn't change if we only navigate without
refreshing the app.

Fixes https://github.com/twentyhq/core-team-issues/issues/657
2025-04-15 15:32:41 +02:00
GuillimandGitHub 5c23b52c0d multiline CSS aligned to the top (#11582)
Updating CSS for inline cells so that multilie works fine and are
aligned to the top

Fixes
https://github.com/twentyhq/core-team-issues/issues/757?issue=twentyhq%7Ctwenty%7C11495
2025-04-15 13:15:37 +00:00
Charles BochetandGitHub 7bab6cab41 Fix storybook and chromatic tests and fix Block editor custom slash menu positioning (#11580)
Storybook / Chromatic fixes:
- fix linaria twenty-ui style loading (since twenty-ui prebuild
refactoring)
- update prefetch view mocks
- add ability to disable hotkeys initialization in storybook to avoid
race condition

Custom slash menu positioning fix
2025-04-15 14:57:35 +02:00
Murali SinghandGitHub 9da2a74d9e Fix inline field height #11442 (#11553)
Screenshots:

![Image](https://github.com/user-attachments/assets/998f2a88-53ab-49ef-8bb5-c7bef9158b0d)


![Image](https://github.com/user-attachments/assets/218c8f4b-f8d1-4d49-8029-8f99113f01ec)


![Image](https://github.com/user-attachments/assets/1dfde61a-62bb-403a-af3d-fb99c16ab29e)

@Bonapara Can you confirm is this what you expected ?
2025-04-15 14:42:21 +02:00
Charles BochetandGitHub d6ae4d59f0 Various fixes charles 3 (#11573) 2025-04-15 13:45:04 +02:00
Antoine MoreauxandGitHub f30070c2c9 feat(auth): enhance logo behavior and simplify billing logic (#11574)
Added default domain redirection functionality to the Logo component,
leveraging UndecoratedLink for navigation when default logos are used.
Removed metered product billing feature flag logic in the billing
webhook subscription service to simplify and streamline the codebase.

Fix https://github.com/twentyhq/core-team-issues/issues/783
2025-04-15 13:43:13 +02:00
GuillimandGitHub e1ce98825b Possiblity to reconnect on Failed unkown (#11576)
Possiblity to reconnect you account on Failed Unkown errors.

This PR triggers a similar flow than the Failed errors for unsufficient
permission already existing in twenty.

Allows our users to force the synchro again even though they have a
strange error. It's been asked by some customers since we have had a
couple of issues in messaging lately

Fixes https://github.com/twentyhq/twenty/issues/11411
2025-04-15 13:39:18 +02:00
e8db0176a1 Remove recoil sync (#11569)
Recoil-sync was causing issues with Firefox, replacing it with a simpler
mechanism to hydrate variables on page load

---------

Co-authored-by: etiennejouan <jouan.etienne@gmail.com>
2025-04-15 13:32:12 +02:00
Baptiste DevessierandGitHub 6c2d64dcb2 Fix e2e tests (#11577) 2025-04-15 12:16:38 +02:00
EtienneandGitHub 8b10059e1b fix - remove isMeteredProductBillingEnabled (#11575) 2025-04-15 11:15:02 +02:00
16fb4d406b i18n - translations (#11572)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-14 18:49:45 +02:00
Raphaël BosiandGitHub 8f2dddaa5f Create stories for action display components (#11547)
Create stories for:
- ActionButton
- ActionComponent
- ActionDisplay
- ActionDropdownItem
- ActionListItem
2025-04-14 18:42:49 +02:00
EtienneandGitHub 0249cf3b34 remove feature flag on billing metered product + fixes (#11570)
- remove feature flag
- design fixes
2025-04-14 18:39:19 +02:00
EtienneandGitHub 9a69cd0b61 add billing threshold + specific trial free credits (#11533)
In this PR : 
- set billing thresholds after subscription creation (not possible
during billing checkout)
- add specific free trial workflow credit quantities + set them in
subscription item + check them when receiving stripe alert event

closes : https://github.com/twentyhq/core-team-issues/issues/682
2025-04-14 16:25:07 +00:00
Baptiste DevessierandGitHub 704b18af30 Create FormRichTextField (#11474)
This PR adds a new Form Field for Rich Text V2 fields. The
implementation was relatively simple, thanks to @thomtrp's job on the
back-end side.

## Demo

### Edit mode + insert in database


https://github.com/user-attachments/assets/f44a6442-fad3-4ad9-af50-a7d90e872c90

### Readonly mode


https://github.com/user-attachments/assets/66243ddf-d4a2-4187-894c-356d9c02b2b2

Closes https://github.com/twentyhq/private-issues/issues/229
2025-04-14 18:07:09 +02:00
Baptiste DevessierandGitHub 0be700f376 Fix e2e tests (#11565)
Fixing the e2e tests
2025-04-14 17:47:57 +02:00
GuillimandGitHub 8a3f8ef324 Chip untitled modification (#11498)
Fixes https://github.com/twentyhq/core-team-issues/issues/663
2025-04-14 15:33:41 +00:00
MarieandGitHub d4deca45e8 Read feature flags from cache (#11556)
We are now storing a workspace's feature flag map in our redis cache. 
The cache is invalidated upon feature flag update through the lab
resolver.
2025-04-14 17:31:13 +02:00
Charles BochetandGitHub 15eb96337f Various fixes (#11567)
In this PR:
- Remove SignUpLoading blank screen by an empty dark overlay =>
VerifyEffect
- Add ModalContent from pages themselves instead of using it the Layout.
This allow for empty dark overlay without showing an empty modal with
padding
2025-04-14 17:24:16 +02:00
85d94822b3 Fix the Command menu items right padding #11484 (#11489)
Screenshot:
![Screenshot 2025-04-10 at 1 07
24 AM](https://github.com/user-attachments/assets/1e7ed8e7-594f-4ead-9b04-0c7dab636fbd)

---------

Co-authored-by: guillim <guigloo@msn.com>
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
2025-04-14 14:12:15 +02:00
Thomas TrompetteandGitHub 69a00eaaf6 Emit message event with actual message object (#11548)
Events were emitted with the wrong object. We were using
messageWithParticipant instead of actual message object
2025-04-14 13:49:19 +02:00
abecdbafc1 Add Edit Rich Text functionality to table view (#11390)
Fixes https://github.com/twentyhq/core-team-issues/issues/729


[recording.webm](https://github.com/user-attachments/assets/ea95d67b-64a3-4fef-91ed-b06318099a78)

---------

Co-authored-by: Félix Malfait <felix@twenty.com>
2025-04-14 11:46:22 +00:00
Charles BochetandGitHub 8f7a82f177 Fix refactor selectableList broke hotkey onEnter behavior (#11562) 2025-04-14 12:25:54 +02:00
4a123a8eac i18n - translations (#11560)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2025-04-14 11:11:30 +02:00
ace515eea7 Fix workflow with manual triggers and no selection not appearing in the command menu (#11544)
Fix workflow with manual triggers and no selection not appearing in the
command menu

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 11:03:29 +02:00
Lucas BordeauandGitHub b5a1d1a895 Improving empty filter chip UI (#11537)
This PR is simply removing the : character on the filter chip when the
filter value is empty.

The issue originally was about removing the filter chip when closing the
filter value dropdown with an empty value but it is already the default
behavior.

Fixes https://github.com/twentyhq/core-team-issues/issues/658
2025-04-14 10:43:20 +02:00
EtienneandGitHub 721a34864f create workflow subscription item addition command (#11541)
closes https://github.com/twentyhq/core-team-issues/issues/541
2025-04-14 10:41:37 +02:00
e2b2697fcc refacto dropdown v1>v2 in address input (#11549)
Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 10:37:40 +02:00
0de8140b3a CreateComponentFamilyState -> createComponentFamilyStateV2 (#11546)
Refacto of createComponentFamilyState

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2025-04-14 10:31:30 +02:00
Thomas TrompetteandGitHub 27f542e132 Use transformer in workflows (#11497)
We do not manage rich text properly in workflows. This is because API
has a layer called transformer service. Looks a bit as a duplicate of
format data, but this api layer was already there for position anyway.
Using it in workflow record actions.

I hope at some point we merged formatData util and transformer.
2025-04-11 16:31:45 +00:00
Baptiste DevessierandGitHub 897684f995 JSON Visualizer: ensure labels are 24px tall as all other elements (#11535)
## Before

![CleanShot 2025-04-11 at 14 42
15@2x](https://github.com/user-attachments/assets/a4726342-212a-40b3-829f-40cae7724fec)

## After

![CleanShot 2025-04-11 at 14 42
27@2x](https://github.com/user-attachments/assets/e84a4d81-fdcc-422e-b294-55867a4bc5fb)
2025-04-11 18:25:29 +02:00
MarieandGitHub 162c6bcaa3 [permissions] Implement object-records permissions in query builders (#11458)
In this PR we are

- (if permissionsV2 is enabled) executing permission checks at query
builder level. To do so we want to override the query builders methods
that are performing db calls (.execute(), .getMany(), ... etc.) For now
I have just overriden some of the query builders methods for the poc. To
do so I created custom query builder classes that extend typeorm's query
builder (selectQueryBuilder and updateQueryBuilder, for now and later I
will tackle softDeleteQueryBuilder, etc.).
- adding a notion of roles permissions version and roles permissions
object to datasources. We will now use one datasource per roleId and
rolePermissionVersion. Both rolesPermissionsVersion and rolesPermissions
objects are stored in redis and recomputed at role update or if queried
and found empty. Unlike for metadata version we don't need to store a
version in the db that stands for the source of truth. We also don't
need to destroy and recreate the datasource if the rolesPermissions
version changes, but only to update the value for rolesPermissions and
rolesPermissionsVersions on the existing datasource.

What this PR misses
- computing of roles permissions should take into account
objectPermissions table (for now it only looks at what's on the roles
table)
- pursue extension of query builder classes and overriding of their db
calling-methods
- what should the behaviour be for calls from twentyOrmGlobalManager
that don't have a roleId?
2025-04-11 17:34:02 +02:00
martmullandGitHub 82fa71c2cd Update canary package versions (#11543)
as title
2025-04-11 16:48:41 +02:00
1546 changed files with 48269 additions and 12842 deletions
+21 -1
View File
@@ -168,9 +168,25 @@ jobs:
image: redis
ports:
- 6379:6379
clickhouse:
image: clickhouse/clickhouse-server:latest
env:
CLICKHOUSE_PASSWORD: clickhousePassword
CLICKHOUSE_URL: "http://default:clickhousePassword@localhost:8123/twenty"
ports:
- 8123:8123
- 9000:9000
options: >-
--health-cmd "clickhouse-client --host=localhost --port=9000 --user=default --password=clickhousePassword --query='SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 5
env:
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
NODE_ENV: test
ANALYTICS_ENABLED: true
CLICKHOUSE_URL: "http://default:clickhousePassword@localhost:8123/twenty"
CLICKHOUSE_PASSWORD: clickhousePassword
steps:
- name: Fetch custom Github Actions and base branch history
uses: actions/checkout@v4
@@ -178,7 +194,7 @@ jobs:
fetch-depth: 0
- name: Install dependencies
uses: ./.github/workflows/actions/yarn-install
- name: Update .env.test for billing
- name: Update .env.test for integrations tests
run: |
echo "IS_BILLING_ENABLED=true" >> .env.test
echo "BILLING_STRIPE_API_KEY=test-api-key" >> .env.test
@@ -198,6 +214,10 @@ jobs:
- name: Server / Create Test DB
run: |
PGPASSWORD=postgres psql -h localhost -p 5432 -U postgres -d postgres -c 'CREATE DATABASE "test";'
- name: Run ClickHouse migrations
run: npx nx clickhouse:migrate twenty-server
- name: Run ClickHouse seeds
run: npx nx clickhouse:seed twenty-server
- name: Server / Run Integration Tests
uses: ./.github/workflows/actions/nx-affected
with:
@@ -0,0 +1,43 @@
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]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
actions: write
pull-requests: read
jobs:
changed-files-check:
uses: ./.github/workflows/changed-files.yaml
with:
files: |
.github/workflows/preview-env-dispatch.yaml
.github/workflows/preview-env-keepalive.yaml
packages/twenty-docker/**
docker-compose.yml
packages/twenty-server/**
packages/twenty-front/**
trigger-preview:
needs: changed-files-check
if: needs.changed-files-check.outputs.any_changed == 'true' || contains(github.event.pull_request.labels.*.name, 'preview')
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,141 @@
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
# Remove line below when true becomes the default value (soon)
echo "CONFIG_VARIABLES_IN_DB_ENABLED=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: 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: ./
+4 -1
View File
@@ -17,4 +17,7 @@ postgres-on-docker:
-c "CREATE DATABASE \"test\" WITH OWNER postgres;"
redis-on-docker:
docker run -d --name twenty_redis -p 6379:6379 redis/redis-stack-server:latest
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
+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
View File
+6 -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",
@@ -99,7 +100,9 @@
"graphql-fields": "^2.0.3",
"graphql-middleware": "^6.1.35",
"graphql-rate-limit": "^3.3.0",
"graphql-redis-subscriptions": "^2.7.0",
"graphql-scalars": "^1.23.0",
"graphql-sse": "^2.5.4",
"graphql-subscriptions": "2.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
@@ -181,6 +184,7 @@
"semver": "^7.5.4",
"sharp": "^0.32.1",
"slash": "^5.1.0",
"storybook-addon-mock-date": "^0.6.0",
"stripe": "^17.3.1",
"ts-key-enum": "^2.0.12",
"tslib": "^2.3.0",
@@ -354,7 +358,8 @@
"type-fest": "4.10.1",
"typescript": "5.3.3",
"prosemirror-model": "1.23.0",
"yjs": "13.6.18"
"yjs": "13.6.18",
"graphql-redis-subscriptions/ioredis": "^5.6.0"
},
"version": "0.2.1",
"nx": {},
@@ -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>
+3
View File
@@ -1,4 +1,7 @@
# README
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## Overview
+48
View File
@@ -0,0 +1,48 @@
# How to deploy twenty on podman
DISCLAIMER: The k8s and podman deployments are not maintained by the core team.
These files are provided and maintained by the community. Twenty core team
maintains support for docker deployment.
## How to use
1. Edit `.env` file. At the minimum set `POSTGRES_PASSWORD`, `SERVER_URL`, and `APP_SECRET`.
2. Start twenty by running `podman-compose up -d`.
If you need to stop twenty, you can do so by running `podman-compose down`.
### Install systemd service (optional)
If you want to install a systemd service to run twenty, you can use the provided systemd service.
Edit `twentycrm.service` and change these two variables:
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
`WorkingDirectory` should be changed to the path in which `podman-compose.yml` is located.
`EnvironmentFile` should be changed to the path in which your `.env`file is located.
You can run the script `install-systemd-user-service` to install the systemd service under the current user.
./install-systemd-user-service
Note: this script will enable the service and also start it. So it will assume that twenty is not currently running.
If you started it previously, bring it down using:
podman-compose down
## Compatibility
These files should be compatible with podman 4.3+.
I have tested this on Debian GNU/Linux 12 (bookworm) and with the podman that is distributed with the official Debian stable mirrors (podman v4.3.1+ds1-8+deb12u1, podman-compose v1.0.3-3).
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
mkdir -p ~/.config/systemd/user
[ -f twentycrm.service ] || { echo "Error: twentycrm.service not found"; exit 1; }
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
@@ -0,0 +1,71 @@
#!/bin/bash
set -e
if [ ! -f "$(dirname "$0")/.env" ]; then
echo "Error: .env file not found"
exit 1
fi
source "$(dirname "$0")/.env"
## steps to cleanup and start over from scratch - useful when testing
#podman pod stop twenty-pod
#podman pod rm twenty-pod
#podman volume rm twenty-db-data twenty-server-data twenty-redis-data
# end of cleanup
podman volume create twenty-db-data
podman volume create twenty-server-data
podman volume create twenty-redis-data
podman pod create --name twenty-pod -p 127.0.0.1:8080:3000
podman run -d --pod twenty-pod --name twenty-db \
-e POSTGRES_DB=twenty \
-e POSTGRES_USER=twenty \
-e POSTGRES_PASSWORD="$POSTGRES_PASSWORD" \
-v twenty-db-data:/var/lib/postgresql/data:Z \
docker.io/library/postgres:16
podman run -d --pod twenty-pod --name twenty-redis \
-v twenty-redis-data:/data:Z \
docker.io/library/redis:latest
podman run -d --pod twenty-pod --name twenty-server \
-e NODE_PORT=3000 \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest
podman run -d --pod twenty-pod --name twenty-worker \
--init \
-e SERVER_URL="$SERVER_URL" \
-e PG_DATABASE_URL="postgresql://twenty:$POSTGRES_PASSWORD@twenty-db:5432/twenty" \
-e REDIS_URL="redis://twenty-redis:6379" \
-e APP_SECRET="$APP_SECRET" \
-e DISABLE_DB_MIGRATIONS=true \
-e NODE_ENV=production \
-e LOG_LEVEL=info \
-v twenty-server-data:/app/docker-data:Z \
docker.io/twentycrm/twenty:latest \
yarn worker:prod
# wait some time, check status
sleep 30
podman ps --pod -f name=twenty-pod
mkdir -p ~/.config/systemd/user
if [ ! -f "twentycrm.service" ]; then
echo "Error: twentycrm.service file not found"
exit 1
fi
cp twentycrm.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable twentycrm.service
systemctl --user start twentycrm.service
@@ -0,0 +1,55 @@
version: "3.8"
services:
db:
container_name: twenty-db
image: postgres:16
environment:
POSTGRES_DB: twenty
POSTGRES_USER: twenty
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- twenty-db-data:/var/lib/postgresql/data:Z
redis:
container_name: twenty-redis
image: redis:latest
volumes:
- twenty-redis-data:/data:Z
server:
container_name: twenty-server
image: twentycrm/twenty:latest
environment:
NODE_PORT: "3000"
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
ports:
- 127.0.0.1:8080:3000
worker:
container_name: twenty-worker
image: twentycrm/twenty:latest
command: yarn worker:prod
environment:
SERVER_URL: ${SERVER_URL}
PG_DATABASE_URL: "postgresql://twenty:${POSTGRES_PASSWORD}@twenty-db:5432/twenty"
REDIS_URL: "redis://twenty-redis:6379"
APP_SECRET: ${APP_SECRET}
DISABLE_DB_MIGRATIONS: "true"
NODE_ENV: production
LOG_LEVEL: info
volumes:
- twenty-server-data:/app/docker-data:Z
init: true
volumes:
twenty-db-data:
twenty-server-data:
twenty-redis-data:
@@ -0,0 +1,15 @@
[Unit]
Description=TwentyCRM Container Stack via Podman-Compose
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/apps/twenty
EnvironmentFile=/opt/apps/twenty/.env
ExecStart=/usr/bin/podman-compose -f podman-compose.yml up -d
ExecStop=/usr/bin/podman-compose -f podman-compose.yml down
RemainAfterExit=yes
[Install]
WantedBy=default.target
-2
View File
@@ -64,8 +64,6 @@ WORKDIR /app/packages/twenty-server
ARG REACT_APP_SERVER_BASE_URL
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
ARG SENTRY_RELEASE
ENV SENTRY_RELEASE $SENTRY_RELEASE
ARG APP_VERSION
ENV APP_VERSION $APP_VERSION
@@ -17,12 +17,15 @@ export class WorkflowVisualizerPage {
readonly deactivateWorkflowButton: Locator;
readonly addTriggerButton: Locator;
readonly commandMenu: Locator;
readonly stepHeaderInCommandMenu: Locator;
readonly workflowNameLabel: Locator;
readonly triggerNode: Locator;
readonly background: Locator;
readonly useAsDraftButton: Locator;
readonly overrideDraftButton: Locator;
readonly discardDraftButton: Locator;
readonly seeRunsButton: Locator;
readonly goBackInCommandMenu: Locator;
#actionNames: Record<WorkflowActionType, string> = {
'create-record': 'Create Record',
@@ -30,6 +33,7 @@ export class WorkflowVisualizerPage {
'delete-record': 'Delete Record',
code: 'Code',
'send-email': 'Send Email',
form: 'Form',
};
#createdActionNames: Record<WorkflowActionType, string> = {
@@ -38,6 +42,7 @@ export class WorkflowVisualizerPage {
'delete-record': 'Delete Record',
code: 'Code - Serverless Function',
'send-email': 'Send Email',
form: 'Form',
};
#triggerNames: Record<WorkflowTriggerType, string> = {
@@ -68,6 +73,9 @@ export class WorkflowVisualizerPage {
});
this.addTriggerButton = page.getByText('Add a Trigger');
this.commandMenu = page.getByTestId('command-menu');
this.stepHeaderInCommandMenu = this.commandMenu.getByTestId(
'workflow-step-header',
);
this.workflowNameLabel = page
.getByTestId('top-bar-title')
.getByText(this.workflowName);
@@ -80,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() {
@@ -114,7 +126,7 @@ export class WorkflowVisualizerPage {
.getByTestId(`row-id-${this.workflowId}`)
.getByRole('link', { name: this.workflowName });
await workflowLink.click();
await workflowLink.click({ force: true });
await this.waitForWorkflowVisualizerLoad();
}
@@ -246,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');
},
);
});
@@ -110,6 +110,10 @@ export class SettingsPage {
await this.releasesLink.click();
}
async logout() {
await this.page.getByText('Logout').click();
}
async toggleAdvancedSettings() {
await this.advancedToggle.click();
}
@@ -9,4 +9,5 @@ export type WorkflowActionType =
| 'update-record'
| 'delete-record'
| 'code'
| 'send-email';
| 'send-email'
| 'form';
-1
View File
@@ -1,6 +1,5 @@
{
"name": "twenty-e2e-testing",
"version": "0.51.0",
"description": "",
"author": "",
"private": true,
@@ -10,7 +10,9 @@ test('Create workflow', async ({ page }) => {
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
await workflowsLink.click();
const createWorkflowButton = page.getByRole('button', { name: 'New record' });
const createWorkflowButton = page.getByRole('button', {
name: 'Create new workflow',
});
const [createWorkflowResponse] = await Promise.all([
page.waitForResponse(async (response) => {
@@ -26,7 +28,7 @@ test('Create workflow', async ({ page }) => {
createWorkflowButton.click(),
]);
const recordName = page.getByTestId('top-bar-title').getByTestId('tooltip');
const recordName = page.getByTestId('top-bar-title').getByText('Untitled');
await recordName.click();
const nameInput = page.getByTestId('top-bar-title').getByRole('textbox');
@@ -1,60 +1,153 @@
import { expect } from '@playwright/test';
import { test } from '../lib/fixtures/blank-workflow';
test.fixme(
'The workflow run visualizer shows the executed draft version without the last draft changes',
async ({ workflowVisualizer, page }) => {
await workflowVisualizer.createInitialTrigger('manual');
test('The workflow run visualizer shows the executed draft version without the last draft changes', async ({
workflowVisualizer,
page,
}) => {
await workflowVisualizer.createInitialTrigger('manual');
const manualTriggerAvailabilitySelect = page.getByRole('button', {
name: 'When record(s) are selected',
});
const manualTriggerAvailabilitySelect = page.getByRole('button', {
name: 'When record(s) are selected',
});
await manualTriggerAvailabilitySelect.click();
await manualTriggerAvailabilitySelect.click();
const alwaysAvailableOption = page.getByText(
'When no record(s) are selected',
);
const alwaysAvailableOption = page.getByText(
'When no record(s) are selected',
);
await alwaysAvailableOption.click();
await alwaysAvailableOption.click();
await workflowVisualizer.closeSidePanel();
await workflowVisualizer.closeSidePanel();
const { createdStepId: firstStepId } =
await workflowVisualizer.createStep('create-record');
const { createdStepId: firstStepId } =
await workflowVisualizer.createStep('create-record');
await workflowVisualizer.closeSidePanel();
await workflowVisualizer.closeSidePanel();
const launchTestButton = page.getByLabel('Test Workflow');
const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
await launchTestButton.click();
await launchTestButton.click();
const goToExecutionPageLink = page.getByRole('link', {
name: 'View execution details',
});
const executionPageUrl = await goToExecutionPageLink.getAttribute('href');
expect(executionPageUrl).not.toBeNull();
const goToExecutionPageLink = page.getByRole('link', {
name: 'View execution details',
});
const executionPageUrl = await goToExecutionPageLink.getAttribute('href');
expect(executionPageUrl).not.toBeNull();
await workflowVisualizer.deleteStep(firstStepId);
await workflowVisualizer.deleteStep(firstStepId);
await page.goto(executionPageUrl!);
await page.goto(executionPageUrl!);
const workflowRunName = page.getByText('Execution of v1');
const workflowRunName = page
.getByText(`#1 - ${workflowVisualizer.workflowName}`)
.nth(1);
await expect(workflowRunName).toBeVisible();
await expect(workflowRunName).toBeVisible();
const flowTab = page.getByText('Flow', { exact: true });
const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
await flowTab.click();
await expect(executedFirstStepNode).toBeVisible();
const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
await executedFirstStepNode.click();
await expect(executedFirstStepNode).toBeVisible();
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
'Create Record',
);
});
await executedFirstStepNode.click();
// FIXME: Documented bug. See https://github.com/twentyhq/core-team-issues/issues/921
test.fail('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');
await expect(
workflowVisualizer.commandMenu.getByRole('textbox').first(),
).toHaveValue('Create Record');
},
);
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',
@@ -57,7 +53,7 @@ test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
},
);
await linkToFirstWorkflowVersion.click();
await linkToFirstWorkflowVersion.click({ force: true });
await expect(workflowVisualizer.workflowStatus).toHaveText('Archived');
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
@@ -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',
@@ -139,7 +129,7 @@ test('Use an old version as draft while having a pending draft version', async (
},
);
await linkToFirstWorkflowVersion.click();
await linkToFirstWorkflowVersion.click({ force: true });
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
@@ -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
View File
@@ -1,6 +1,5 @@
{
"name": "twenty-emails",
"version": "0.51.0",
"description": "",
"author": "",
"private": true,
+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"
-2
View File
@@ -1,5 +1,3 @@
const path = require('path');
module.exports = {
extends: ['../../.eslintrc.react.cjs'],
ignorePatterns: [
+1
View File
@@ -48,6 +48,7 @@ const config: StorybookConfig = {
'storybook-dark-mode',
'storybook-addon-cookie',
'storybook-addon-pseudo-states',
'storybook-addon-mock-date'
],
framework: {
name: '@storybook/react-vite',
@@ -8,6 +8,7 @@ import { RootDecorator } from '../src/testing/decorators/RootDecorator';
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';
initialize({
@@ -61,6 +62,7 @@ const preview: Preview = {
date: /Date$/,
},
},
mockingDate: new Date('2024-03-12T09:30:00.000Z'),
options: {
storySort: {
order: ['UI', 'Modules', 'Pages'],
-1
View File
@@ -12,7 +12,6 @@ module.exports = {
'!./src/**/*.test.tsx',
'!./src/**/*.stories.tsx',
'!./src/**/__mocks__/*.ts',
'!./src/modules/users/graphql/queries/getCurrentUserAndViews.ts',
],
overwrite: true,
generates: {

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