Compare commits

..
Author SHA1 Message Date
Charles Bochet 0b7b33fe18 fix(server): backport relationTargetFieldMetadataId column-add to 2.4 and 2.5 fast instance
Backports the column-add to two new fast instance commands (2.4 at
timestamp 1747234400000 and 2.5 at 1747234500000) so users at v2.3.x or
v2.4.x baselines can upgrade past v2.5 without hitting the 2.5 workspace
command NormalizeCompositeFieldDefaults failing on
`column ViewFilterEntity.relationTargetFieldMetadataId does not exist`.

Same fix as main #20721, scoped to v2.5.x. ADD COLUMN IF NOT EXISTS keeps
both idempotent against DBs that already received the column via the 2.3
backport or the 2.6 add.
2026-05-19 16:02:30 +02:00
Charles Bochet f1125d0894 chore: revert version constants to 2.5.0 for v2.5.3 patch release
The v2.5.x patch tags (v2.5.0, v2.5.1, v2.5.2) were cut from main *after* #20585 bumped TWENTY_CURRENT_VERSION to 2.6.0, so all three binaries report "2.6.0" in the admin-panel inferred-version view despite being tagged 2.5.x.

Restore the version constants to the values they had at v2.5.0 so v2.5.3 reports the correct minor version. Same shape as a pure revert of #20585.
2026-05-18 11:36:42 +02:00
Charles BochetandGitHub 6b3064e2ba fix(server): add relationTargetFieldMetadataId column early in upgrade sequence (#20664)
## Summary

Cross-version upgrade fails at the 2.3
`DropMessageDirectionFieldCommand` stage:

```
[QueryFailedError] column ViewFilterEntity.relationTargetFieldMetadataId does not exist
  at WorkspaceFlatViewFilterMapCacheService.computeForCache
```

(see
https://github.com/twentyhq/twenty-infra/actions/runs/25929264129/job/76219964380)

Same shape as #20584 (subFieldName), one column over.

### Root cause

1. The 2.3 `DropMessageDirectionFieldCommand` builds a workspace
migration that deletes a `fieldMetadata` (the `direction` field).
2. `WorkspaceMigrationRunnerService.run` walks the metadata cascade
graph and pulls `viewFilter` into the dependency set because
`viewFilter` is the inverse one-to-many of `fieldMetadata`.
3. That maps to cache keys → `flatViewFilterMaps` gets requested →
`WorkspaceFlatViewFilterMapCacheService.computeForCache` runs.
4. `computeForCache` does `viewFilterRepository.find({ where: {
workspaceId }, withDeleted: true })` with no `select`, so TypeORM emits
a SELECT that includes `relationTargetFieldMetadataId` — column only
added by the 2.6 fast instance command `1798000005000`, not yet run at
the 2.3 stage. 💥

### Why v2.5.0 / v2.5.1 passed

They didn't include #20527 (one-hop relation filters, May 14), which
added `relationTargetFieldMetadataId` to `ViewFilterEntity` and the 2.6
instance command. The CI base image (v1.22) seeded the DB, then the
v2.5.0/v2.5.1 container ran upgrade commands against an entity that
didn't yet know about this column.
2026-05-18 10:42:40 +02:00
Charles BochetandGitHub a321e24839 fix(server): scope workspace findOne in incrementMetadataVersion (#20660)
## Summary

Cross-version upgrade fails at the 2.1
`GateExportImportCommandMenuItemsByPermissionFlagCommand` stage:

```
[GateExportImportCommandMenuItemsByPermissionFlagCommand] Found 3 command menu item(s) to update for workspace ...
error: column WorkspaceEntity.isInternalMessagesImportEnabled does not exist
```

(see
https://github.com/twentyhq/twenty-infra/actions/runs/25929264129/job/76219964380)

### Root cause

Same class of bug as #20581 and #20583, one layer deeper in the call
graph.

1. The 2.1 workspace command emits a `commandMenuItem` migration (3
items differ from the current standard expressions).
2. After the migration commits,
`WorkspaceMigrationRunnerService.invalidateCache` walks the
related-for-validation metadata for `commandMenuItem`, which includes
`objectMetadata`. That puts `flatObjectMetadataMaps` in the keys set.
3. `getLegacyCacheInvalidationPromises` sees `flatObjectMetadataMaps` in
the keys and calls
`WorkspaceMetadataVersionService.incrementMetadataVersion(workspaceId)`.
4. `incrementMetadataVersion` did a bare `findOne` on `WorkspaceEntity`
with no `select` → TypeORM emits a SELECT for every column declared on
the entity → hits `isInternalMessagesImportEnabled` (added by #20457),
whose DB column is only created by the 2.5 fast instance command
`1778525104406-add-is-internal-messages-import-enabled`, which has not
run yet at the 2.1 stage. 💥

### Fix

The function only reads `workspace.metadataVersion`, so narrow the
`select` to `['id', 'metadataVersion']`. No behavior change.

```diff
 async incrementMetadataVersion(workspaceId: string): Promise<void> {
   const workspace = await this.workspaceRepository.findOne({
+    select: ['id', 'metadataVersion'],
     where: { id: workspaceId },
     withDeleted: true,
   });
```
2026-05-18 10:36:33 +02:00
nitinandGitHub 3717df34be fix(twenty-front): anchor body text color to theme var (#20622)
Fixes #20607.
also fixes https://github.com/twentyhq/twenty/issues/20627


Front Components rendered via Remote DOM produced black-on-dark text in
dark mode for any unstyled element. `body` already anchored `background`
to a theme var; the matching `color` rule was missing, so unstyled
subtrees fell through to browser default `#000`.

before - 

<img width="850" height="526" alt="CleanShot 2026-05-16 at 16 31 49@2x"
src="https://github.com/user-attachments/assets/ca21359c-d1d1-4367-831e-f694673757e5"
/>

<img width="840" height="1694" alt="CleanShot 2026-05-16 at 16 32 02@2x"
src="https://github.com/user-attachments/assets/ed0891b5-1b97-4499-bb52-9e31c4cabf11"
/>

after - 

<img width="828" height="514" alt="CleanShot 2026-05-16 at 16 30 50@2x"
src="https://github.com/user-attachments/assets/a22d1f1b-a79b-454c-8c05-5c7c00157b2c"
/>

<img width="852" height="1674" alt="CleanShot 2026-05-16 at 16 31 07@2x"
src="https://github.com/user-attachments/assets/9b1dc19e-ccc5-472b-9184-59fa9b8832f8"
/>
2026-05-18 10:29:22 +02:00
Shubham SinghandGitHub 140dceebd1 fix(front): use theme-aware color for side panel title (#20645)
## Summary
- Added `color: ${themeCssVariables.font.color.primary}` to
`StyledPageInfoTitleContainer` in `SidePanelPageInfoLayout.tsx`
- The "Update records" title had no explicit color, so it didn't adapt
to dark mode and was nearly invisible against the dark background
- Now correctly uses the theme-aware primary font color

## Changes
-
`packages/twenty-front/src/modules/side-panel/components/SidePanelPageInfoLayout.tsx`

Fixes #20627
2026-05-18 10:25:34 +02:00
4d2ceaf70a i18n - translations (#20661)
Created by Github action

---------

Co-authored-by: github-actions <[email protected]>
2026-05-18 10:20:30 +02:00
Félix MalfaitandGitHub 6b49a14b9f feat(auth): set 50-character maximum length on passwords (#20655)
## Summary
- Cap password length at 50 characters in the shared regex used by
sign-up, password reset, and password change (both `twenty-front` and
`twenty-server`).
- Update the user-facing validation message on sign-up and password
reset to mention both the 8 min and 50 max bounds.
- Extend the `PASSWORD_REGEX` unit test to cover the new upper bound.

The cap also prevents unbounded inputs from reaching bcrypt, which
silently truncates passwords above 72 bytes and can mask user-visible
bugs.

## Test plan
- [x] `npx jest src/modules/auth/utils/__tests__/passwordRegex.test.ts`
passes (8-char min and 50-char max).
- [ ] Sign up with a 51-character password — form rejects with "Password
must be between 8 and 50 characters".
- [ ] Sign up with an 8–50 character password — succeeds.
- [ ] Password reset rejects a 51-character password with the same
message.
- [ ] Existing users with longer passwords (if any pre-exist) can still
sign in (the regex only gates write paths: sign-up, change, reset).
2026-05-18 10:12:19 +02:00
81 changed files with 224 additions and 201 deletions
+1
View File
@@ -4,6 +4,7 @@ body {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background: var(--t-background-tertiary);
color: var(--t-font-color-primary);
}
html {
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Wagwoord is gestel"
msgid "Password has been updated"
msgstr "Wagwoord is opgedateer"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Wagwoord moet minstens 8 karakters wees"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "تم تعيين كلمة المرور"
msgid "Password has been updated"
msgstr "تم تحديث كلمة السر"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "يجب أن تكون كلمة المرور 8 أحرف على الأقل"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "La contrasenya s'ha establert"
msgid "Password has been updated"
msgstr "La contrasenya s'ha actualitzat"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "La contrasenya ha de tenir almenys 8 caràcters"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Heslo bylo nastaveno"
msgid "Password has been updated"
msgstr "Heslo bylo aktualizováno"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Heslo musí mít alespoň 8 znaků"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Adgangskoden er blevet sat"
msgid "Password has been updated"
msgstr "Password er blevet opdateret"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Adgangskode skal være min. 8 tegn"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Das Passwort wurde aktualisiert"
msgid "Password has been updated"
msgstr "Das Passwort wurde aktualisiert"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Passwort muss mind. 8 Zeichen lang sein"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Ο κωδικός πρόσβασης έχει ρυθμιστεί"
msgid "Password has been updated"
msgstr "Ο κωδικός έχει ενημερωθεί"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Ο κωδικός πρόσβασης πρέπει να είναι τουλάχιστον 8 χαρακτήρες"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11819,11 +11819,11 @@ msgstr "Password has been set"
msgid "Password has been updated"
msgstr "Password has been updated"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Password must be min. 8 characters"
msgid "Password must be between 8 and 50 characters"
msgstr "Password must be between 8 and 50 characters"
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "La contraseña ha sido establecida"
msgid "Password has been updated"
msgstr "La contraseña ha sido actualizada"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "La contraseña debe tener al menos 8 caracteres"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Salasana on asetettu"
msgid "Password has been updated"
msgstr "Salasana on päivitetty"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Salasanassa on oltava vähintään 8 merkkiä"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Le mot de passe a été défini"
msgid "Password has been updated"
msgstr "Le mot de passe a été mis à jour"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Le mot de passe doit comporter au minimum 8 caractères"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
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
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "הסיסמה עודכנה"
msgid "Password has been updated"
msgstr "הסיסמה עודכנה"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "הסיסמה חייבת להיות באורך מינימום 8 תווים"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "A jelszót beállították"
msgid "Password has been updated"
msgstr "A jelszót frissítették"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "A jelszónak legalább 8 karakter hosszúnak kell lennie"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "La password è stata impostata"
msgid "Password has been updated"
msgstr "La password è stata aggiornata"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "La password deve essere di almeno 8 caratteri"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "パスワードが設定されました"
msgid "Password has been updated"
msgstr "パスワードが更新されました"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "パスワードは8文字以上である必要があります"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "비밀번호가 설정되었습니다"
msgid "Password has been updated"
msgstr "비밀번호가 업데이트되었습니다"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "비밀번호는 최소 8자여야 합니다"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Wachtwoord is ingesteld"
msgid "Password has been updated"
msgstr "Wachtwoord is geüpdated"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Wachtwoord moet min. 8 tekens bevatten"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Passordet har blitt satt"
msgid "Password has been updated"
msgstr "Passordet har blitt oppdatert"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Passord må være minst 8 tegn"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Hasło zostało ustawione"
msgid "Password has been updated"
msgstr "Hasło zostało zaktualizowane"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Hasło musi mieć min. 8 znaków"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
@@ -11796,10 +11796,10 @@ msgstr ""
msgid "Password has been updated"
msgstr ""
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "A senha foi definida"
msgid "Password has been updated"
msgstr "A senha foi atualizada"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "A senha deve ter no mínimo 8 caracteres"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "A palavra-passe foi definida"
msgid "Password has been updated"
msgstr "A palavra-passe foi atualizada"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "A palavra-passe deve ter no mínimo 8 caracteres"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Parola a fost setată"
msgid "Password has been updated"
msgstr "Parola a fost actualizată"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Parola trebuie să aibă minimum 8 caractere"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
Binary file not shown.
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Лозинка је постављена"
msgid "Password has been updated"
msgstr "Лозинка је ажурирана"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Лозинка мора имати најмање 8 знакова"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11803,11 +11803,11 @@ msgstr "Lösenordet har ställts in"
msgid "Password has been updated"
msgstr "Lösenordet har uppdaterats"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Lösenord måste vara minst 8 tecken"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Parola ayarlandı"
msgid "Password has been updated"
msgstr "Parola güncellendi"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Parola en az 8 karakter olmalıdır"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Пароль було встановлено"
msgid "Password has been updated"
msgstr "Пароль було оновлено"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Пароль має містити щонайменше 8 символів"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "Mật khẩu đã được thiết lập"
msgid "Password has been updated"
msgstr "Mật khẩu đã được cập nhật"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "Mật khẩu phải có tối thiểu 8 ký tự"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "密码已更新"
msgid "Password has been updated"
msgstr "密码已更新"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "密码长度至少为 8 个字符"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
+3 -3
View File
@@ -11801,11 +11801,11 @@ msgstr "密碼已設定"
msgid "Password has been updated"
msgstr "密碼已更新"
#. js-lingui-id: 1oqxe6
#. js-lingui-id: BfLK2u
#: src/pages/auth/PasswordReset.tsx
#: src/modules/auth/sign-in-up/hooks/useSignInUpForm.ts
msgid "Password must be min. 8 characters"
msgstr "密碼至少需 8 個字元"
msgid "Password must be between 8 and 50 characters"
msgstr ""
#. js-lingui-id: mi6Rel
#: src/modules/auth/sign-in-up/hooks/useHandleResetPassword.ts
@@ -26,7 +26,10 @@ const makeValidationSchema = (signInUpStep: SignInUpStep) =>
signInUpStep === SignInUpStep.Password
? z
.string()
.regex(PASSWORD_REGEX, t`Password must be min. 8 characters`)
.regex(
PASSWORD_REGEX,
t`Password must be between 8 and 50 characters`,
)
: z.string().optional(),
captchaToken: z.string().default(''),
})
@@ -8,4 +8,12 @@ describe('PASSWORD_REGEX', () => {
expect(PASSWORD_REGEX.test(validPassword)).toBe(true);
expect(PASSWORD_REGEX.test(invalidPassword)).toBe(false);
});
it('should match passwords with at most 50 characters', () => {
const validPassword = 'a'.repeat(50);
const invalidPassword = 'a'.repeat(51);
expect(PASSWORD_REGEX.test(validPassword)).toBe(true);
expect(PASSWORD_REGEX.test(invalidPassword)).toBe(false);
});
});
@@ -1 +1 @@
export const PASSWORD_REGEX = /^.{8,}$/;
export const PASSWORD_REGEX = /^.{8,50}$/;
@@ -93,19 +93,6 @@ export const useSaveLayoutCustomization = () => {
continue;
}
await createPendingFieldsWidgetViews(pageLayoutId);
await createPendingRecordTableWidgetViews(pageLayoutId);
const refreshedDraft = store.get(
pageLayoutDraftComponentState.atomFamily({
instanceId: pageLayoutId,
}),
);
if (!isDefined(refreshedDraft)) {
continue;
}
const persistedAsDraft: DraftPageLayout = {
id: persisted.id,
name: persisted.name,
@@ -117,12 +104,15 @@ export const useSaveLayoutCustomization = () => {
};
const isPageLayoutStructureDirty = !isDeeplyEqual(
refreshedDraft,
draft,
persistedAsDraft,
);
await createPendingFieldsWidgetViews(pageLayoutId);
await createPendingRecordTableWidgetViews(pageLayoutId);
if (isPageLayoutStructureDirty) {
const updateInput = convertPageLayoutDraftToUpdateInput(refreshedDraft);
const updateInput = convertPageLayoutDraftToUpdateInput(draft);
const result = await updatePageLayoutWithTabsAndWidgets(
pageLayoutId,
updateInput,
@@ -6,7 +6,6 @@ import { usePerformViewAPIPersist } from '@/views/hooks/internal/usePerformViewA
import { useStore } from 'jotai';
import { useCallback } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { v4 as uuidv4 } from 'uuid';
import { ViewType, WidgetType } from '~/generated-metadata/graphql';
export const useCreatePendingFieldsWidgetViews = () => {
@@ -26,71 +25,26 @@ export const useCreatePendingFieldsWidgetViews = () => {
}),
);
const persistedFieldsWidgetViewIdsByWidgetId = new Map(
(persisted?.tabs ?? [])
.flatMap((tab) => tab.widgets)
.filter((widget) => widget.type === WidgetType.FIELDS)
.map((widget) => [
widget.id,
getWidgetConfigurationViewId(widget.configuration),
]),
);
const draftWithGeneratedViewIds = {
...draft,
tabs: draft.tabs.map((tab) => ({
...tab,
widgets: tab.widgets.map((widget) => {
if (widget.type !== WidgetType.FIELDS) {
return widget;
}
const viewId = getWidgetConfigurationViewId(widget.configuration);
if (isDefined(viewId)) {
return widget;
}
return {
...widget,
configuration: {
...widget.configuration,
viewId: uuidv4(),
},
};
}),
})),
};
store.set(
pageLayoutDraftComponentState.atomFamily({
instanceId: pageLayoutId,
}),
draftWithGeneratedViewIds,
const persistedWidgetIds = new Set(
persisted?.tabs.flatMap((tab) =>
tab.widgets.map((widget) => widget.id),
) ?? [],
);
const objectMetadataItems = store.get(objectMetadataItemsSelector.atom);
const fieldsWidgetsToPersist = draftWithGeneratedViewIds.tabs
const newFieldsWidgets = draft.tabs
.flatMap((tab) => tab.widgets)
.filter((widget) => {
if (widget.type !== WidgetType.FIELDS) {
return false;
}
const viewId = getWidgetConfigurationViewId(widget.configuration);
if (!isDefined(viewId)) {
return false;
}
const persistedViewId =
persistedFieldsWidgetViewIdsByWidgetId.get(widget.id);
return persistedViewId !== viewId;
return isDefined(viewId) && !persistedWidgetIds.has(widget.id);
});
for (const widget of fieldsWidgetsToPersist) {
for (const widget of newFieldsWidgets) {
const viewId = getWidgetConfigurationViewId(widget.configuration);
if (!isDefined(viewId)) {
@@ -29,6 +29,7 @@ export const StyledPageInfoTextContainer = styled.div`
`;
export const StyledPageInfoTitleContainer = styled.div`
color: ${themeCssVariables.font.color.primary};
font-size: ${themeCssVariables.font.size.md};
font-weight: ${themeCssVariables.font.weight.semiBold};
max-width: 150px;
@@ -40,14 +40,14 @@ import {
import { useNavigateApp } from '~/hooks/useNavigateApp';
import { logError } from '~/utils/logError';
const passwordMinLengthMessage = msg`Password must be min. 8 characters`;
const passwordLengthMessage = msg`Password must be between 8 and 50 characters`;
const validationSchema = z
.object({
passwordResetToken: z.string(),
newPassword: z
.string()
.regex(PASSWORD_REGEX, i18n._(passwordMinLengthMessage)),
.regex(PASSWORD_REGEX, i18n._(passwordLengthMessage)),
})
.required();
@@ -0,0 +1,21 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.3.0', 1747234300000)
export class AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`,
);
}
}
@@ -0,0 +1,21 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.4.0', 1747234400000)
export class AddRelationTargetFieldMetadataIdToViewFilterEarly2_4FastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`,
);
}
}
@@ -0,0 +1,21 @@
import { QueryRunner } from 'typeorm';
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
@RegisteredInstanceCommand('2.5.0', 1747234500000)
export class AddRelationTargetFieldMetadataIdToViewFilterEarly2_5FastInstanceCommand
implements FastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`,
);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`,
);
}
}
@@ -9,7 +9,7 @@ export class AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand
{
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" ADD "relationTargetFieldMetadataId" uuid`,
`ALTER TABLE "core"."viewFilter" ADD COLUMN IF NOT EXISTS "relationTargetFieldMetadataId" uuid`,
);
await queryRunner.query(
`CREATE INDEX "IDX_VIEW_FILTER_RELATION_TARGET_FIELD_METADATA_ID" ON "core"."viewFilter" ("relationTargetFieldMetadataId") WHERE "relationTargetFieldMetadataId" IS NOT NULL`,
@@ -27,7 +27,7 @@ export class AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand
`DROP INDEX "core"."IDX_VIEW_FILTER_RELATION_TARGET_FIELD_METADATA_ID"`,
);
await queryRunner.query(
`ALTER TABLE "core"."viewFilter" DROP COLUMN "relationTargetFieldMetadataId"`,
`ALTER TABLE "core"."viewFilter" DROP COLUMN IF EXISTS "relationTargetFieldMetadataId"`,
);
}
}
@@ -21,6 +21,8 @@ import { BackfillPageLayoutWidgetPositionSlowInstanceCommand } from 'src/databas
import { AddCacheTokensToAgentChatThreadFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777455269302-add-cache-tokens-to-agent-chat-thread';
import { AddLogoToApplicationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-2/2-2-instance-command-fast-1777539664664-add-logo-to-application';
import { AddSubFieldNameToViewSortEarlyFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234200000-add-sub-field-name-to-view-sort';
import { AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1747234300000-add-relation-target-field-metadata-id-to-view-filter';
import { AddRelationTargetFieldMetadataIdToViewFilterEarly2_5FastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-5/2-5-instance-command-fast-1747234500000-add-relation-target-field-metadata-id-to-view-filter';
import { AddUpgradeMigrationWorkspaceIdIndexFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777308014234-add-upgrade-migration-workspace-id-index';
import { AddDeletedAtToAgentChatThreadFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777682000000-add-deleted-at-to-agent-chat-thread';
import { ConnectionProviderSyncableEntityFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-fast-1777896012579-connection-provider-syncable-entity';
@@ -30,6 +32,7 @@ import { AddToolAndWorkflowActionTriggerSettingsFastInstanceCommand } from 'src/
import { BackfillApplicationVariableUniversalIdentifierSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-slow-1777966965588-backfill-application-variable-universal-identifier';
import { MigrateToolTriggerSettingsSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-3/2-3-instance-command-slow-1797000002000-migrate-tool-trigger-settings';
import { AddMetadataToBillingPriceFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1777100000000-add-metadata-to-billing-price';
import { AddRelationTargetFieldMetadataIdToViewFilterEarly2_4FastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1747234400000-add-relation-target-field-metadata-id-to-view-filter';
import { AddEmailGroupChannelTypeFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1778256809018-add-email-group-channel-type';
import { AddApplicationIdToPublicDomainFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-4/2-4-instance-command-fast-1798000003000-add-application-id-to-public-domain';
import { AddIsInternalMessagesImportEnabledFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-5/2-5-instance-command-fast-1778525104406-add-is-internal-messages-import-enabled';
@@ -61,11 +64,14 @@ export const INSTANCE_COMMANDS = [
AddPageLayoutIdToCommandMenuItemFastInstanceCommand,
AddConditionalAvailabilityExpressionToPageLayoutWidgetFastInstanceCommand,
AddSubFieldNameToViewSortEarlyFastInstanceCommand,
AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand,
AddRelationTargetFieldMetadataIdToViewFilterEarly2_5FastInstanceCommand,
AddUpgradeMigrationWorkspaceIdIndexFastInstanceCommand,
AddIsPreInstalledToApplicationRegistrationFastInstanceCommand,
AddProviderExecutedToAgentMessagePartFastInstanceCommand,
BackfillPageLayoutWidgetPositionSlowInstanceCommand,
AddMetadataToBillingPriceFastInstanceCommand,
AddRelationTargetFieldMetadataIdToViewFilterEarly2_4FastInstanceCommand,
AddCacheTokensToAgentChatThreadFastInstanceCommand,
AddLogoToApplicationFastInstanceCommand,
AddDeletedAtToAgentChatThreadFastInstanceCommand,
@@ -7,7 +7,7 @@ import {
import * as bcrypt from 'bcrypt';
export const PASSWORD_REGEX = /^.{8,}$/;
export const PASSWORD_REGEX = /^.{8,50}$/;
const saltRounds = 10;
@@ -7,4 +7,4 @@
* |___/
*/
export const TWENTY_CURRENT_VERSION = '2.6.0' as const;
export const TWENTY_CURRENT_VERSION = '2.5.0' as const;
@@ -7,6 +7,4 @@
* |___/
*/
export const TWENTY_NEXT_VERSIONS = [
'2.7.0',
] as const;
export const TWENTY_NEXT_VERSIONS = ['2.6.0'] as const;
@@ -16,5 +16,4 @@ export const TWENTY_PREVIOUS_VERSIONS = [
'2.2.0',
'2.3.0',
'2.4.0',
'2.5.0',
] as const;
@@ -18,7 +18,6 @@ import { WorkspaceMigrationBuilderException } from 'src/engine/workspace-manager
@Catch(
ViewException,
ViewFieldException,
ViewFieldGroupException,
ViewFilterException,
ViewFilterGroupException,
ViewGroupException,
@@ -25,6 +25,7 @@ export class WorkspaceMetadataVersionService {
async incrementMetadataVersion(workspaceId: string): Promise<void> {
const workspace = await this.workspaceRepository.findOne({
select: ['id', 'metadataVersion'],
where: { id: workspaceId },
withDeleted: true,
});