Compare commits

..
Author SHA1 Message Date
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 <github-actions@twenty.com>
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
62b347fc74 chore: sync AI model catalog from models.dev (#20620)
Automated daily sync of `ai-providers.json` from
[models.dev](https://models.dev).

This PR updates pricing, context windows, and model availability based
on the latest data.
New models meeting inclusion criteria (tool calling, pricing data,
context limits) are added automatically.
Deprecated models are detected based on cost-efficiency within the same
model family.

**Please review before merging** — verify no critical models were
incorrectly deprecated.

Co-authored-by: FelixMalfait <6399865+FelixMalfait@users.noreply.github.com>
2026-05-16 08:45:07 +02:00
Charles BochetandGitHub cf4b4455d3 fix(server): normalize composite defaultValues in manifest converter (unblock app re-install on 2.5-normalized workspaces) (#20615)
## Context

The runtime create-field path and the v2.5
`NormalizeCompositeFieldDefaultsCommand` workspace upgrade both run
composite `defaultValue`s through `nullifyEmptyCompositeDefaultValue`.
The manifest install/sync path was the only write path that skipped it:
[`fromFieldManifestToUniversalFlatFieldMetadata`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/core-modules/application/application-manifest/converters/from-field-manifest-to-universal-flat-field-metadata.util.ts)
passed `fieldManifest.defaultValue` through verbatim.

For the SDK-emitted ACTOR system fields (`createdBy` / `updatedBy`),
`twenty-sdk` ships `{ name: "''", source: "'MANUAL'" }`. After the
runtime or the 2.5 normalize command stores them, the workspace row
holds the canonical four-key form `{ context: null, name: null, source:
"'MANUAL'", workspaceMemberId: null }`. The next install computes its TO
map from the manifest, still gets the raw two-key shape, and diffs it
against the normalized FROM. The dispatcher emits a `defaultValue`
update on each system actor field; the flat-field-metadata validator
rejects it with `FIELD_MUTATION_NOT_ALLOWED`, blocking every re-install
of any application that defines a custom object on a v2.5-normalized
workspace.


## Fix

Normalize composite `defaultValue`s inside the converter, reusing the
same `nullifyEmptyCompositeDefaultValue` helper the three other write
paths already share:

-
[`get-default-flat-field-metadata-from-create-field-input.util.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/get-default-flat-field-metadata-from-create-field-input.util.ts)
— `createOneObject` and `createOneField` GraphQL paths.
-
[`sanitize-raw-update-field-input.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/engine/metadata-modules/flat-field-metadata/utils/sanitize-raw-update-field-input.ts)
— `updateOneField` GraphQL path.
-
[`2-5-workspace-command-1778000001000-normalize-composite-field-defaults.command.ts`](https://github.com/twentyhq/twenty/blob/main/packages/twenty-server/src/database/commands/upgrade-version-command/2-5/2-5-workspace-command-1778000001000-normalize-composite-field-defaults.command.ts)
— the upgrade backfill that introduced the divergence.

After the fix, the four write paths agree on the canonical shape, so
re-installs are no-ops on system actor fields regardless of when the 2.5
normalize command ran. Non-composite types pass through unchanged.

## Test

New spec
`from-field-manifest-to-universal-flat-field-metadata.util.spec.ts`
covers:

- Empty-name actor defaults are normalized to the four-key canonical
shape.
- The converter is idempotent: feeding its own output back in produces
the same result (so two consecutive syncs of the same manifest never
emit a `defaultValue` update).
- When the manifest omits `defaultValue`, the converter falls back to
`generateDefaultValue` and normalizes the result.
- Non-composite defaults pass through unchanged.

```
PASS  src/engine/core-modules/application/application-manifest/converters/__tests__/from-field-manifest-to-universal-flat-field-metadata.util.spec.ts
  fromFieldManifestToUniversalFlatFieldMetadata
    composite defaultValue normalization
      ✓ normalizes empty-name actor defaults to the canonical four-key shape
      ✓ is idempotent: re-running the converter on its own output yields the same defaultValue
      ✓ falls back to the generated default and normalizes it when defaultValue is omitted
      ✓ leaves non-composite defaults untouched
Tests: 4 passed
```

## CI gap that let this through

The integration suites covering manifest install (`appDevOnce` against
the test workspace) never re-installed an existing app on a workspace
whose composite fields had already been put through the 2.5 normalize
command. They synced once, then ran assertions on the resulting state;
the second sync that would have re-triggered the `defaultValue` diff was
never exercised.

If we want to catch this class of regression at the integration level
too, we'd add a test that (1) syncs an app whose manifest includes an
ACTOR system field with the raw SDK shape, (2) invokes
`NormalizeCompositeFieldDefaultsCommand` directly on the test workspace,
(3) re-syncs the same manifest, and (4) asserts no
`FIELD_MUTATION_NOT_ALLOWED` errors. The unit-level idempotency check in
this PR is the minimal version of that same coverage. Happy to ship that
integration spec in a follow-up if it'd help.
2026-05-15 18:31:48 +02:00
268fccca29 i18n - translations (#20609)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-05-15 16:51:02 +02:00
c938fbf4d6 feat(twenty-front): relation traversal in filter dropdown (stacked) (#20533)
**Stacked on #20527** 




https://github.com/user-attachments/assets/48995655-401a-4c35-8094-e88da8408bdd





## Summary

Surfaces the one-hop relation traversal added in #20527 through the
existing **composite sub-field dropdown pattern**. Clicking a
MANY_TO_ONE relation field in the "+ Filter" picker now opens the same
second-level dropdown that composite fields (FULL_NAME, ADDRESS,
CURRENCY, etc.) already use — populated with the target object's
filterable fields. Picking one (e.g. `Company → Name`) builds a filter
that serializes to the nested GraphQL filter the backend now accepts: `{
company: { name: { ilike: "%X%" } } }`.

No new components. The whole feature reuses
`AdvancedFilterSubFieldSelectMenu` + the existing
`subFieldNameUsedInDropdownComponentState` + the existing `MenuItem
hasSubMenu` indicator. Only the conditions that gate the sub-menu (and
the sub-menu's content for relations) were broadened.

## What landed

| File | Change |
|---|---|
| `ObjectFilterDropdownFilterSelectMenuItem` | Sub-menu chevron now
shows on MANY_TO_ONE relations (`isManyToOneRelationField` util). |
| `AdvancedFilterFieldSelectMenu` | Relation clicks open the sub-menu
alongside composite clicks. |
| `AdvancedFilterSubFieldSelectMenu` | New branch: when the sub-menu
type is `'RELATION'`, render the target object's filterable fields via
`useFilterableFieldMetadataItems(targetObjectMetadataId)`. Composite
logic untouched. |
| `objectFilterDropdownSubMenuFieldType` state | Widened to accept a
`'RELATION'` sentinel. Role-permissions sub-field menu narrows it back
out (it doesn't traverse relations). |
| `useSelectFieldUsedInAdvancedFilterDropdown` | New optional
`targetFieldMetadataItem` arg. When present, the stored RecordFilter's
`type` is the target field's type so the operand picker and value input
render the target's operands (`'TEXT'` operators when filtering
`company.name`, etc.). |
| `turnRecordFilterIntoGqlOperationFilter` (shared) | When the filter
targets a `RELATION` field with a `subFieldName`, synthesize a
field-metadata for the target, recurse to build the inner filter, then
wrap it under the relation field's name → `{ relationName: {
targetFieldName: { ...operator } } }`. |

`RecordFilter.subFieldName` stays narrowly typed as
`CompositeFieldSubFieldName` so the wide downstream consumers
(`shouldShowFilterTextInput`, composite handlers in the serializer,
etc.) don't change. The relation target field's name is stored through a
narrowly-scoped cast at the dropdown's storage point — the serializer
checks `filter.type === 'RELATION'` before interpreting it as a target
field name, so the cast can't be mis-read by composite-only code paths.

## Test plan

- [ ] Open a table view on People, click "+ Filter", click "Company" →
sub-menu opens with Company's filterable fields
- [ ] Pick "Name" → operand picker shows TEXT operators (Contains,
Equals, …)
- [ ] Type "Airbnb" → filter applies, table shows people whose company
name contains "Airbnb"
- [ ] Verify network tab: the GraphQL filter variable is `{ company: {
name: { ilike: "%Airbnb%" } } }`
- [ ] Same flow with a composite target field (e.g. `Company →
annualRecurringRevenue → amountMicros`) — should work end-to-end
(backend supports composite-within-relation; #20527 has an integration
test covering this)
- [ ] Composite fields (FULL_NAME, ADDRESS) still open their normal
sub-menu and filter correctly — no regression
- [ ] Role-permissions field-select sub-field menu is unaffected (it
bails out early on the RELATION sentinel)

## Out of scope

- ONE_TO_MANY traversal (no backend support yet)
- Aggregates (`people.count > 5`)
- Persisting relation-traversal filters into a saved view (ViewFilter
has no `relationPath` column yet; that's a separate slice)
- REST API DSL changes
- AI Tools

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-15 16:42:47 +02:00
Charles BochetandGitHub eca92ca559 fix(server): rebuild unique phone indexes drops legacy non-empty partial WHERE clause (#20606)
## Summary

`RebuildUniquePhoneIndexesCommand` reuses each index's existing
`indexWhereClause` when recreating the physical index. For workspaces
whose unique phone indexes have a legacy clause like
`"primaryPhoneNumber" != ''` (created before PR #18024 hardened the
validator allowlist), the recreate path fails at
`validateAndReturnIndexWhereClause` because the clause isn't in
`ALLOWED_INDEX_WHERE_CLAUSES`.

Two workspaces are hitting this on the 2.5 upgrade:
- `3a797122-…` — `"companyPhonePrimaryPhoneNumber" != ''`
- `ea74716f-…` — `"phonesPrimaryPhoneNumber" != ''`

## Fix

Detect the legacy `"<col>" != ''` shape via a strict regex. When it's
there, before the existing drop+create, do three things inside the
workspace transaction:

1. **Normalize the data** that the legacy partial clause was masking —
`UPDATE "<schema>"."<table>" SET "<col>" = NULL WHERE "<col>" = ''` for
every column the index covers. Without this the next step would fail
because the new plain-unique index would see duplicate `''` values
across the rows the old partial clause was excluding.
2. **Null out `core."indexMetadata".indexWhereClause`** so the metadata
row matches what the UI would have created (`indexWhereClause: null`)
and doesn't carry the validator-rejected clause forward to any future
re-emit. Uses the same workspace `queryRunner` (Postgres lets one
connection write across schemas).
3. **Recreate** with an overridden flat index where `indexWhereClause:
null`. `createIndexInWorkspaceSchema` → `indexManager.createIndex` →
`validateAndReturnIndexWhereClause` short-circuits on null, no allowlist
check.

End state matches the shape a fresh "toggle unique in Settings UI"
creates: plain unique index, no `WHERE`, NULL semantics doing the
"exclude empty phones" work via PG's default NULL-distinct behaviour.

For indexes whose clause is already allowlisted (`"deletedAt" IS NULL`)
or null, behaviour is unchanged — just the column-list widening this
command already does.
2026-05-15 16:39:34 +02:00
83 changed files with 393 additions and 333 deletions
@@ -23,9 +23,11 @@ jobs:
packages/twenty-sdk/**
packages/twenty-client-sdk/**
packages/twenty-shared/**
packages/twenty-server/**
!packages/twenty-sdk/package.json
!packages/twenty-client-sdk/package.json
!packages/twenty-shared/package.json
!packages/twenty-server/package.json
example-app-postcard:
needs: changed-files-check
@@ -83,6 +85,31 @@ jobs:
working-directory: packages/twenty-apps/examples/postcard
run: npx vitest run
- name: Configure remote for SDK CLI
run: |
mkdir -p ~/.twenty
cat > ~/.twenty/config.json <<EOF
{
"version": 1,
"remotes": {
"target": {
"apiUrl": "${TWENTY_API_URL}",
"apiKey": "${TWENTY_API_KEY}",
"accessToken": "${TWENTY_API_KEY}"
}
},
"defaultRemote": "target"
}
EOF
- name: Deploy postcard app (registry install path)
working-directory: packages/twenty-apps/examples/postcard
run: node ${{ github.workspace }}/packages/twenty-sdk/dist/cli.cjs deploy --remote target
- name: Install postcard app (registry install path)
working-directory: packages/twenty-apps/examples/postcard
run: node ${{ github.workspace }}/packages/twenty-sdk/dist/cli.cjs install --remote target
ci-example-app-postcard-status-check:
if: always() && !cancelled()
timeout-minutes: 5
+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 {
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "En"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Enige {fieldLabel}-veld"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "و"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "أي حقل {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "I"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Qualsevol camp {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "A"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Libovolné pole {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Og"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Ethvert {fieldLabel}-felt"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Und"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Beliebiges {fieldLabel}-Feld"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Και"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Οποιοδήποτε πεδίο {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1958,7 +1958,7 @@ msgid "And"
msgstr "And"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Any {fieldLabel} field"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Y"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Cualquier campo {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Ja"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Mikä tahansa {fieldLabel}-kenttä"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Et"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Tout champ {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "וגם"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "כל שדה {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "És"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Bármely {fieldLabel} mező"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "E"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Qualsiasi campo {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "および"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "任意の {fieldLabel} フィールド"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "및"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "모든 {fieldLabel} 필드"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "En"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Elk {fieldLabel}-veld"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Og"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Ethvert {fieldLabel}-felt"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "I"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Dowolne pole {fieldLabel}"
@@ -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
@@ -1958,7 +1958,7 @@ msgid "And"
msgstr ""
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr ""
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "E"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Qualquer campo {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "E"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Qualquer campo {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Și"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Orice câmp {fieldLabel}"
@@ -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.
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "И"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Било које поље {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Och"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Vilket {fieldLabel}-fält som helst"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Ve"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Herhangi bir {fieldLabel} alanı"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Та"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Будь-яке поле {fieldLabel}"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "Và"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "Bất kỳ trường {fieldLabel} nào"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "且"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "任意 {fieldLabel} 字段"
@@ -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
+4 -4
View File
@@ -1963,7 +1963,7 @@ msgid "And"
msgstr "和"
#. js-lingui-id: KYvJeB
#: src/modules/object-record/advanced-filter/components/AdvancedFilterSubFieldSelectMenu.tsx
#: src/modules/object-record/advanced-filter/components/AdvancedFilterCompositeSubFieldSelectMenu.tsx
msgid "Any {fieldLabel} field"
msgstr "任何 {fieldLabel} 欄位"
@@ -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}$/;
@@ -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"`,
);
}
}
@@ -1,6 +1,7 @@
import { Command } from 'nest-commander';
import { FieldMetadataType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { isNonEmptyString } from '@sniptt/guards';
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
@@ -10,13 +11,17 @@ import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
import { type FlatIndexMetadata } from 'src/engine/metadata-modules/flat-index-metadata/types/flat-index-metadata.type';
import { WorkspaceSchemaManagerService } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.service';
import { computeObjectTargetTable } from 'src/engine/utils/compute-object-target-table.util';
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
import {
computeFlatIndexFieldColumnNames,
createIndexInWorkspaceSchema,
dropIndexFromWorkspaceSchema,
} from 'src/engine/workspace-manager/workspace-migration/workspace-migration-runner/action-handlers/index/utils/index-action-handler.utils';
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
const LEGACY_NON_EMPTY_PARTIAL_INDEX_PATTERN = /^"[a-zA-Z][a-zA-Z0-9]*" != ''$/;
@RegisteredWorkspaceCommand('2.5.0', 1778000000000)
@Command({
name: 'upgrade:2-5:rebuild-unique-phone-indexes',
@@ -103,6 +108,35 @@ export class RebuildUniquePhoneIndexesCommand extends ActiveOrSuspendedWorkspace
flatEntityMaps: flatObjectMetadataMaps,
});
const hasLegacyNonEmptyPartialClause =
isNonEmptyString(uniquePhoneIndex.indexWhereClause) &&
LEGACY_NON_EMPTY_PARTIAL_INDEX_PATTERN.test(
uniquePhoneIndex.indexWhereClause,
);
if (hasLegacyNonEmptyPartialClause) {
const tableName = computeObjectTargetTable(flatObjectMetadata);
const columns = computeFlatIndexFieldColumnNames({
flatIndexFieldMetadatas: uniquePhoneIndex.flatIndexFieldMetadatas,
flatFieldMetadataMaps,
});
for (const column of columns) {
await queryRunner.query(
`UPDATE "${schemaName}"."${tableName}"
SET "${column}" = NULL
WHERE "${column}" = ''`,
);
}
await queryRunner.query(
`UPDATE "core"."indexMetadata"
SET "indexWhereClause" = NULL
WHERE id = $1`,
[uniquePhoneIndex.id],
);
}
await dropIndexFromWorkspaceSchema({
indexName: uniquePhoneIndex.name,
workspaceSchemaManagerService: this.workspaceSchemaManagerService,
@@ -110,8 +144,13 @@ export class RebuildUniquePhoneIndexesCommand extends ActiveOrSuspendedWorkspace
schemaName,
});
const flatIndexMetadataForRebuild: FlatIndexMetadata =
hasLegacyNonEmptyPartialClause
? { ...uniquePhoneIndex, indexWhereClause: null }
: uniquePhoneIndex;
await createIndexInWorkspaceSchema({
flatIndexMetadata: uniquePhoneIndex,
flatIndexMetadata: flatIndexMetadataForRebuild,
flatObjectMetadata,
flatFieldMetadataMaps,
workspaceSchemaManagerService: this.workspaceSchemaManagerService,
@@ -120,7 +159,7 @@ export class RebuildUniquePhoneIndexesCommand extends ActiveOrSuspendedWorkspace
});
this.logger.log(
`Rebuilt unique phone index ${uniquePhoneIndex.name} for workspace ${workspaceId}`,
`Rebuilt unique phone index ${uniquePhoneIndex.name} for workspace ${workspaceId}${hasLegacyNonEmptyPartialClause ? ' (dropped legacy non-empty partial WHERE clause)' : ''}`,
);
}
await queryRunner.commitTransaction();
@@ -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,7 @@ 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 { 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';
@@ -61,6 +62,7 @@ export const INSTANCE_COMMANDS = [
AddPageLayoutIdToCommandMenuItemFastInstanceCommand,
AddConditionalAvailabilityExpressionToPageLayoutWidgetFastInstanceCommand,
AddSubFieldNameToViewSortEarlyFastInstanceCommand,
AddRelationTargetFieldMetadataIdToViewFilterEarlyFastInstanceCommand,
AddUpgradeMigrationWorkspaceIdIndexFastInstanceCommand,
AddIsPreInstalledToApplicationRegistrationFastInstanceCommand,
AddProviderExecutedToAgentMessagePartFastInstanceCommand,
@@ -0,0 +1,108 @@
import { type FieldManifest } from 'twenty-shared/application';
import {
type FieldMetadataDefaultActor,
FieldMetadataType,
} from 'twenty-shared/types';
import { fromFieldManifestToUniversalFlatFieldMetadata } from 'src/engine/core-modules/application/application-manifest/converters/from-field-manifest-to-universal-flat-field-metadata.util';
const APP_UID = '11111111-1111-1111-1111-111111111111';
const OBJECT_UID = '22222222-2222-2222-2222-222222222222';
const FIELD_UID = '33333333-3333-3333-3333-333333333333';
const NOW = '2026-05-15T10:00:00.000Z';
const buildFieldManifest = (
overrides: Partial<FieldManifest>,
): FieldManifest & { objectUniversalIdentifier: string } =>
({
universalIdentifier: FIELD_UID,
type: FieldMetadataType.TEXT,
name: 'demo',
label: 'Demo',
objectUniversalIdentifier: OBJECT_UID,
...overrides,
}) as FieldManifest & { objectUniversalIdentifier: string };
describe('fromFieldManifestToUniversalFlatFieldMetadata', () => {
describe('composite defaultValue normalization', () => {
it('normalizes empty-name actor defaults to the canonical four-key shape', () => {
const result = fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: buildFieldManifest({
type: FieldMetadataType.ACTOR,
name: 'createdBy',
label: 'Created by',
defaultValue: { name: "''", source: "'MANUAL'" },
}),
applicationUniversalIdentifier: APP_UID,
now: NOW,
});
expect(result.defaultValue).toEqual({
context: null,
name: null,
source: "'MANUAL'",
workspaceMemberId: null,
});
});
it('is idempotent: re-running the converter on its own output yields the same defaultValue', () => {
const first = fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: buildFieldManifest({
type: FieldMetadataType.ACTOR,
name: 'createdBy',
label: 'Created by',
defaultValue: { name: "''", source: "'MANUAL'" },
}),
applicationUniversalIdentifier: APP_UID,
now: NOW,
});
const second = fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: buildFieldManifest({
type: FieldMetadataType.ACTOR,
name: 'createdBy',
label: 'Created by',
defaultValue: first.defaultValue as FieldMetadataDefaultActor,
}),
applicationUniversalIdentifier: APP_UID,
now: NOW,
});
expect(second.defaultValue).toEqual(first.defaultValue);
});
it('falls back to the generated default and normalizes it when defaultValue is omitted', () => {
const result = fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: buildFieldManifest({
type: FieldMetadataType.ACTOR,
name: 'updatedBy',
label: 'Updated by',
}),
applicationUniversalIdentifier: APP_UID,
now: NOW,
});
expect(result.defaultValue).toEqual({
context: null,
name: "'System'",
source: "'MANUAL'",
workspaceMemberId: null,
});
});
it('leaves non-composite defaults untouched', () => {
const result = fromFieldManifestToUniversalFlatFieldMetadata({
fieldManifest: buildFieldManifest({
type: FieldMetadataType.TEXT,
name: 'title',
label: 'Title',
defaultValue: "'todo'",
}),
applicationUniversalIdentifier: APP_UID,
now: NOW,
});
expect(result.defaultValue).toBe("'todo'");
});
});
});
@@ -8,7 +8,10 @@ import {
ApplicationException,
ApplicationExceptionCode,
} from 'src/engine/core-modules/application/application.exception';
import { type CompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/types/composite-field-metadata-type.type';
import { isCompositeFieldMetadataType } from 'src/engine/metadata-modules/field-metadata/utils/is-composite-field-metadata-type.util';
import { generateDefaultValue } from 'src/engine/metadata-modules/field-metadata/utils/generate-default-value';
import { nullifyEmptyCompositeDefaultValue } from 'src/engine/metadata-modules/flat-field-metadata/utils/nullify-empty-composite-default-value.util';
import { PARTIAL_SYSTEM_FLAT_FIELD_METADATAS } from 'src/engine/metadata-modules/object-metadata/constants/partial-system-flat-field-metadatas.constant';
import { isMorphOrRelationFieldMetadataType } from 'src/engine/utils/is-morph-or-relation-field-metadata-type.util';
import { type UniversalFlatFieldMetadata } from 'src/engine/workspace-manager/workspace-migration/universal-flat-entity/types/universal-flat-field-metadata.type';
@@ -65,6 +68,18 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
relationTargetObjectMetadataUniversalIdentifier,
} = getRelationTargetUniversalIdentifiers(fieldManifest);
// TODO: generate system fields server-side from the object manifest
// so the converter doesn't need to re-normalize composite defaults
// that the SDK couldn't have known the canonical shape of.
const rawDefaultValue =
fieldManifest.defaultValue ?? generateDefaultValue(fieldManifest.type);
const defaultValue = isCompositeFieldMetadataType(fieldManifest.type)
? nullifyEmptyCompositeDefaultValue({
defaultValue: rawDefaultValue,
fieldType: fieldManifest.type as CompositeFieldMetadataType,
})
: rawDefaultValue;
return {
universalIdentifier: fieldManifest.universalIdentifier,
applicationUniversalIdentifier,
@@ -75,8 +90,7 @@ export const fromFieldManifestToUniversalFlatFieldMetadata = ({
icon: fieldManifest.icon ?? null,
standardOverrides: null,
options: fieldManifest.options ?? null,
defaultValue:
fieldManifest.defaultValue ?? generateDefaultValue(fieldManifest.type),
defaultValue,
universalSettings: fieldManifest.universalSettings ?? null,
isCustom: true,
isActive: true,
@@ -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;
@@ -1420,18 +1420,6 @@
"maxOutputTokens": 30000,
"modalities": ["image"]
},
{
"name": "grok-4-1-fast",
"label": "Grok 4.1 Fast",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.2,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.05,
"contextWindowTokens": 2000000,
"maxOutputTokens": 30000,
"modalities": ["image"],
"supportsReasoning": true
},
{
"name": "grok-4.20-0309-reasoning",
"label": "Grok 4.20 (Reasoning)",
@@ -1450,17 +1438,6 @@
"modalities": ["image"],
"supportsReasoning": true
},
{
"name": "grok-3-mini-fast-latest",
"label": "Grok 3 Mini Fast Latest",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.6,
"outputCostPerMillionTokens": 4,
"cachedInputCostPerMillionTokens": 0.15,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192,
"supportsReasoning": true
},
{
"name": "grok-vision-beta",
"label": "Grok Vision Beta",
@@ -1472,70 +1449,6 @@
"maxOutputTokens": 4096,
"modalities": ["image"]
},
{
"name": "grok-3-mini",
"label": "Grok 3 Mini",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.3,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.075,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192,
"supportsReasoning": true
},
{
"name": "grok-3-fast-latest",
"label": "Grok 3 Fast Latest",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 5,
"outputCostPerMillionTokens": 25,
"cachedInputCostPerMillionTokens": 1.25,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192
},
{
"name": "grok-4-1-fast-non-reasoning",
"label": "Grok 4.1 Fast (Non-Reasoning)",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.2,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.05,
"contextWindowTokens": 2000000,
"maxOutputTokens": 30000,
"modalities": ["image"]
},
{
"name": "grok-4",
"label": "Grok 4",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 3,
"outputCostPerMillionTokens": 15,
"cachedInputCostPerMillionTokens": 0.75,
"contextWindowTokens": 256000,
"maxOutputTokens": 64000,
"supportsReasoning": true
},
{
"name": "grok-code-fast-1",
"label": "Grok Code Fast 1",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.2,
"outputCostPerMillionTokens": 1.5,
"cachedInputCostPerMillionTokens": 0.02,
"contextWindowTokens": 256000,
"maxOutputTokens": 10000,
"supportsReasoning": true
},
{
"name": "grok-3-latest",
"label": "Grok 3 Latest",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 3,
"outputCostPerMillionTokens": 15,
"cachedInputCostPerMillionTokens": 0.75,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192
},
{
"name": "grok-2-vision-1212",
"label": "Grok 2 Vision (1212)",
@@ -1547,17 +1460,6 @@
"maxOutputTokens": 4096,
"modalities": ["image"]
},
{
"name": "grok-3-mini-fast",
"label": "Grok 3 Mini Fast",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.6,
"outputCostPerMillionTokens": 4,
"cachedInputCostPerMillionTokens": 0.15,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192,
"supportsReasoning": true
},
{
"name": "grok-2-1212",
"label": "Grok 2 (1212)",
@@ -1599,17 +1501,6 @@
"maxOutputTokens": 4096,
"modalities": ["image"]
},
{
"name": "grok-3-mini-latest",
"label": "Grok 3 Mini Latest",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.3,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.075,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192,
"supportsReasoning": true
},
{
"name": "grok-4.3",
"label": "Grok 4.3",
@@ -1639,16 +1530,6 @@
"maxOutputTokens": 4096,
"modalities": ["image"]
},
{
"name": "grok-3-fast",
"label": "Grok 3 Fast",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 5,
"outputCostPerMillionTokens": 25,
"cachedInputCostPerMillionTokens": 1.25,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192
},
{
"name": "grok-2-latest",
"label": "Grok 2 Latest",
@@ -1658,39 +1539,6 @@
"cachedInputCostPerMillionTokens": 2,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192
},
{
"name": "grok-4-fast",
"label": "Grok 4 Fast",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.2,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.05,
"contextWindowTokens": 2000000,
"maxOutputTokens": 30000,
"modalities": ["image"],
"supportsReasoning": true
},
{
"name": "grok-3",
"label": "Grok 3",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 3,
"outputCostPerMillionTokens": 15,
"cachedInputCostPerMillionTokens": 0.75,
"contextWindowTokens": 131072,
"maxOutputTokens": 8192
},
{
"name": "grok-4-fast-non-reasoning",
"label": "Grok 4 Fast (Non-Reasoning)",
"modelFamily": "GROK",
"inputCostPerMillionTokens": 0.2,
"outputCostPerMillionTokens": 0.5,
"cachedInputCostPerMillionTokens": 0.05,
"contextWindowTokens": 2000000,
"maxOutputTokens": 30000,
"modalities": ["image"]
}
]
}
@@ -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,
});
@@ -69,21 +69,7 @@ export class FindRecordsWorkflowAction implements WorkflowAction {
workspaceId,
);
// Relation-traversal filters reference target fields on related
// objects, which aren't in flatObjectMetadata.fieldIds. Collect the
// referenced target ids from the record filters so the shared
// dispatcher can resolve them and avoid silently dropping the filter.
const relationTargetFieldIds = (
workflowActionInput.filter?.recordFilters ?? []
)
.map((filter) => filter.relationTargetFieldMetadataId)
.filter(isDefined);
const fieldIds = Array.from(
new Set([...flatObjectMetadata.fieldIds, ...relationTargetFieldIds]),
);
const fields = fieldIds
const fields = flatObjectMetadata.fieldIds
.map((fieldId) => {
const field = findFlatEntityByIdInFlatEntityMaps({
flatEntityId: fieldId,
@@ -206,6 +206,7 @@ exports[`syncApplication should delete old field and create equivalent one when
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"defaultValue": {
"context": null,
"name": "'System'",
"source": "'MANUAL'",
"workspaceMemberId": null,
@@ -236,6 +237,7 @@ exports[`syncApplication should delete old field and create equivalent one when
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"defaultValue": {
"context": null,
"name": "'System'",
"source": "'MANUAL'",
"workspaceMemberId": null,
@@ -562,6 +564,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"defaultValue": {
"context": null,
"name": "'System'",
"source": "'MANUAL'",
"workspaceMemberId": null,
@@ -592,6 +595,7 @@ exports[`syncApplication should return workspace migration actions on initial sy
"applicationUniversalIdentifier": Any<String>,
"createdAt": Any<String>,
"defaultValue": {
"context": null,
"name": "'System'",
"source": "'MANUAL'",
"workspaceMemberId": null,