Commit Graph
11511 Commits
Author SHA1 Message Date
Paul Rastoinandprastoin e13c9ef46c [Upgrade] Fix workspace creation cursor (#19701)
The upgrade migration system required new workspaces to always start
from a workspace command, which was too rigid. When the system was
mid-upgrade within an instance command (IC) segment, workspace creation
would fail or produce inconsistent state.

Instance commands now write upgrade migration rows for **all
active/suspended workspaces** alongside the global row. This means every
workspace has a complete migration history, including instance command
records.

- `InstanceCommandRunnerService` reloads `activeOrSuspendedWorkspaceIds`
immediately before writing records (both success and failure paths) to
mitigate race conditions with concurrent workspace creation.
- `recordUpgradeMigration` in `UpgradeMigrationService` accepts a
discriminated union over `status`, handles `error: unknown` formatting
internally, and writes global + workspace rows in batch.

`getInitialCursorForNewWorkspace` now accepts the last **attempted**
(not just completed) instance command with its status:

- If the IC is `completed` and the next step is a workspace segment →
cursor is set to the last WC of that segment (existing behavior).
- If the IC is `failed` or not the last of its segment → cursor is set
to that IC itself, preserving its status.

This allows workspaces to be created at any point during the upgrade
lifecycle, including mid-IC-segment and after IC failure.

`validateWorkspaceCursorsAreInWorkspaceSegment` accepts workspaces whose
cursor is:
1. Within the current workspace segment, OR
2. At the immediately preceding instance command with `completed` status
(handles the `-w` single-workspace upgrade scenario).

Workspaces with cursors in a previous segment, ahead of the current
segment, or at a preceding IC with `failed` status are rejected.

created empty workspaces to allow testing upgrade with several active
workspaces
2026-04-15 17:51:35 +02:00
prastoin 438d502988 fid(server): workspace activation set workspace.version v1.22.1 2026-04-14 16:46:56 +02:00
edc47bd458 i18n - docs translations (#19677)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
v1.22.0
2026-04-14 12:45:12 +02:00
WeikoandGitHub 47bdcb11d8 Move is active to fe (#19649)
## Context
Moving isActive filtering to the frontend for page layout tabs and
widgets, hiding inactive entities from the UI while keeping them in
state for future reactivation

Next we will implement deactivated standard tab re-activation during tab
creation (cc @Devessier)
<img width="234" height="303" alt="📋 Menu (Slots)"
src="https://github.com/user-attachments/assets/17a25ac6-55e2-4778-b7f0-e7554ed69704"
/>
2026-04-14 10:18:09 +00:00
Baptiste DevessierandGitHub b817bdca02 Rpl various fixes (#19668) 2026-04-14 09:46:15 +00:00
EtienneandGitHub 9c07ecd363 Fix view filter/sort deletion (#19567)
fixes https://github.com/twentyhq/twenty/issues/19543

+ bonus bug : when deleting an advanced filter, it triggers a destroy
which cascade-deletes associated view filters. Then, view filters
deletion throws.
2026-04-14 09:43:52 +00:00
Raphaël BosiandGitHub eb13378760 Fix Quick Lead command menu item not appearing (#19635)
- Refactored prefillWorkflowCommandMenuItems and
prefillFrontComponentCommandMenuItems to use
validateBuildAndRunWorkspaceMigration instead of raw TypeORM
createQueryBuilder inserts
- This ensures the flat entity cache is properly updated when seeding
command menu items, fixing the Quick Lead item not appearing after
workspace creation
- Moved command menu item prefill calls outside the transaction since
they now go through the migration pipeline
2026-04-14 09:30:31 +00:00
Paul RastoinandGitHub 3e699c4458 Fix upgrade commands discovery outside of cli (#19671)
# Introduction
We were allowing the sequence to be empty in the worker context that was
facing an edge case importing the UpgradeModule through the
WorkspaceModule god module, no commands were discovered and it was
throwing as the sequence must have at least one workspace commands to
allow a workspace creation

Though the issue was also applicable to the twenty-server `AppModule`
too that was not discovering any commands

## Integration tests were passing
The integration test were importing the `CommandModule` at the nest
testing app creating leading to asymmetric testing context
It was a requirement for a legacy commands import and global assignation

## Fix
The `UpgradeModule` now import both `WorkspaceCommandsProviderModule`
and `InstanceCommandProviderModule` which ships the commands directly in
the module
We could consider moving the commands into the `engine/upgrade` folder

## Concern
Bootstrap could become more and more long to load at both server and
worker start
When this becomes a problem we will have to only import the latest
workspace command or whatever
For the moment this is not worth it the risk to import not the latest
workspace command
2026-04-14 09:20:33 +00:00
EtienneandGitHub f738961127 Add gql operationName metadata in sentry (#19564) 2026-04-14 08:55:54 +00:00
49aac04b84 fix: edit button not coming up on avatar right after image upload (#19596)
## Summary

After uploading an image/file to the empty avatar field in the person
tab, the edit icon next to the field would not appear until the browser
was refreshed or another field was clicked.

### Root cause

- When user clicks over the avatar field,
`recordFieldListCellEditModePosition` is set to `globalIndex`
- That is fine when a avatar already exists. But when there is no avatar
already set, the native file picker is opened with no `onClose` handler
attached.
- So after the file upload is completed,
`recordFieldListCellEditModePosition` is never reset to null.
- `FieldsWidgetCellEditModePortal` stays anchored to the avatar file
element
- When the user hovers over the same field again, its hover portal tries
to compete to anchor for the same element
- So, `RecordInlineCellDisplayMode ` (the edit button) doesn't render

### Fix

- Pass the `onClose` function through `openFieldInput` to
`openFilesFieldInput`
- `onClose` resets `recordFieldListCellEditModePosition` back to null,
when the upload completes.

## Before


https://github.com/user-attachments/assets/ac9318e9-5471-434c-8af3-5c20d0112460

## After


https://github.com/user-attachments/assets/0d064a7f-95ad-4b92-a9ee-d9570f360972

Fixes #19595

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-14 08:54:14 +00:00
40c6c63bf5 i18n - docs translations (#19672)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-14 10:54:27 +02:00
d583984bf0 fix(api-key): batch role resolution with DataLoader to fix N+1 (#19590)
## Summary

The `role` @ResolveField on `ApiKeyResolver` calls `getRolesByApiKeys`
with a single-element array per API key. When a query returns N API
keys, this produces N separate DB queries to resolve their roles.

This adds an `apiKeyRoleLoader` to the existing DataLoader
infrastructure. All API key IDs in a single GraphQL request are
collected and resolved in one batched query.

- Before: N queries (one per API key)
- After: 1 query (batched via DataLoader)

## Changes

- `dataloader.service.ts` - new `createApiKeyRoleLoader` method,
delegates to `ApiKeyRoleService.getRolesByApiKeys`
- `dataloader.interface.ts` - `apiKeyRoleLoader` added to `IDataloaders`
- `dataloader.module.ts` - import `ApiKeyModule` so `ApiKeyRoleService`
is available
- `api-key.resolver.ts` - `role()` now uses
`context.loaders.apiKeyRoleLoader.load()` instead of calling the service
directly

## Test plan

- [ ] Verify `apiKeys { id role { label } }` query returns the same
results as before
- [ ] Confirm only 1 role_target query fires regardless of how many API
keys are returned

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-14 08:43:31 +00:00
Paul RastoinandGitHub 714f149b0c Move backfill page layout to 1.23 (#19670) 2026-04-14 08:39:24 +00:00
martmullandGitHub 194f0963dc Remove 'twenty-app' keyword by default (#19669)
as title
2026-04-14 08:26:45 +00:00
5fa3094800 test: fix failing useColorScheme test and remove FIXME (#19593)
Summary
This PR fixes a bug in the `useColorScheme` test suite and removes a
lingering `FIXME` comment where the color scheme was unexpectedly
unsetting during state updates.

Root Cause
Previously, the Jotai state was being initialized *inside* the
`renderHook` callback using `useSetAtomState`. When the `setColorScheme`
function was called, it triggered a hook re-render, which caused the
callback to execute again and overwrite the new state with the hardcoded
`'System'` initial state.

The Fix
- Removed the state initialization from inside the render cycle.
- Bootstrapped the state on a fresh store using `resetJotaiStore()` and
`store.set()` *before* rendering the hook.
- Updated the mock `workspaceMember` to correctly use the
`CurrentWorkspaceMember` type.
- Removed the `FIXME` comment and successfully asserted that the color
scheme updates to `'Dark'`.

Testing
Ran tests locally to confirm the fix works as expected:
`corepack yarn jest --config packages/twenty-front/jest.config.mjs
--testPathPattern=useColorScheme.test.tsx`

---------

Co-authored-by: Srabani Ghorai <subhojit04ghorai@gmail.com>
2026-04-14 06:40:40 +00:00
87f8e5ca19 few website updates (#19663)
## Summary
- refresh pricing page content, plan cards, CTA styling, and Salesforce
comparison visuals
- update partner and hero/testimonial visuals, including pulled
carousel-compatible partner testimonial data
- improve halftone export and illustration mounting flows, plus related
button and hydration fixes
- add updated website illustration and pricing assets

## Testing
- Not run (not requested)

---------

Co-authored-by: Abdullah <125115953+mabdullahabaid@users.noreply.github.com>
2026-04-14 06:23:20 +00:00
e041125426 fix: return 404 for deleted workspace webhook race (#19439)
Handle late TwentyORM workspace-not-found exceptions in the workflow
webhook REST exception filter so deleted workspaces return a 404 instead
of surfacing as internal errors.

Also add a focused regression spec covering the deleted-workspace ORM
codes and the existing workflow-trigger status mappings.

Closes #15544

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-13 22:38:36 +00:00
d88fb2bd65 Clean event creation exception (#19561)
https://twenty-v7.sentry.io/issues/7351816489/?environment=prod&project=4507072499810304&query=is%3Aunresolved&referrer=issue-stream

Those are expected error that should not reach sentry. These happen when
stream TTL expires or user session ends

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-13 22:11:57 +00:00
Abdullah.andGitHub cdc7339da1 Fix testimonials background, faq clickability and some case-studies page edits. (#19657)
As title. Also copied release-notes related files from `twenty-website`
to `twenty-website-new`.
2026-04-13 21:19:41 +00:00
69d228d8a1 Deprecate IS_RECORD_TABLE_WIDGET_ENABLED feature flag (#19662)
## Summary
- Removes the `IS_RECORD_TABLE_WIDGET_ENABLED` feature flag, making the
record table widget unconditionally available in dashboard widget type
selection
- The flag was already seeded as `true` for all new workspaces and only
gated UI visibility in one component
(`SidePanelPageLayoutDashboardWidgetTypeSelect`)
- Cleans up the flag from `FeatureFlagKey` enum, dev seeder, and test
mocks

## Analysis
The flag only controlled whether the "View" (Record Table) widget option
appeared in the dashboard widget type selector. The entire record table
widget infrastructure (rendering, creation hooks, GraphQL types,
`RECORD_TABLE` enum in `WidgetType`) is independent of the flag and
fully implemented. No backend logic depends on this flag.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-13 21:13:15 +00:00
455022f652 Add ClickHouse-backed metered credit cap enforcement (#19586)
## Summary
Implements a ClickHouse-backed polling system to enforce metered-credit
caps for workflow executions, replacing reliance on Stripe billing
alerts. The system re-evaluates tier caps against live pricing on every
poll cycle, allowing price/tier changes to propagate immediately without
recreating Stripe alert objects.

## Key Changes

- **BillingUsageCapService**: New service that queries ClickHouse for
current-period credit usage and evaluates whether a subscription has
reached its metered-credit allowance (tier cap + credit balance)
  - `isClickHouseEnabled()`: Checks if ClickHouse is configured
- `getCurrentPeriodCreditsUsed()`: Sums creditsUsedMicro from usageEvent
table for a workspace within a billing period
- `evaluateCap()`: Determines if usage has reached the allowance by
reading live pricing from the subscription

- **EnforceUsageCapJob**: Cron job that polls all active subscriptions
and updates `hasReachedCurrentPeriodCap` on metered items
  - Runs every 2 minutes to keep cap enforcement in sync with live usage
- Supports shadow mode (log-only) via
`BILLING_USAGE_CAP_CLICKHOUSE_ENABLED` flag for safe rollout
- Continues processing after per-subscription errors with detailed
logging

- **EnforceUsageCapCronCommand**: CLI command to register the
enforcement cron job

- **MeteredCreditService**: Extracted
`extractMeteredPricingInfoFromSubscription()` as a pure function for
callers that already hold the subscription with pricing loaded, avoiding
redundant DB queries

- **Configuration**: Added `BILLING_USAGE_CAP_CLICKHOUSE_ENABLED` flag
to control enforcement mode (active vs. shadow)

- **Constants**: Added `METERED_OPERATION_TYPES` to define which
operation types count toward the metered product's credit cap

## Implementation Details

- The service queries ClickHouse for the sum of `creditsUsedMicro` in
the current billing period, matching Stripe meter semantics
- Pricing is re-read on every evaluation, so tier changes propagate
within one poll cycle without Stripe alert recreation
- The cron job only updates the database when the cap state actually
changes (no-op if already in the correct state)
- Shadow mode allows safe validation before enabling enforcement;
transitions are logged but not persisted
- Comprehensive test coverage for both the service and cron job,
including error handling and state transitions

https://claude.ai/code/session_01VksTSrYLXJVCPVBQhQdBTe

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-13 21:17:41 +02:00
Charles BochetandGitHub fa354b4c1c Remove orphaned workspaceId column from BillingSubscriptionItemEntity (#19660)
## Summary
- Removes the `workspaceId` column, `@Index()`, and `@ManyToOne`
workspace relation from `BillingSubscriptionItemEntity`
- The entity defined these fields but they don't exist in the actual
database table, causing `column X.workspaceId does not exist` errors at
runtime
- The workspace relationship is already accessible through the parent
`BillingSubscriptionEntity`
2026-04-13 17:53:33 +00:00
martmullandGitHub 0894f2004b Remove app record if first install fails (#19659)
If application install fails, and if app was created, uninstall app

fixes
https://discord.com/channels/1130383047699738754/1491822937462804590
2026-04-13 17:39:59 +00:00
665db83bb5 i18n - translations (#19661)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 19:45:10 +02:00
martmullGitHubcubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
64a7725ac7 Add banner for not vetted apps (#19655)
https://github.com/user-attachments/assets/4038e21a-d5d9-4b93-8589-7a4baf35ef5b

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-13 17:28:50 +00:00
76d3e4ad2e i18n - translations (#19656)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 18:30:08 +02:00
Raphaël BosiandGitHub fb772c7695 Sync command menu with main context store (#19650)
## PR description

- The command menu in the side panel now reads directly from
`MAIN_CONTEXT_STORE_INSTANCE_ID` instead of snapshotting the main
context store into a separate side-panel instance when opening. This
keeps the command menu always in sync with the current page state
(selection, filters, view, etc.).
- Removed the broadening/reset-to-selection feature (Backspace to clear
context, "Reset to" button) since the command menu no longer maintains
its own copy of the context.

## Video QA


https://github.com/user-attachments/assets/5d5bc664-b6d4-431d-a271-6ce23d8a4ae0
2026-04-13 16:08:15 +00:00
Paul RastoinandGitHub 123d6241d7 Fix AddPermissionFlagRoleIdIndexFastInstanceCommand (#19654)
# Introduction
Index seemed to be missing in production only, as it's blocking the
whole migration release on other env that already implements the index
2026-04-13 18:14:31 +02:00
neo773andGitHub d2a99ef72d Fix VariablePicker and Fullscreen Icon overlap in FormAdvancedTextFieldInput (#19614)
fixes 

<img width="659" height="386" alt="image"
src="https://github.com/user-attachments/assets/c9755574-6830-464d-8abf-7741188f84dd"
/>
2026-04-13 16:01:50 +00:00
Abdul RahmanandGitHub 96959b43ba Fix: Filter out deactivated objects from navigation sidebar (#19620) 2026-04-13 15:54:30 +00:00
Abdul RahmanandGitHub 3f495124a5 Fix navbar folder not opening on page refresh when it has an active child item (#19619)
### Before


https://github.com/user-attachments/assets/b76e6184-0299-4240-a1f7-8651b69885ec

### After


https://github.com/user-attachments/assets/e7e9061b-98a1-4781-b882-eef87b83597a
2026-04-13 15:53:28 +00:00
353d1e89d5 Fix merge with null value + reset data virtualization before init load (#19633)
**Merge records fix:**

selectPriorityFieldValue throws when merging records if the priority
record has no value for a field (e.g., null/empty) but 2+ other records
do. The recordsWithValues array is pre-filtered to only records with
non-empty values, so the priority record isn't in the list. The fix:
instead of throwing, fall back to null since this is the priority record
actual value


**Duplicated IDs fix**


https://github.com/user-attachments/assets/bd6d7d08-d079-49a5-aad4-740b59a3c246


When applying a filter that reduces the record count, the virtualized
table's record ID array keeps stale entries from the previous larger
result set. loadRecordsToVirtualRows clones the old array (e.g., 60
entries) and only overwrites the first N positions (e.g., 9) with the
new filtered results, leaving positions 9-59 with old IDs. If any old ID
matches a new one, it appears twice in the selection, causing "-> 2
selected" for a single click and a duplicate ID in the merge mutation
payload. The fix: clear the record IDs array in
useTriggerInitialRecordTableDataLoad before repopulating it with fresh
data.

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
2026-04-13 15:50:58 +00:00
Paul RastoinandGitHub 87f5c0083f Prevent cross version upgrade mismatch in 1.22 (#19627)
## Introduction
As the new upgrade sequence engine is released in `1.22` it requires all
workspaces to be in `1.21.0` which mean they will have a cursor on the
sequence

As if if someone upgrades from `1.20` to `1.22` no `upgradeMigration`
will exist and throw a pretty basic `Could not find any cursor, database
might not been initialized correctly`

Here we allow a meaningful error
2026-04-13 14:53:12 +00:00
neo773andGitHub 7dfc556250 refactor messaging jobs (#19626)
Cleans up the code quality by migrating from Raw SQL to TypeORM
entities. The previous implementation was necessary to do cross‑schema
table joins but since we've migrated to the core schema we don't need it
anymore.

- Also extracted `toIsoStringOrNull` to a utility it was duplicated
several times
- Moved `isThrottled` logic from job handler to cron enqueuer
2026-04-13 14:39:52 +00:00
9f6855e7dd i18n - translations (#19652)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 16:54:50 +02:00
33c74c4d28 i18n - docs translations (#19651)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 16:48:44 +02:00
Paul RastoinandGitHub ce2723d6cf Move view field label identifier deletion validation into the cross entity validation (#19642)
## Introduction
In the same validate build and run we should be able to delete a view
field targetting a label identifier and at the same create one that
repoints to it again without failing any validation

Leading for this valdiation rule to be moved in the cross entity
validation steps
2026-04-13 14:38:27 +00:00
Thomas des FrancsandGitHub 12233e6c47 few fixes (#19648)
## Summary
- refresh the partner hero visual and testimonial presentation,
including the partner-specific carousel and illustration assets
- switch the testimonials top notch to the masked rendering approach
used elsewhere for more precise shape control
- extend halftone studio/export support and related geometry/state
handling used by the updated partner visuals
- include supporting website UI adjustments across navigation, pricing,
plans, and Salesforce-related sections

## Testing
- Not run (not requested)
2026-04-13 14:36:03 +00:00
Abdullah.andGitHub 84b325876d More website updates. (#19624)
This PR introduces more updates to the website, such as real
testimonials, case studies, copy of pricing plans table. It also adds
modals for "Talk to Us" and "Become a Partner".
2026-04-13 14:02:21 +00:00
neo773andGitHub 88c0b24d9e Add per-workspace error handling to CronTriggerCronJob (#19640)
fix sonarly 19618
2026-04-13 13:59:54 +00:00
Thomas des FrancsandGitHub 87bb2f94bb Fixes on website (#19625)
## Summary
- fix the halftone studio image-switch behavior so image mode uses a
sane default preview distance instead of rendering nearly off-screen
- add shared preview-distance handling for shape and image modes, and
tune the default 3D idle auto-rotate speed
- update halftone controls/export plumbing to support the latest studio
settings changes
- refresh website UI/content in pricing, Salesforce, menu, and
billing-related sections

## Testing
- Ran targeted Jest tests for halftone state and footprint logic
- Ran TypeScript check for `packages/twenty-website-new`
- Broader app-level/manual testing not run
2026-04-13 13:55:38 +00:00
c67602f2e8 i18n - translations (#19647)
Created by Github action

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 16:00:27 +02:00
e34ca3817c i18n - translations (#19646)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 15:53:02 +02:00
martmullandGitHub 227d24512e Fix permission flag deletion validator (#19636)
As title
2026-04-13 13:41:28 +00:00
Raphaël BosiandGitHub 1382790c80 Fix side panel close button title (#19638)
## Before
<img width="830" height="1486" alt="CleanShot 2026-04-13 at 15 07 19@2x"
src="https://github.com/user-attachments/assets/757a52bb-f06e-4f04-950a-087cbdec0653"
/>


## After
<img width="838" height="1478" alt="CleanShot 2026-04-13 at 15 06 56@2x"
src="https://github.com/user-attachments/assets/ed9d99ab-fbda-4548-b09a-e7825d86b5dd"
/>
2026-04-13 13:39:51 +00:00
Paul RastoinandGitHub 5e7e5dd466 Colliding subject field fix on messageThread command (#19637) 2026-04-13 13:33:46 +00:00
martmullandGitHub 6182918a66 Document isAuthRequired: true instead of false (#19641) 2026-04-13 13:32:23 +00:00
Baptiste DevessierandGitHub 6829fc315a Implement full tab widget frontend (#19568)
https://github.com/user-attachments/assets/488e0145-ff49-4205-8fd3-0eb4f614c054
2026-04-13 13:24:20 +00:00
8425afd930 i18n - translations (#19645)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 15:37:00 +02:00
64e031b9dd i18n - translations (#19643)
Created by Github action

---------

Co-authored-by: github-actions <github-actions@twenty.com>
2026-04-13 15:30:32 +02:00