0d3c7a47af27d5a67fa36b27f109cc35bfdd4752
12501 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
0d3c7a47af |
fix: guard against undefined logicFunctionId when destroying workflow CODE steps (#21256)
## Summary - Adds `isDefined` guard in `handleLogicFunctionSubEntities` to skip CODE steps with undefined `logicFunctionId` instead of crashing - Adds same guard in `runWorkflowVersionStepDeletionSideEffects` for consistency - Rejects CODE steps in `create_complete_workflow` AI tool at runtime to prevent creating workflows with missing logic functions in the first place Fixes `"Logic function with id undefined not found"` INTERNAL_SERVER_ERROR when destroying workflows whose CODE steps were created via `create_complete_workflow` without a proper logic function. ## Test plan - [x] Destroy a workflow that has a CODE step with undefined logicFunctionId → should succeed silently - [x] Try creating a workflow with a CODE step via `create_complete_workflow` tool → should return error message - [x] Normal workflow destroy with valid CODE steps still deletes the logic function |
||
|
|
2dbdd72e65 |
chore: bump version to 2.11.0 (#21259)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
f20d04eb6e |
feat(app-dev): surface metadata diff in dev sync and name failing migration actions (#21249)
Split out of #21240. - Render the applied metadata changes (created/updated/deleted + identifiers) in the dev sync output instead of a bare `✓ Synced`. - Include the failing entity's `universalIdentifier` in `WorkspaceMigrationRunnerException` messages so conflicts are diagnosable. <img width="637" height="114" alt="image" src="https://github.com/user-attachments/assets/61422a16-370c-4e9b-a2f6-c29ce17f3b1b" /> <img width="497" height="104" alt="image" src="https://github.com/user-attachments/assets/d493c398-da29-49c9-ac5e-aa0f26cd7389" /> <img width="593" height="127" alt="image" src="https://github.com/user-attachments/assets/15e26edc-c0e4-4427-bd34-909040e970c9" /> --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
f72898063a | upgrade command patch - warn instead of throw when no calendarEvent object found in the workspace (#21258) | ||
|
|
e485b679ea |
[Call Recording] Add standard object (#21158)
Adds **Call Recording** as a first-class standard object (Twenty's
flat-metadata
standard-object system), with a hidden junction to calendar events and a
backfill
command for existing workspaces. Everything is gated behind the
`IS_CALL_RECORDING_ENABLED` feature flag.
### What's included
- **`CallRecording`**: audio/video files, transcript, status, recording
policy,
timing, external bot/recording ids. Label identifier is
`meetingOccurrenceKey`.
- **`CallRecordingCalendarEventAssociation`**: hidden junction linking a
recording
to a calendar event (dedupes one bot to many subscribers of the same
meeting).
- Full metadata graph via the flat-metadata builders: fields, indexes,
views,
view fields/groups, record page layout, and navigation items.
- **Metadata-only reverse relation** on `CalendarEvent`: present in
standard
metadata, omitted from the TS entity class to avoid expanding recursive
nested-insert types.
- **Upgrade command (2.9.0)** backfilling active/suspended workspaces:
- Creates the full graph; idempotent (skips when it already exists).
- Moves a colliding custom `callRecording` object aside to
`callRecordingOld`
(numeric suffix if that name is also taken).
- Navigation items (commands) are flag-gated by `universalIdentifier`,
so a custom object
reusing the name is never gated.
### QA
Run locally against existing workspaces (with and without a name
collision) and a
freshly created workspace:
- [x] Backfill, collision: custom `callRecording` renamed to
`callRecordingOld`;
standard graph created.
- [x] Backfill, no collision: standard graph created; unrelated custom
object untouched.
- [x] Idempotent: re-run is a no-op, with no duplicate metadata and
counts unchanged.
- [x] New workspace via `init()` produces an identical graph to the
backfill
(`universalIdentifier` set-diff = 0).
- [x] Label identifier (`meetingOccurrenceKey`) holds position 0 in
non-widget views.
- [x] Nav items gated behind the feature flag; collision-renamed
object's nav
expression re-pointed to its new name.
- [x] Unit tests cover collision name resolution and nav-gating logic.
|
||
|
|
a78b319877 |
sdk/v* twenty/v* namespaces (#21247)
# Introduction Removed never used release dispatch workflow Now assuming that anyone releasing will create both twenty and npm family tags Will create a workflow to ease this later We will now start to have several github releases, one per namespace |
||
|
|
c3dd6b25a6 |
fix: use canonical oxlint rule id in lint-disable directives (#21253)
## What Many `oxlint-disable` / `eslint-disable` directives across the repo carry a corrupted rule id — `@typescripttypescript/<rule>` — most likely a find-and-replace accident that mangled the eslint-era `@typescript-eslint/` prefix. oxlint matches disable directives **loosely by rule name**, so these still suppress in practice (not a silent no-op), but the id is malformed and misleading. ## Change Replace them with the **canonical oxlint id** `typescript/<rule>` — matching the plugin name and rule keys declared in `.oxlintrc.json` — **127 files, 262 directives**: | rule | count | | --- | ----- | | `typescript/no-explicit-any` | 250 | | `typescript/ban-ts-comment` | 6 | | `typescript/no-misused-promises` | 4 | | `typescript/no-empty-object-type` | 2 | - `twenty-server`: 122 files - `twenty-front`: 5 files Comment-only — no code or runtime changes. ## Verification `oxlint --type-aware -c .oxlintrc.json` reports **0 warnings / 0 errors** for both `twenty-server` and `twenty-front`. Every changed line is exactly the id correction inside a disable directive (262 insertions / 262 deletions, no collateral edits). > Addresses the cubic review, which flagged that the canonical oxlint id is `typescript/...` (no `@`). Worth noting the original `@typescripttypescript/` was not actually a silent no-op — oxlint matches these directives loosely by rule name — but `typescript/` is the correct, config-aligned id. |
||
|
|
6f9b59b224 |
Scaffold twenty-new-ui (#21236)
Scaffolds `twenty-new-ui`, the next-gen replacement for `twenty-ui`, on **SCSS** Modules + **Base UI** (no Linaria). - **Tooling**: Vite lib build, subpaths mirror twenty-ui, typed SCSS Modules, Storybook + axe a11y, size-limit, Nx targets. - **Theme**: single token source → nx generateTheme emits the CSS vars + accessor; parity test asserts token-for-token match with twenty-ui. Migrated a first `Toggle` component with its stories to allow @charlesBochet to wire the new pixel-diff system. --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
b60a91a075 |
fix(website): render releases from local notes, drop GitHub gate (#21238)
The releases page gated visible notes on fetchLatestGithubReleaseTag(); when that unauthenticated GitHub call was rate-limited at build (common on shared Cloudflare build IPs, no GITHUB_TOKEN), it returned null and getVisibleReleaseNotes returned [], rendering 'No releases are visible yet for the current published version' — the exact prod symptom. force-static made each deploy a coin flip. Committed MDX (+images) is the single source of truth, so gate visibility on nothing: render all local notes deterministically with no network call. Removes the dev/prod divergence and deletes the now-dead fetch-latest-release-tag.ts and get-visible-releases.ts. |
||
|
|
cd540098f1 |
fix: pass reference_commit to Argos to resolve orphan PR builds (#21245)
## Summary - Fixes Argos CI builds showing as "Orphan" (no reference branch) for PR builds - Computes the merge-base SHA between the PR head and `main` using the GitHub API (`compareCommitsWithBasehead`) in the dispatch workflow - Passes `reference_commit` in the `ci-privileged` dispatch payload so it can be forwarded to the Argos upload API ## Context PR builds on Argos were showing as "Orphan" because `ci-privileged` (where the actual Argos upload happens) has no git history of the `twenty` repo — it cannot compute the merge-base locally. Without a `referenceCommit`, Argos can't determine which `main` build to compare against. The local `visual-diff.sh` script already passes `ARGOS_REFERENCE_COMMIT` via `git merge-base HEAD main`, but the CI pipeline was missing this. This PR adds equivalent logic using the GitHub API (no checkout needed). ## Note for ci-privileged The `upload-to-argos.ts` script in `ci-privileged` needs a corresponding update to read `reference_commit` from the dispatch payload and pass it as `referenceCommit` in the Argos API call: ```typescript referenceCommit: process.env.REFERENCE_COMMIT || undefined, ``` ## Test plan - [ ] Verify the workflow runs successfully on a PR (merge-base step computes a SHA) - [ ] Confirm Argos PR builds are no longer marked as "Orphan" after the ci-privileged counterpart is updated |
||
|
|
1b30983307 |
fix(settings): gate the AI settings page on AI_SETTINGS, not the chat flag (#21239)
## Summary Closes #21229. The two AI role permissions behaved **opposite to their labels**. The trap is that the flag's code name is the inverse of its UI label: | `PermissionFlagType` | UI label | Section | Means | |---|---|---|---| | `AI` | **"Ask AI"** | Actions | End-user: chat with AI | | `AI_SETTINGS` | **"AI"** | Member / settings | Admin: configure AI agents | Before this PR (on `main`): - `AI` ("Ask AI", chat) gated **both** the AI chat **and** the AI settings page. - `AI_SETTINGS` ("AI", configure agents) gated **nothing** the user could see. So a chat-only user could reach the whole AI **configuration** page, and toggling the "AI" settings permission did nothing — exactly the misalignment reported in #21229. ## Root cause `PermissionFlagType.AI` *reads* like "the AI permission", so it looks like the natural gate for the AI settings page — but it's actually the **chat** flag. The settings page (nav item + route) had been pointed at `AI` in #21072 to match the Overview stats query (`findWorkspaceAiStats`), which was itself mis-gated on `AI`. Both the stats query and the rest of the settings surface are admin/config features, so they belong on `AI_SETTINGS`. ## Changes All three move the **AI settings surface** from the chat flag (`AI`) to the settings flag (`AI_SETTINGS`); chat keeps following `AI`: - `useSettingsNavigationItems.tsx` — AI nav item → `AI_SETTINGS` - `SettingsRoutes.tsx` — AI settings route group → `AI_SETTINGS` - `ai-workspace-stats.resolver.ts` — `findWorkspaceAiStats` (settings-only, drives the Overview tab) → `AI_SETTINGS` After this: the "AI" permission controls the AI settings page + its Overview; the "Ask AI" permission controls the chat. Both toggles now match their labels. ## Test plan - [ ] Role with **only "Ask AI"** (`AI`): AI chat tabs/pane visible; **Settings → AI is hidden** and the route is not reachable. - [ ] Role with **only "AI"** (`AI_SETTINGS`): Settings → AI is visible, Overview stats load; chat nav is hidden. - [ ] Admin (both flags): everything works as before. ## Known follow-ups (out of scope — pre-existing, shared endpoints) These remain on `AI` because they're shared with non-settings surfaces and need either OR-gating or a resolver split, so a role with `AI_SETTINGS` but **not** `AI` still can't use them yet: - `getAiSystemPromptPreview` (Models/Prompts tabs) lives in the chat resolver, class-gated `AI`; NestJS guards are additive so it can't be cleanly method-overridden — it should be pulled into a settings resolver. - Agent reads `findManyAgents` / `findOneAgent` (agent create/edit forms) are class-gated `AI` and shared with the **Workflow** editor and **Roles** pages; these want a guard that accepts `AI ∨ AI_SETTINGS ∨ WORKFLOWS`. |
||
|
|
128d2d394d |
feat: allow apps to add view fields to existing views (defineViewField) (#21160)
## Summary
Lets a Twenty application add **view fields (columns) to an existing
view it does not own** — including standard views like the People index
view — without redeclaring/owning that view. This mirrors the existing,
working pattern by which an app adds a custom field to a standard object
via `defineField` + `objectUniversalIdentifier`.
The asymmetry being removed was purely in the manifest schema:
`ViewFieldManifest` only existed *nested* inside
`ViewManifest.fields[]`, so adding a view field forced declaring a
`ViewManifest` — which the sync treats as a view the app creates and
owns, and rejects when the UID is a standard view's. Validation,
persistence, the FK aggregator machinery, and uninstall cleanup were
already generic and cross-app-safe, so no engine changes were needed.
### Changes
- **twenty-shared:** new top-level `StandaloneViewFieldManifest`
(`ViewFieldManifest & { viewUniversalIdentifier }`),
`Manifest.viewFields`, and a `SyncableEntity.ViewField` member.
- **twenty-sdk:** `defineViewField` (validates `universalIdentifier` +
`viewUniversalIdentifier` + `fieldMetadataUniversalIdentifier`), CLI
manifest assembly of a top-level `viewFields` list, and `dev:add
viewField` scaffolding.
- **twenty-server:** one top-level loop over `manifest.viewFields` that
reuses the existing `fromViewFieldManifestToUniversalFlatViewField`
converter (already parameterized by `viewUniversalIdentifier`). No
validator/persistence/aggregator changes.
### Notes for maintainers
- Confirm the `Manifest.viewFields` optionality convention — implemented
as a **required** array to mirror `fields`/`views`.
- Two different apps adding a column for the same field to the same view
conflicts on the existing unique `(fieldMetadataId, viewId)` partial
index; the existing `flat-view-field-validator` duplicate check surfaces
this as a structured validation error.
- `dev:add viewField` scaffolding is included (was optional in the
plan).
## Test Plan
- [x] `twenty-shared` typecheck
- [x] `twenty-sdk` 364 unit tests + `buildManifest` assembly test
(rich-app fixture) + typecheck + prettier
- [x] `twenty-server` typecheck + `lint:diff-with-main`
- [x] **Server integration suite**
`successful-manifest-update-view-field.integration-spec.ts` (4/4):
- standalone view field attaches to the standard `allPeople` view
without recreating it (sync succeeds, no
`INVALID_VIEW_DATA`/`ENTITY_ALREADY_EXISTS`)
- uninstall removes the contributed column while the standard view + its
columns remain intact
- duplicate `(view, field)` rejected with `METADATA_VALIDATION_FAILED`
- unknown target view rejected
- [x] Sibling `successful-manifest-update-field.integration-spec.ts`
still green (no harness regression)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||
|
|
ff9b5a5cad |
chore: sync AI model catalog from models.dev (#21242)
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> |
||
|
|
979047d004 |
fix: allow email change verification on self-hosted instances (#20123)
fixes #20117 ## Technical Details Flow after fix: 1. User submits email change request 2. user.service.ts:517-524 calls sendVerificationEmail() with verificationTrigger: EMAIL_UPDATE 3. Guard checks: verificationTrigger === SIGN_UP → false → guard skipped 4. Verification token generated, email rendered and sent via emailService.send() 5. User receives confirmation email at new address 6. User clicks confirmation link → email update completes --- Impact - Minimal change: Only 3 lines modified in a single file - No breaking changes: Sign-up verification behavior unchanged - Security preserved: Email changes always require verification (correct security behavior) - Self-hosted friendly: Instance admins can disable sign-up verification while keeping email change verification active --------- Co-authored-by: Charles Bochet <charles@twenty.com> |
||
|
|
8bd4cbc3fd |
fix(ai) - optim (#21233)
1. tool-registry.service.ts, Pass precomputed catalog to resolveSchemas() resolveSchemas() now accepts an optional precomputedCatalog parameter. Both getToolsByName() and getToolInfo() pass the catalog they already fetched, eliminating a redundant getCatalog() rebuild inside resolveSchemas(). 2. database-tool.provider.ts, Skip field lookup when schemas=false When building the catalog index (includeSchemas=false), getFlatFieldsFromFlatObjectMetadata() is no longer called for each of the 25 objects. The hasGroupByToolInputSchema() check is also skipped, group_by tools are always included in the index, with the real eligibility check deferred to learn_tools time. --> 100/150ms gain on learn/execute_tool execution |
||
|
|
f899660a40 |
i18n - docs translations (#21237)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
0877ba2ffd |
Fix getApplicationSubAllFlatEntityMaps to prune unrelated appIds universal identifier aggregators (#21234)
# Introduction Atm when computing the `fromAllFlatEntityMaps` we're retrieving all the applicationIds related metadata entities to build a flat entity maps scoped to them ( atm always the applicationId + twenty-standard application id ) only inter app dependency we manage for the moment A flat entity contains universal identifier aggregator to its related entities The issue was that the `getApplicationSubAllFlatEntityMaps` wasn't pruning the aggregator by app Now added a new process phase after the initial one that will check that all the aggregators contains universal identifiers that has been retrieve from the appId + appId standard intersection ## TDD test Created a very human readable ( that's a joke ) test |
||
|
|
4e1cc2d831 |
fix: prevent workflow from disappearing after activation (#21231)
## Summary - Fixes a regression from #21176 where activating a workflow caused it to disappear until page refresh - Root cause: when a draft is activated (status DRAFT→ACTIVE), `useEffectiveDraftVersionId` incorrectly treated it as a discard because the cached version was no longer DRAFT, filtering it from the versions list - Fix: only set `lastDiscardedDraftId` when `deletedAt` is actually set on the cached version, not when the status simply changes ## Test plan - [x] Open a workflow with a DRAFT version - [x] Activate the workflow → verify it does NOT disappear - [x] Discard a draft → verify header does NOT flicker between DRAFT/ACTIVE |
||
|
|
c2ca90c255 |
feat(sdk): add runAgent() to run app agents from logic functions (#21157)
<img width="948" height="593" alt="image" src="https://github.com/user-attachments/assets/d990fa98-3cfd-469d-ab7f-0b2d4ccf3afc" /> <img width="1361" height="802" alt="image" src="https://github.com/user-attachments/assets/1091f598-49f3-4c16-92ea-1e1c200181e2" /> ## Add `runAgent()` to the Logic Function SDK Lets an app's logic function run one of its own AI agents server-side and get the result back synchronously — reusing the existing agent executor instead of a new bespoke transport. ### Backend - New **`runAgent` GraphQL mutation** (metadata schema) in `ai-agent-execution`, wrapping the existing `AgentAsyncExecutorService.executeAgent`. Scopes the agent lookup to the calling application and runs it under an application auth context. - New `@AuthApplication()` param decorator (mirrors `@AuthWorkspace()`) — first GraphQL resolver authenticated by an **application access token**. - Guarded by `WorkspaceAuthGuard` + `SettingsPermissionGuard(PermissionFlagType.AI)`: the app's role must grant the `AI` permission flag. ### SDK - `runAgent({ agentUniversalIdentifier, prompt })` posts the mutation to `/metadata` with the app token via a new runtime GraphQL transport. Returns `{ result, hasNoMoreAvailableCredits }`. - Refactored the connections helpers onto a shared `postAppEndpoint` util (removes duplicated transport logic). ### Frontend - App install permission modal now shows an explicit consent line — _"Run AI agents and bill AI credits to your workspace"_ — when the app's role requests the `AI` flag. ### Docs - Documented `runAgent` and its `AI` permission-flag requirement in _Skills & Agents_. - Fixed outdated role-permission examples in _Roles & Permissions_ (`permissionFlags` → `permissionFlagUniversalIdentifiers`, `PermissionFlag` → `SystemPermissionFlag`). ### Test plan - [x] SDK unit tests (`run-agent.spec.ts`) — request shape, GraphQL/HTTP error handling, missing env vars - [x] `twenty-server`, `twenty-front`, `twenty-shared` typecheck + lint - [ ] Manual: install an app granting the `AI` flag, call `runAgent()` from a logic function, confirm the agent runs and credits are billed --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> |
||
|
|
36b654bab3 |
Scaffold people data labs enrichment app (#21175)
# Scaffold People Data Labs enrichment app Defines the data model for enriching **Person** and **Company** with People Data Labs data. **Scaffold only** — the enrichment logic (the "mapper") follows separately; see the package README. ## Included - **Fields** on Person & Company (PDL base data set). - **Enums as SELECT / MULTI_SELECT** validated against PDL canonical files (v34.1). - **Standard-field mapping**: no `pdl*` shadow where a standard field exists. - **Location → ADDRESS**; **relation** `pdlCurrentCompany` ↔ `pdlCurrentEmployees`. - **Metadata**: `pdlId`, `pdlLikelihood`, `pdlEnrichmentStatus`, `pdlLastEnrichedAt`, `pdlRawPayload`. - Shared option constants + helper, indexes, and a view per object. |
||
|
|
41d5d80a65 |
Migrate Company and Person standard fields in preparation for the enrichment app (#21171)
# Migrate Company and Person standard fields in preparation for the
enrichment app
## Why
Our standard `Person`/`Company` objects accumulated fields that aren't
generic to every
business, while missing a more universal revenue field that essentially
every CRM ships.
This PR makes the **Standard application** hold a tighter, more
universal set of fields,
and sets the stage for a follow-up PR that introduces a **People Data
Labs enrichment app**
to populate them.
## What changes
### Standard fields
**Demoted (Standard → Workspace Custom application)** — not generic
enough to ship as standard:
| Object | Field | Type |
| ------- | ------------------------------ | -------- |
| Company | annualRecurringRevenue (ARR) | CURRENCY |
| Company | employees | NUMBER |
| Company | idealCustomerProfile (ICP) | BOOLEAN |
| Company | xLink (X/Twitter) | LINKS |
| Person | xLink (X/Twitter) | LINKS |
| Person | city | TEXT |
**Added (new generic Standard field)** — present in
Salesforce/HubSpot/Zoho, PDL-populatable:
| Object | Field | Type |
| ------- | ------------- |
-------------------------------------------------------- |
| Company | annualRevenue | CURRENCY (generic total revenue; replaces
the niche ARR) |
### Behavior by workspace
* **New workspaces:** demoted fields are gone; `annualRevenue` is
**active**.
* **Existing workspaces:** demoted fields are **preserved as active
custom fields, data intact**;
`annualRevenue` is created **inactive (opt-in)** with its column ready,
so a later activation
is a metadata-only toggle.
### Upgrade commands (v2.9)
Three idempotent, per-workspace commands, run in timestamp order:
1. **`upgrade:2-9:move-demoted-standard-fields-to-custom-application`**
(1799000040000) —
re-owns the 6 demoted fields to the workspace custom application
(`isCustom = true`,
new `applicationId` + fresh `universalIdentifier`), keeping their data
and active state.
2. **`upgrade:2-9:rename-conflicting-custom-fields`** (1799000045000) —
if a workspace already
has a *custom* field named `annualRevenue`, renames it to
`annualRevenueCustom`
(data preserved via column rename) so the standard field can be added.
Skips non-custom matches.
3. **`upgrade:2-9:add-inactive-generic-standard-fields`**
(1799000050000) — creates
`Company.annualRevenue` on existing workspaces as inactive, guarded to
skip workspaces
missing the target object or where the name is still taken.
**Failure model:** the workspace iterator isolates failures per
workspace (one workspace failing
never affects others); within a workspace the runner records per-command
status and resumes on the
next run, and every command is idempotent, so partial runs self-heal.
### Supporting changes
* **Field-option color palette:** widened the `TagColor` union
(`twenty-shared` `FieldMetadataOptions`
+ the field-metadata `options.input` DTO) from 10 colors to the full
theme palette, benefiting any
future SELECT/MULTI_SELECT field.
* **Dev seeder:**
* The default "Annual Recurring Revenue" dashboard widget now points at
the generic
`annualRevenue` field (renamed to "Annual Revenue").
* Removed the "Companies by Size (Stacked by City)" widget (relied on
the demoted `employees`).
* `employees` is dropped from company data seeds and re-added as a
**custom** field seed, so dev
workspaces still get an `employees` column matching the demoted
behavior.
### Cleanup
Front-end record types (`Company.ts`/`Person.ts`), the
`getDisplayNameFromParticipant` test mock,
metadata integration specs, the Zapier `crud_record` test, and the
regenerated
`get-standard-object-metadata-related-entity-ids` snapshot.
## ⚠️ Breaking change (intentional)
Removes standard fields `Company.annualRecurringRevenue`,
`Company.employees`,
`Company.idealCustomerProfile`, `Company.xLink`, `Person.xLink`, and
`Person.city` from the core
GraphQL schema (replaced by `Company.annualRevenue`).
This is why the breaking-changes check reports a large number of
removals — `graphql-inspector`
flags any removed object field plus its derived
aggregate/order-by/filter/update types.
**Mitigation:** the
`upgrade:2-9:move-demoted-standard-fields-to-custom-application` command
re-owns these fields as custom fields per workspace, preserving their
name and data, so existing
tenants keep working. New workspaces won't have them.
|
||
|
|
e0d42323af |
Add more control on http trigger (#21216)
add "new Response" utils to define response code or content type of http route triggered logic function responses follow up of https://github.com/twentyhq/twenty/pull/21214 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
d3a1781a59 |
Use serialize-javascript for JSON-LD serialization on twenty-website (#21223)
Our scanner flags the `dangerouslySetInnerHTML` in `JsonLd.tsx` as a potential XSS sink. Since JSON-LD must be emitted as raw `<script type="application/ld+json">` text (rendering it as a React child HTML-entity-escapes it and corrupts the JSON, and the site is statically generated so it must be in the SSG HTML for crawlers), `dangerouslySetInnerHTML` is the correct, Next.js-documented approach (the real fix is sanitizing the payload). This PR swaps our hand-rolled `JSON.stringify().replace(/</g, ...)` for [`serialize-javascript`](https://www.npmjs.com/package/serialize-javascript) in `isJSON` mode, the maintained library [Next.js explicitly recommends](https://nextjs.org/docs/app/guides/json-ld) for this, so the script-unsafe characters are escaped by a vetted serializer rather than custom code. |
||
|
|
70066cdcf4 |
Update Google Workspace and integration logo assets (#21185)
## Summary - Replace the Gmail and Google Calendar assets with their May 2026 icon refreshes. - Update the shared Google, Google Meet, Microsoft Outlook, Microsoft Calendar-provider, Docusign, Stripe, Tally, and Zapier logo assets. - Regenerate matching website/front raster assets at their existing dimensions. ## Preview GitHub's file diff can render some tiny transparent SVG/WebP logo diffs as nearly empty. This grid uses the final raster assets from the PR branch; Stripe and Zapier use their official favicon marks. | Logo | Preview | | --- | --- | | Gmail | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/gmail.webp" width="48" height="48" alt="Gmail logo" /> | | Google Calendar | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/calendar.webp" width="48" height="48" alt="Google Calendar logo" /> | | Google | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/google.webp" width="48" height="48" alt="Google logo" /> | | Google Meet | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/meet.webp" width="48" height="48" alt="Google Meet logo" /> | | Microsoft Outlook / Calendar | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/outlook.webp" width="48" height="48" alt="Microsoft Outlook / Calendar logo" /> | | Docusign | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/docusign.webp" width="48" height="48" alt="Docusign logo" /> | | Stripe | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/stripe.webp" width="48" height="48" alt="Stripe logo" /> | | Tally | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/tally.webp" width="48" height="48" alt="Tally logo" /> | | Zapier | <img src="https://raw.githubusercontent.com/twentyhq/twenty/bonapara/update-gmail-icon/packages/twenty-website/public/images/shared/companies/logos/zapier.webp" width="48" height="48" alt="Zapier logo" /> | ## Notes - Microsoft Calendar now uses the current Outlook/M365 icon, matching the provider users connect for Microsoft calendar sync. - Docusign keeps the compact Nexus mark for the small square logo slot, regenerated from the current official Docusign lockup. - Stripe now uses the official favicon mark from stripe.com. - Zapier now uses the official square favicon mark from zapier.com. ## Sources - Gmail 2026: https://upload.wikimedia.org/wikipedia/commons/8/8f/Gmail_icon_%282026%29.svg - Google Calendar 2026: https://upload.wikimedia.org/wikipedia/commons/f/fa/Google_Calendar_icon_%282026%29.svg - Google gradient G: https://blog.google/company-news/inside-google/company-announcements/gradient-g-logo-design/ - Google Meet 2026: https://commons.wikimedia.org/wiki/File:Google_Meet_icon_(2026).svg - Microsoft 365 icon refresh: https://techcommunity.microsoft.com/blog/microsoft365insiderblog/new-microsoft-365-icons-for-the-ai-era/4458674 - Docusign logo guidelines: https://brand.docusign.com/logo - Stripe favicon: https://images.stripeassets.com/fzn2n1nzq965/1hgcBNd12BfT9VLgbId7By/01d91920114b124fb4cf6d448f9f06eb/favicon.svg - Tally press kit: https://tally.so/help/press-kit - Zapier favicon: https://zapier.com/favicon.ico ## Validation - Confirmed touched UI SVGs transform through SVGR successfully. - Confirmed regenerated raster dimensions and alpha metadata with Sharp. - Reviewed a generated contact sheet at 72px, 40px, and 16px. - Ran `git diff --check`. - Ran `packages/twenty-ui` Vite build with ARM Node v24.5.0: `/Users/thomascolasdesfrancs/.nvm/versions/node/v24.5.0/bin/node ../../node_modules/vite/bin/vite.js build`. Local note: `npx vite build` fails in `packages/twenty-ui` on this machine because that directory resolves `/usr/local/bin/node` as x64 v23.5.0 while the Yarn install links Rollup's ARM optional package. The direct ARM Node build above passed. |
||
|
|
a7fed47932 |
fix(twenty-ui): prevent local visual diffs from polluting CI baselines (#21225)
## Summary - **Username-prefix branches**: Local visual-diff builds now use `charles/main` instead of `main` as the branch name, preventing local runs from creating auto-approved reference builds that could overwrite CI baselines. - **Local merge-base computation**: Computes `ARGOS_REFERENCE_COMMIT` via `git merge-base HEAD main` locally, so the Argos SDK skips `git fetch origin <branch>` — fixing the "fatal: couldn't find remote ref" error when running from non-pushed branches. - **Pass `referenceCommit` to vitest plugin**: Ensures the locally computed merge-base is forwarded to the Argos upload. ## Test plan - [x] Verified local visual-diff works from `main` branch (branch becomes `charles/main`, not auto-approved) - [x] Verified local visual-diff works from a non-pushed branch (`test/local-only-visual-diff` → build uploaded successfully) |
||
|
|
f4da7767f8 |
chore: remove Chromatic dependencies and configuration (#21221)
## Summary
- Remove `chromatic` and `@chromatic-com/storybook` devDependencies from
twenty-front
- Remove global `chromatic` Nx target from nx.json and twenty-front
project.json override
- Remove commented Chromatic Storybook addon from twenty-front
- Remove `CHROMATIC_PROJECT_TOKEN` from .env.example
- Update README to remove Chromatic sponsor reference (image was already
missing)
- Update stale Chromatic comment in toSpliced.ts
## Context
Visual regression testing has moved from Chromatic SaaS to self-hosted
Argos at `argos.twenty-internal.com`. These are dead references that are
no longer used by any CI workflow.
**Note:** Story `parameters.chromatic: { disableSnapshot: true }`
entries are intentionally kept — the Argos plugin reads them as a
fallback.
## Test plan
- Verify `yarn install` succeeds after dependency removal
- Verify no workflow references `chromatic` or `nx chromatic`
|
||
|
|
badeaddd37 |
fix(ci): ensure ui-sb-test runs on push to main (#21222)
## Summary - Add explicit `if: always() && needs.ui-sb-build.result == 'success'` to `ui-sb-test` job ## Context After merging #21217, the main-branch Argos baseline pipeline doesn't work: `ui-sb-test` is silently skipped on push to main, so no `argos-screenshots-twenty-ui` artifact is produced. **Root cause:** `changed-files-check` is skipped on push events (PR-only). `ui-sb-build` handles this with `if: always() && ...`, but `ui-sb-test` has no explicit `if` — GitHub Actions propagates the skip through the transitive dependency chain (`changed-files-check` → `ui-sb-build` → `ui-sb-test`). ## Test plan - Merge this PR and verify the next push to main produces the `argos-screenshots-twenty-ui` artifact - Verify `dispatch-main` successfully triggers ci-privileged with the artifact |
||
|
|
9042e8a542 |
feat(ci): Argos main baselines + local visual diff support (#21217)
## Summary **CI: Main-branch Argos baselines** - Run storybook build + screenshot capture on `push` to `main` in CI UI workflow - Add `dispatch-main` job in visual regression dispatch to forward main-branch screenshots to ci-privileged - Simplify `dispatch-pr` by inlining the artifact name and removing unused `project` output **Local visual diff support** - Add `scripts/visual-diff.sh` for running Argos uploads locally via tunnel - Add `storybook:visual-diff` Nx target wrapping the script (depends on `storybook:build`) - Honor `STORYBOOK_URL` env in `vitest.config.ts` to reuse pre-served static builds (mirrors twenty-front pattern) - Support `ARGOS_BUILD_NAME`, `ARGOS_REFERENCE_BRANCH` env overrides in vitest plugin config ## Context Argos builds on PRs are all "Orphan" because there's no reference build on `main` to compare against. The CI changes add the missing piece: every merge to main now produces screenshots and uploads them to Argos as reference builds. The local visual diff script enables developers to run visual regression checks from their machine against the self-hosted Argos instance via `kubectl port-forward` (set up by the twenty-infra `argos-tunnel` command). ## Related - twentyhq/twenty-argos#1 (backend config for self-hosted HTTPS redirect) - twentyhq/twenty-infra#709 (argos-tunnel super CLI command + self-hosted mode) ## Test plan - [ ] Verify CI UI runs on next push to main and produces the `argos-screenshots-twenty-ui` artifact - [ ] Verify `dispatch-main` triggers and uploads screenshots to Argos - [ ] Verify subsequent PR builds show diffs against the main baseline instead of "Orphan" - [ ] Run `ARGOS_TOKEN=<token> npx nx storybook:visual-diff twenty-ui` locally with tunnel active |
||
|
|
100b08e827 |
i18n - website translations (#21220)
Created by Github action --------- Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
437eed0862 |
fix(messaging): fix reply-quotation stripping that emptied email bodies (#21118)
some synced messages were stored with empty bodies, others with the entire reply thread re-quoted, planer was stripping entirely quoted forwards down to nothing and not trimming inline reply history at all switched plaintext quote stripping to `email-reply-parser`, falling back to the full text when it strips everything so forwards don't end up blank. kept planer for the html path, and normalized body whitespac --------- Co-authored-by: prastoin <paul@twenty.com> |
||
|
|
5a55021e26 |
feat(website): add /partners/apply standalone page (#21219)
## Summary - Adds a standalone `/partners/apply` page — a shareable URL that opens the partner application wizard full-page (no modal, no nav, no footer), on a plain black background - Adds a `slots` prop to `PartnerApplicationWizard` so it can render outside a `Dialog.Root` context (Base UI), keeping the existing modal on `/partners` completely untouched - Surfaces logic function errors to the user: the API route now checks the webhook response body for `ok: true`, so a silent backend failure no longer shows a false success state ## Test plan - [ ] `yarn jest --no-coverage` — 365/365 passing - [ ] `npx oxlint -c .oxlintrc.json .` — 0 errors (1 pre-existing warning unrelated to this PR) - [ ] `npx oxfmt --check .` — clean - [ ] `npx tsc --noEmit` — clean - [ ] Visit `/partners/apply` — wizard loads full-page on black background, no menu, no footer - [ ] Complete the wizard and submit — redirects to `/partners/list` - [ ] Visit `/partners` — "Become a partner" modal still opens normally |
||
|
|
63435a7937 |
Twenty new ui README (#21186)
Generated a twenty new ui implementation plan README after the discussion with @charlesBochet |
||
|
|
6a2c948e84 |
chore: bump version to 2.10.0 (#21218)
## Summary - Moves current version to previous versions array - Sets TWENTY_CURRENT_VERSION to the new version - Updates TWENTY_NEXT_VERSIONS with the next minor version - Bumps twenty-client-sdk, twenty-sdk, and create-twenty-app to the same version ## Checklist - [ ] Verify version constants are correct - [ ] Verify npm package versions match Co-authored-by: Github Action Deploy <github-action-deploy@twenty.com> |
||
|
|
b53f1832d8 |
feat(ci): simplify visual regression dispatch to twenty-ui only (#21215)
## Summary - Only trigger visual regression on `CI UI` workflow (drop `CI Front`) - Remove tarball re-packaging step — `ci-privileged` now downloads the artifact directly via GitHub API - Remove `mode`/`project` parameters from the dispatch payload (hardcoded to twenty-ui in ci-privileged) - Pass `run_id` of the triggering CI UI workflow so ci-privileged can fetch the correct artifact ## Context Part of the fast visual regression CI initiative. The `ci-privileged` workflow has been simplified to only handle `twenty-ui` screenshots uploaded directly to Argos. ## Test plan - [x] Full E2E verified on production: screenshots → Argos build → diff results → PR comment |
||
|
|
3d49642d12 |
[AUDIT] Run knip over twenty-server (#21159)
# Introduction Run [knip](https://knip.dev/) over twenty-server Used config: ```json { "$schema": "https://unpkg.com/knip@5/schema.json", "workspaces": { "packages/twenty-server": { "entry": [ "src/main.ts", "src/command/command.ts", "src/queue-worker/queue-worker.ts", "src/database/scripts/setup-db.ts", "src/database/scripts/truncate-db.ts", "src/database/clickHouse/migrations/run-migrations.ts", "src/database/clickHouse/seeds/run-seeds.ts", "src/instrument.ts", "lingui.config.ts", "test/integration/graphql/codegen/index.ts", "test/integration/utils/setup-test.ts", "test/integration/utils/teardown-test.ts", "scripts/**/*.ts", "**/*.spec.ts", "**/*.integration-spec.ts" ], "project": ["src/**/*.ts", "test/**/*.ts", "scripts/**/*.ts"], "ignore": [ "src/database/typeorm/**/migrations/**", "src/database/typeorm/**/*.entity.ts", "**/*.workspace-entity.ts", "**/logic-function-resource/constants/seed-project/**" ], "ignoreDependencies": ["@types/psl", "@types/aws-lambda"], "ignoreBinaries": ["nest", "lingui", "typeorm"] } } } ``` |
||
|
|
4ad8d8e98e |
Set 200 code for post requests (#21214)
as title, nestJS use to set 201 for post requests but some services (like google) requests 200 response code See https://discord.com/channels/1130383047699738754/1511054250971758642/1511785364027609099 for context |
||
|
|
475cd9e7fe | fix(upgrade): resequence workflow step logs command (#21213) | ||
|
|
f0be78e629 |
chore(deps-dev): bump prettier from 3.4.2 to 3.8.3 (#21205)
Bumps [prettier](https://github.com/prettier/prettier) from 3.4.2 to 3.8.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>3.8.3</h2> <ul> <li>SCSS: Prevent trailing comma in <code>if()</code> function (<a href="https://redirect.github.com/prettier/prettier/pull/18471">prettier/prettier#18471</a> by <a href="https://github.com/kovsu"><code>@kovsu</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.8.3/CHANGELOG.md#383">Changelog</a></p> <h2>3.8.2</h2> <ul> <li>Support Angular v21.2</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#382">Changelog</a></p> <h2>3.8.1</h2> <ul> <li>Include available <code>printers</code> in plugin type declarations (<a href="https://redirect.github.com/prettier/prettier/pull/18706">#18706</a> by <a href="https://github.com/porada"><code>@porada</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#381">Changelog</a></p> <h2>3.8.0</h2> <ul> <li>Support Angular v21.1</li> </ul> <p><a href="https://github.com/prettier/prettier/compare/3.7.4...3.8.0">diff</a></p> <p>🔗 <a href="https://prettier.io/blog/2026/01/14/3.8.0">Release note "Prettier 3.8: Support for Angular v21.1"</a></p> <h2>3.7.4</h2> <h2>What's Changed</h2> <ul> <li>Fix comment in union type gets duplicated by <a href="https://github.com/fisker"><code>@fisker</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18393">prettier/prettier#18393</a></li> <li>Fix unstable comment print in union type by <a href="https://github.com/fisker"><code>@fisker</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18395">prettier/prettier#18395</a></li> <li>Avoid quote around LWC interpolations by <a href="https://github.com/kovsu"><code>@kovsu</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18383">prettier/prettier#18383</a></li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#374">Changelog</a></p> <h2>3.7.3</h2> <h2>What's Changed</h2> <ul> <li>Fix <code>prettier.getFileInfo()</code> change that breaks VSCode extension by <a href="https://github.com/fisker"><code>@fisker</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18375">prettier/prettier#18375</a></li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#373">Changelog</a></p> <h2>3.7.2</h2> <h2>What's Changed</h2> <ul> <li>Fix string print when switching quotes by <a href="https://github.com/fisker"><code>@fisker</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18351">prettier/prettier#18351</a></li> <li>Preserve quote for embedded HTML attribute values by <a href="https://github.com/kovsu"><code>@kovsu</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18352">prettier/prettier#18352</a></li> <li>Fix comment in empty type literal by <a href="https://github.com/fisker"><code>@fisker</code></a> in <a href="https://redirect.github.com/prettier/prettier/pull/18364">prettier/prettier#18364</a></li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#372">Changelog</a></p> <h2>3.7.1</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>3.8.3</h1> <p><a href="https://github.com/prettier/prettier/compare/3.8.2...3.8.3">diff</a></p> <h4>SCSS: Prevent trailing comma in <code>if()</code> function (<a href="https://redirect.github.com/prettier/prettier/pull/18471">#18471</a> by <a href="https://github.com/kovsu"><code>@kovsu</code></a>)</h4> <!-- raw HTML omitted --> <pre lang="scss"><code>// Input $value: if(sass(false): 1; else: -1); <p>// Prettier 3.8.2 $value: if( sass(false): 1; else: -1, );</p> <p>// Prettier 3.8.3 $value: if(sass(false): 1; else: -1); </code></pre></p> <h1>3.8.2</h1> <p><a href="https://github.com/prettier/prettier/compare/3.8.1...3.8.2">diff</a></p> <h4>Angular: Support Angular v21.2 (<a href="https://redirect.github.com/prettier/prettier/pull/18722">#18722</a>, <a href="https://redirect.github.com/prettier/prettier/pull/19034">#19034</a> by <a href="https://github.com/fisker"><code>@fisker</code></a>)</h4> <p>Exhaustive typechecking with <code>@default never;</code></p> <!-- raw HTML omitted --> <pre lang="html"><code><!-- Input --> @switch (foo) { @case (1) {} @default never; } <p><!-- Prettier 3.8.1 --> SyntaxError: Incomplete block "default never". If you meant to write the @ character, you should use the "&<a href="https://redirect.github.com/prettier/prettier/issues/64">#64</a>;" HTML entity instead. (3:3)</p> <p><!-- Prettier 3.8.2 --> <a href="https://github.com/switch"><code>@switch</code></a> (foo) { <a href="https://github.com/case"><code>@case</code></a> (1) {} <a href="https://github.com/default"><code>@default</code></a> never; } </code></pre></p> <p><code>arrow function</code> and <code>instanceof</code> expressions.</p> <!-- raw HTML omitted --> <pre lang="html"><code></tr></table> </code></pre> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/prettier/prettier/commit/d7108a79ec745c04292aabf22c4c1adbd690b191"><code>d7108a7</code></a> Release 3.8.3</li> <li><a href="https://github.com/prettier/prettier/commit/177f90898170d363ef64fde663e4d13170688bfe"><code>177f908</code></a> Prevent trailing comma in SCSS <code>if()</code> function (<a href="https://redirect.github.com/prettier/prettier/issues/18471">#18471</a>)</li> <li><a href="https://github.com/prettier/prettier/commit/1cd40668c3d6f2f4cf9d87bbc9096d92361b2606"><code>1cd4066</code></a> Release <code>@prettier/plugin-oxc</code><a href="https://github.com/0"><code>@0</code></a>.1.4</li> <li><a href="https://github.com/prettier/prettier/commit/a8700e245038cd8cc0cf28ef06ffedbcb3fc2dfc"><code>a8700e2</code></a> Update oxc-parser to v0.125.0</li> <li><a href="https://github.com/prettier/prettier/commit/752157c78eca6f0a30e5d5cb513b682c5ecfa01e"><code>752157c</code></a> Fix tests</li> <li><a href="https://github.com/prettier/prettier/commit/053fd418e180b12fa2014260212fae831f5fc5ec"><code>053fd41</code></a> Bump Prettier dependency to 3.8.2</li> <li><a href="https://github.com/prettier/prettier/commit/904c6365ec46726fd0e21021c52ae934b7e5abc6"><code>904c636</code></a> Clean changelog_unreleased</li> <li><a href="https://github.com/prettier/prettier/commit/dc1f7fcc508d116cbf1644d69a1f0eb93e40d4a4"><code>dc1f7fc</code></a> Update dependents count</li> <li><a href="https://github.com/prettier/prettier/commit/b31557cf331a02acf83e7e29d1001b070189a0d9"><code>b31557c</code></a> Release 3.8.2</li> <li><a href="https://github.com/prettier/prettier/commit/96bbaeda0525bf758e464aed2f939d739a85c315"><code>96bbaed</code></a> Support Angular v21.2 (<a href="https://redirect.github.com/prettier/prettier/issues/18722">#18722</a>)</li> <li>Additional commits viewable in <a href="https://github.com/prettier/prettier/compare/3.4.2...3.8.3">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for prettier since your current version.</p> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
fe5337b7d0 |
chore(deps-dev): bump @types/passport-microsoft from 2.1.0 to 2.1.1 (#21204)
Bumps [@types/passport-microsoft](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/passport-microsoft) from 2.1.0 to 2.1.1. <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/passport-microsoft">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
f50e471385 |
chore(deps): bump @mantine/hooks from 8.3.15 to 8.3.18 (#21203)
Bumps [@mantine/hooks](https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks) from 8.3.15 to 8.3.18. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/mantinedev/mantine/releases">@mantine/hooks's releases</a>.</em></p> <blockquote> <h2>8.3.18</h2> <p>This is the last 8.x release. You are welcome to test 9.0 alpha version and provide feedback before its release on March 31 – <a href="https://alpha.mantine.dev/changelog/9-0-0/">https://alpha.mantine.dev/changelog/9-0-0/</a></p> <ul> <li><code>[@mantine/core]</code> PasswordInput: Fix styles api props not resolving correctly in theme (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8716">#8716</a>)</li> </ul> <h2>8.3.17</h2> <h2>Changes</h2> <ul> <li><code>[@mantine/core]</code> Stepper: Fix Google Translate compatibility issues (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8744">#8744</a>)</li> <li><code>[@mantine/hooks]</code> use-list-state: Add memoization to all handlers (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8739">#8739</a>)</li> </ul> <h2>8.3.16</h2> <h2>What's Changed</h2> <ul> <li><code>[@mantine/modals]</code> Fix <code>onClose</code> being called multiple times (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8727">#8727</a>)</li> <li><code>[@mantine/core]</code> Tooltip: Fix component not throwing erro when used with string (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8694">#8694</a>)</li> <li><code>[@mantine/core]</code> NumberInput: Fix incorrect decimal separator parsing in <code>onPaste</code></li> <li><code>[@mantine/core]</code> AppShell: Fix <code>layout="alt"</code> not working with <code>mode="static"</code></li> <li><code>[@mantine/stotlight]</code> Fix actions list being rendered when nothing found message was not set (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8592">#8592</a>)</li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/mantinedev/mantine/compare/8.3.15...8.3.16">https://github.com/mantinedev/mantine/compare/8.3.15...8.3.16</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/mantinedev/mantine/commit/530249feb498d74d5ea849d2984c86efd072f38c"><code>530249f</code></a> [release] Version: 8.3.18</li> <li><a href="https://github.com/mantinedev/mantine/commit/bac61d6fc21be84bd80d1d9232a605c05692ae75"><code>bac61d6</code></a> [release] Version: 8.3.17</li> <li><a href="https://github.com/mantinedev/mantine/commit/6b3fdee137584aece43b88b62d8c207a58c35295"><code>6b3fdee</code></a> [refactor] Fix formatting</li> <li><a href="https://github.com/mantinedev/mantine/commit/c048f996cc1a8287bd9eaba1bb59bc6637316b90"><code>c048f99</code></a> [<code>@mantine/hooks</code>] use-list-state: Add memoization to all handlers (<a href="https://github.com/mantinedev/mantine/tree/HEAD/packages/@mantine/hooks/issues/8739">#8739</a>)</li> <li><a href="https://github.com/mantinedev/mantine/commit/dbb8732ca3350259e0cf7b2536d0bcc885b1b587"><code>dbb8732</code></a> [release] Version: 8.3.16</li> <li>See full diff in <a href="https://github.com/mantinedev/mantine/commits/8.3.18/packages/@mantine/hooks">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
a3a44c8315 |
fix(front): settings skeleton, app-detail header & empty favorites (#21209)
Three small post-redesign UI fixes. Each is an independent commit, so they can be split into separate PRs if preferred. ## 1. Settings loading skeleton — match the rounded-card layout The redesign (#21131) moved settings chrome into a rounded card (`SettingsPageLayout`: bordered header with breadcrumb + centered title, optional secondary bar, 760px body), but `SettingsSkeletonLoader` still rendered the old flat `PageHeader` + `PageBody` — so pages painted as a full-width flat bar then snapped into the card. - `SettingsSkeletonLoader` now reproduces the card and **reuses the real `SettingsPageHeader` + `SettingsPageContainer`**, so the frame aligns by construction; the card CSS is replicated (not `SettingsPageLayout`) to avoid the layout's side effects (hotkeys, side panel, info banner). - It's **composed with `SettingsSectionSkeletonLoader`** so the loading body is identical whether or not chrome is present. Rule: no chrome on screen yet → full-page skeleton; chrome already on screen → body-only `SettingsSectionSkeletonLoader` (the admin Enterprise tab now uses it, matching its sibling tabs). A short comment on each component documents this. ## 2. Application detail header — pass a plain title `SettingsApplicationDetails` / `SettingsAvailableApplicationDetails` passed a custom `SettingsApplicationDetailTitle` (avatar + name + multi-line description, fixed width) into `SettingsPageLayout`'s **centered single-line title slot**, which broke the header. They now pass the app's display name like every other page. The available-app "unlisted" notice moves into the body as a reusable `InlineBanner`; the now-unused `SettingsApplicationDetailTitle` is removed. ## 3. Navigation — hide Favorites when empty Always rendering the Favorites section (#21087) left a stray "Favorites" title above Workspace for users with no favorites. It now renders only when at least one favorite exists (redundant per-child guards dropped). Note: the "+ add favorite" entry point therefore appears once you have ≥1 favorite; the first favorite is created from a record/view as before. ## Verification - `nx typecheck twenty-front` ✅ · `oxlint` + `oxfmt --check` on changed files ✅ - i18n catalogs intentionally untouched — handled by the repo's separate i18n pipeline. |
||
|
|
e99116b0a5 |
chore: sync AI model catalog from models.dev (#21212)
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> |
||
|
|
2ac515894b |
feat(settings): add Logs as a dedicated tab in General settings (#21180)
## What & why The audit-log viewer lived as a full-screen page reachable only via a "View Logs" button buried in the **Security** tab. This surfaces it as the **third tab in General settings** (`General | Security | Logs`), consistent with the other tabs. ## Changes - **Relocated** the event-logs module `pages/settings/security/event-logs/` → `modules/settings/event-logs/` and render it as tab content instead of a `FullScreenContainer` page. Dropped `SettingsPath.EventLogs`, its route, and the fullscreen handling in favor of the `general#logs` hash tab. - **Security tab:** removed the "View Logs" entry; kept the log-retention setting there. - **In-tab gating** (shown to users with the Security permission): Enterprise upgrade card when not entitled, a clear "ClickHouse not configured" placeholder otherwise (derived from client config), and the query is skipped when disabled. Replaces a bespoke error component that string-matched error messages with the shared `SettingsEmptyPlaceholder` / `SettingsEnterpriseFeatureGateCard`. - **Layout:** boxed content column with the table selector + filters grouped in a `Card` and the results table below, matching settings conventions. Kept the existing fixed filters (page/event name, member, period) rather than recreating the record-view filter chips (those are tightly coupled to record/view context). Frontend + `twenty-shared` only — no changes to the log query or data. ## Test plan - [x] `npx nx typecheck twenty-front` and `npx nx lint twenty-front` pass - [x] Settings → General shows three tabs; Logs is the third; breadcrumb stays "Workspace / General" - [x] With Enterprise + ClickHouse: table selector, filters, refresh, and the paginated table work - [x] Non-Enterprise: Enterprise upgrade card shown; no failing query fires - [ ] Enterprise without ClickHouse: shows the "ClickHouse not configured" placeholder - [ ] Security tab still shows the log-retention setting and the "View Logs" button is gone - [ ] A user without the Security permission sees neither the Security nor Logs tab |
||
|
|
e6614299c6 |
feat(ci): integrate Argos visual regression via vitest screenshots (#21210)
## Summary
- Adds `@argos-ci/storybook` vitest plugin to `twenty-ui` for automatic
screenshot capture during vitest storybook tests
- Uploads captured screenshots (PNG, ~5MB) as a CI artifact instead of
passing the full storybook build
- Updates the visual regression dispatch workflow to pass
`mode=argos-screenshots` to ci-privileged, which then uploads
screenshots to Argos via CLI
This replaces the 10-minute Storybook screenshot capture with a ~30s
vitest browser-mode approach. The heavy screenshot work happens on free
public runners, while ci-privileged only handles the Argos API upload
(keeping secrets private).
## Architecture
```
twenty (public, free runners) ci-privileged (private)
───────────────────────────── ────────────────────────
1. Build storybook-static 4. Download screenshots artifact
2. Vitest captures screenshots 5. `argos upload` → Argos API
3. Upload screenshots artifact 6. Poll for results
7. Post PR comment
```
## Test plan
- [x] Verified locally: vitest captures 225 screenshots in ~28s
- [x] Verified `@argos-ci/cli upload` successfully creates Argos build
from captured screenshots
- [x] Argos diffs computed and results visible via API
- [ ] CI runs end-to-end on a PR
|
||
|
|
ccffc4a1ea |
Fix axios related dependabot alerts generated against root yarn.lock (#21187)
Fixes the following Dependabot alerts: https://github.com/twentyhq/twenty/security/dependabot?q=is%3Aopen+package%3Aaxios+manifest%3Ayarn.lock+has%3Apatch Upgraded the referenced version in root yarn.lock. Creating a separate PR for the nested ones to keep the updates isolated (e.g. /seed-dependencies/yarn.lock). |
||
|
|
685c0ddd12 |
i18n - docs translations (#21195)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
15eaabdbc1 |
fix(ai) - optimize crud tools (#21133)
- **Add delete many**, `delete_many_{object}` added alongside the
existing `delete_one_{object}`.
- **Uniformize naming**, crud module, type names, and MCP helper
constants renamed for consistency.
- **Optimize tool schema (learn phase)**
- `find_many(_companies)`: **7 158 → 2 700 tokens**
- `find_one(_company)`: **280 → 126 tokens**
- ....
- Main mechanism: `reused: 'ref'` (line 7 of
`to-tool-json-schema.util.ts`). Zod walks the schema tree, tracks which
Zod schema instances appear more than once, and emits each reused
instance exactly once in `$defs`, replacing all subsequent occurrences
with a `$ref`. Works because filter and value schemas are now extracted
as shared objects.
- **Optimize system prompt (tool catalog)**, DATABASE_CRUD section
restructured to list operation patterns (`find_many_{object}`, …) once +
objects once, instead of the full N×M cross-product of tool names.
- **Optimize execute_tool**, shared record-properties schema (same
`$defs` deduplication applies at call time); introduced `upsert_many`;
added `selectedFields` to `find_*` so the agent only fetches the fields
it needs.
|
||
|
|
50c9b68e81 |
Update axios in package.json of seed-dependencies (#21190)
Fixes the following Dependabot alerts: https://github.com/twentyhq/twenty/security/dependabot?q=is%3Aopen+package%3Aaxios+manifest%3Apackages%2Ftwenty-server%2Fsrc%2Fengine%2Fcore-modules%2Fapplication%2Fapplication-package%2Fconstants%2Fseed-dependencies%2Fyarn.lock+has%3Apatch Follow up to the alerts not addressed in [this](https://github.com/twentyhq/twenty/pull/21187) PR. |
||
|
|
34d893f9fd |
i18n - translations (#21192)
Created by Github action Co-authored-by: github-actions <github-actions@twenty.com> |
||
|
|
d3a7ea0790 |
Fix: Not able to add multiple handles to Blocklist in settings/accounts (#21049)
Fixes: #21031 ### Root cause: This feature was never fully implemented even though the placeholder text suggested it was supported. It could only update one handle at a time. ### Fix Fixed the zod validation to validate each handle separately. Used `useCreateManyRecords` to update multiple handles at the same time. ### Before: <img width="2032" height="1162" alt="Screenshot 2026-05-29 at 3 25 12 PM" src="https://github.com/user-attachments/assets/ae6b6ae3-ed38-4410-801e-11f514773681" /> ### After: https://github.com/user-attachments/assets/69354129-422a-41de-baf7-fa5a28f01f3f --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Etienne <45695613+etiennejouan@users.noreply.github.com> |