Here's a concise PR description for your changes:
---
## Fix morph relation fields showing placeholder in kanban view
**Problem:** Morph relation fields always displayed placeholders in
kanban view even when records were selected, because
`useRecordFieldValue` was checking the base field name (e.g.,
`"favorite"`) instead of the computed morph field names (e.g.,
`"favoriteCompany"`).
**Solution:** Modified `useRecordFieldValue` to accept an optional
`fieldDefinition` parameter and added special handling for morph
relations that uses
`recordStoreMorphManyToOneValueWithObjectNameFamilySelector` and
`recordStoreMorphOneToManyValueWithObjectNameFamilySelector` to
correctly retrieve values. Updated `useIsFieldEmpty` to pass the field
definition through, enabling proper empty state detection for morph
relation fields.
**Impact:** Morph relation fields now correctly display their values in
kanban board cards instead of showing placeholders.
Fixes https://github.com/twentyhq/core-team-issues/issues/1323
<img width="681" height="420" alt="Screenshot 2025-10-22 at 14 11 07"
src="https://github.com/user-attachments/assets/de357379-ebff-42c6-bb93-1f0c43ce086d"
/>
Legacy workspaces still hold the old stored expression, which omits
public.unaccent_immutable, so their tsvectors remain accented and can’t
match the new, unaccented queries. Metadata sync doesn’t touch
asExpression, so only a targeted drop/recreate fixes the underlying
column.
In simpler words, the search vector should contain `mader` instead of
`mäder` for the search to work properly. Therefore, this command
regenerates the search vector across every object that uses
`SEARCH_FIELDS_FOR_*`.
Note that dashboard has a searchVector, but breaks the pattern of using
`SEARCH_FIELDS_FOR_DASHBOARD`. If you look at
packages/twenty-server/src/modules/dashboard/standard-objects/dashboard.workspace-entity.ts:116,
the searchVector field is hard-coded as
```
asExpression: `to_tsvector('english', title)`
```
Therefore, the following code snippet.
```
const storedExpression = hasAsExpressionSetting(
searchVectorFieldMetadata.settings,
)
? searchVectorFieldMetadata.settings.asExpression
: undefined;
if (storedExpression) {
return storedExpression;
}
return undefined;
```
It checks whether the searchVector field already carries its own
asExpression value in metadata. If the settings object includes that
string, it returns it so the upgrade can reuse the existing expression
for objects that aren’t in our predefined lists. If not, it returns
undefined, signaling there’s no stored expression to fall back on.
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
Addresses https://github.com/twentyhq/twenty/issues/15274
There's no need to parse the URL, since psql is happy to use it
directly. If you are going to parse the URL, you should parse it
correctly - the logic removed here make a number of assumptions about
the URL that are inaccurate and reject many types of valid URIs.
This does drop the ability to create the database which may be handy for
people that don't do database administration. For people that do, this
is an anti-feature.
This PR implements Sentry's AI agent monitoring by:
- Configuring vercelAIIntegration with recordInputs and recordOutputs
options
- Adding sendDefaultPii to Sentry.init() for better debugging
- Creating a shared AI_TELEMETRY_CONFIG constant to DRY up the telemetry
configuration
- Adding experimental_telemetry to all AI SDK calls (generateText,
generateObject, streamText)
All AI operations are now fully monitored in Sentry with complete
input/output recording for debugging and performance analysis.
Note: Currently on Sentry v9.26.0, which is compatible with this
implementation. No breaking changes from the v9-to-v10 migration guide
were found in the codebase.
Adds the field on the Show page and side panel for Morph relation
fields.
Updates
`packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/hooks/useOpenMorphRelationOneToManyFieldInput.tsx`
to use the correct `recordPickerInstanceId` when opening the picker so
the helper consistently renders (fixes [core-team-issues
#1324](https://github.com/twentyhq/core-team-issues/issues/1324)).
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Instead of declaring packages at the workplace-level package.json,
moving them into their relevant package-level package.json file.
`twenty-front`, `twenty-server` and `twenty-emails` continue to build
and work fine because of hoisting, but the dependencies now follow the
internal strategy of declaring at the package-level, plus give us a
single source of truth to updating package versions.
`twenty-front` and `twenty-emails` only use `@react-email/components`
while `twenty-server` only depends on `@react-email/render`.
# Introduction
Fixing composite field update by computing field column type for each of
its properties instead of globally
## Coverage
Added integration tests for each composite field on both successful
`create` and `update`
```ts
Test Suites: 17 passed, 17 total
Tests: 104 passed, 104 total
Snapshots: 14 passed, 14 total
Time: 135.431 s, estimated 143 s
```
## Conlusion
Related to https://github.com/twentyhq/core-team-issues/issues/1753
## Context
When updating both enum options and defaultValue, the old default might
not be in the new options (or vice versa), causing PostgreSQL constraint
violations regardless of update order.
## Solution
Sort updates to process defaultValue last; before updating options,
temporarily set the new defaultValue in metadata so alterEnumValues
creates the column with the correct default, then skip the redundant
defaultValue update handler.
# Introduction
Adding a view field to a view in v2 would be optimistically rendered by
the front but on refresh would not get persisted.
That's because we cache both:
```ts
useCachedMetadata({
cacheGetter: cacheStorageService.get.bind(cacheStorageService),
cacheSetter: cacheStorageService.set.bind(cacheStorageService),
operationsToCache: ['ObjectMetadataItems', 'FindAllCoreViews'],
}),
```
With keys that look like:
```ts
return `graphql:operations:${operationName}:${workspace.id}:${workspaceMetadataVersion}:${locale}:${queryHash}`;
```
It was functional in v1 as we would be incrementing metadata version
often.
In v2 it gets incremented only if implies an interaction to metadata
object or fields ( will be deprecated in the future though, until we
finish the // run )
The fix was to check if an `view` or related has been processed in the
workspace migration or if we incremented the metadata in order to
manually flush the `findAllCoreViews` redis cache.
Fixes [Dependabot Alert
216](https://github.com/twentyhq/twenty/security/dependabot/216) -
authorization bypass in next.js middleware.
Updated `react-email` version from `4.0.3` to `4.0.4`. This bumps up
Next.js to a safer version for the mentioned critical alert. However,
even the latest `react-email` package has not upgraded to Next.js 15.4.7
- the recommended version by dependabot.
Since `react-email` is a devDependency used to preview email templates
during development, it never gets inserted into the production build.
Therefore, I marking the following alerts as `vulnerable code is never
used` with a comment that it never makes it to the production build.
<p align="center">
<img width="1142" height="342" alt="image"
src="https://github.com/user-attachments/assets/50976fd3-b49c-4ee7-ac26-89f505783d55"
/>
</p>
The only other place where we have next imported is twenty-website,
which uses the safe version `14.2.33`.
<p align="center">
<img width="421" height="92" alt="image"
src="https://github.com/user-attachments/assets/fe1e20dc-7483-44f7-bf26-78f7131ccf46"
/>
</p>
# Introduction
Refactoring the standard overrides dispatcher to only pass over fields
to has to be dispatched in the standardOverrides entry and let the other
side effects resulting from out of standard overrides mutation trigger
Related to https://github.com/twentyhq/core-team-issues/issues/1753
## This allows
- standard field settings, options etc updates and so on
## Remark
- Determine what we should do on object deactivation ( right now in
production we can still access deactivated object relation properties
and so on e.g deactivate opportunities still accessible from a view
field on company ( still have to re-create it as it has been deleted )
=> decided to leave as it is right now, `isActive` could be considered
as uiDeactivated in the end
- We should also add forbidden standard field mutations validation
inside the builder itself ( here we want to early return in the api
input transpiler too as we don't want to spread invalid side effects )
=> or in the end we could just centralize both but it will generate
several errors
## Coverage
```ts
PASS test/integration/metadata/suites/object-metadata/successful-update-one-standard-object-metadata.integration-spec.ts
PASS test/integration/metadata/suites/field-metadata/successful-update-one-standard-field-metadata.integration-spec.ts
PASS test/integration/metadata/suites/object-metadata/failing-update-one-standard-object-metadata.integration-spec.ts
PASS test/integration/metadata/suites/field-metadata/failing-update-one-standard-field-metadata.integration-spec.ts
Test Suites: 4 passed, 4 total
Tests: 18 passed, 18 total
Snapshots: 16 passed, 16 total
Time: 8.721 s, estimated 10 s
```
## Update post review
Faced a behavior where updating back the company label to its original
value would result in storing this value in the standard overrides
Refactored both field and object transpilation behavior to rather remove
the standard override value instead and let fallback on original value
Yes it's quite duplicated will factorize once we move this inside the
builder
- Update user guide links for email integration, notes, tasks, and
API/webhooks sections to reflect new route structure
Currently, navigating using Algolia's search can result in 404s due to
broken links:
<img width="1105" height="601" alt="Screenshot 2025-10-22 at 10 36
55 AM"
src="https://github.com/user-attachments/assets/54ba762c-f616-4029-a100-0eca3f8cbd9e"
/>
Co-authored-by: StephanieJoly4 <stephanie@twenty.com>
Done ⬇️
Gql : move delete and destroy logic to common
Rest :
- rename 'delete' handler to 'destroy'
- create soft delete handlers (named 'delete') : one and many
- create destroy many handler
- update doc
--> Rest api gains NEW soft delete one/many + destroy many capabilities
closes : https://github.com/twentyhq/core-team-issues/issues/1579
Adds intelligent routing system that automatically selects the best
agent for user queries based on conversation context.
### Changes:
- Added `routerModel` column to workspace table for configurable router
LLM selection
- Implemented `RouterService` with conversation history analysis and
agent matching logic
- Created router settings UI in AI Settings page with model dropdown
- Removed agent-specific thread associations - threads are now
agent-agnostic
- Added real-time routing status notification in chat UI with shimmer
effect
- Removed automatic default assistant agent creation
- Renamed GraphQL operations from agent-specific to generic (e.g.,
`agentChatThreads` → `chatThreads`)
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
- Use aggregate operations in the widget configuration instead of
extended aggregate operations
- Use aggregate operation from generated graphql in the frontend
## Context
The _expected response body_ does not use monaco-editor, so enabling
`formatOnPaste `as mentioned in this
[comment](https://github.com/twentyhq/twenty/issues/13506#issuecomment-3188746787)
didn't fix the issue below. However, the `TextVariableEditor` uses
tiptap editor which has a `handlePaste` option that we can use to format
JSON.
- Issue https://github.com/twentyhq/twenty/issues/13506
## Implementation:
1. Insert the clipboard text at the current selection.
2. Retrieve the full editor content, parse it as JSON and stringify it
with indentation.
3. Re-use the method that transforms the text into `JSONContent`.
4. Replace the root node with the newly formatted `JSONContent`.
5. Update the cursor position based on the type of pasted text.
6. Apply the transaction with `view.dispatch()`
Note: If parsing fails (invalid JSON), the input will fall back to a
normal paste.
## test
Loom:
https://www.loom.com/share/f2e84d078662481f9f9f71fc98b772a1?sid=a649c4e9-8c55-4cbe-b031-7aba60af0e05
## What I've Implemented
I've added tooltips that show the original action type when you hover
over workflow step icons in the side panel. Now even if you rename an
action to something custom, you can still see what type of action it
actually is by hovering over the icon.
## The Problem This Solves
Before this change, once you renamed a workflow action (like changing
"Create Record" to "Add New Customer"), there was no way to tell what
the original action type was. This made it really confusing when
collaborating with others or when coming back to your own workflows
after some time - you couldn't tell if an action was a "Create Record"
or "Update Record" or something else.
## What Changed
Updated action type labels: Instead of showing just "Action" for all
record operations, the system now shows specific types like "Create
Record", "Update Record", "Delete Record", etc.
Added hover tooltips: When you hover over the action icons in the
workflow side panel, a tooltip appears showing the original action type,
even if you've renamed the step title.
## Before vs After
Before: All actions showed "Action" in the side panel, making it
impossible to distinguish between different types after renaming.
After: Each action shows its specific type in tooltips, so you always
know what you're working with.
This should make workflow management much clearer, especially when
multiple people are collaborating on the same workflow!
Resolves#14878
## Demo Video
See it in action:
https://www.loom.com/share/c0e0ec24e4524d0685b841e9ceb011d0?t=65&sid=dc05e58a-8869-4969-aa67-9772242fe697
---------
Co-authored-by: Thomas Trompette <thomas.trompette@sfr.fr>
Fixes [Dependabot Alert
203](https://github.com/twentyhq/twenty/security/dependabot/203) -
prototype pollution vulnerability in parse-git-config.
parse-git-config was a dependency for danger@11.3.1, but danger@13.0.4
does not depend on it.