## Release 1.12.0
This release includes:
- Revamped Side Panel - Now opens next to content instead of above it
- Granular Email Folder Sync - Choose which Gmail labels or Outlook
folders to sync
Changelog file:
`packages/twenty-website/src/content/releases/1.12.0.mdx`
Release date: 2025-12-02
This PR improves the general UX and DX of boards, by modifying the query
effect to only use paged group by queries.
In this PR we implement two more things in the backend for group by
queries :
- Fixed ORDER BY in the PARTITION BY sub-query (this wasn't working
because it was applied in the main query, so it sorted randomly picked
records, which was a correct sort on an incorrect dataset returned by
the sub-query)
- Added offset paging in PARTITION BY
Miscellaneous, various bug fixes and improvements along the way :
- Throttled loading of cards to avoid React freeze
- Handling of drag & drop
- Handling of create / delete / update
- Reworked skeleton (the library slows down a lot with hundreds of
skeleton for a spinning effect that is hardly noticed)
- Fixed refetch of aggregate queries (I included the new group by
aggregates query we use in the existing refetch mechanism)
- Re-trigger queries on filters and sorts changes
- Unselect all record ids when deleting / restoring / detroying
- Fetch only groups that still have records to lighten the group by
query.
# What remains to be done
This is still a naïve fetch more implementation that will work for a few
fetch more rounds, but if you scroll and load say 200 cards per column
on a board, React will re-render all 200 cards of each column each time.
We would probably need to virtualize the board with paged queries as we
did for the table, this could be done after this PR but seems less
urgent.
What's nice is that this new query pattern is well designed for
virtualization also, drawing from our experience with table
virtualization, and adapted to a multi-column request pattern, like a
2:2 matrix of records, for our boards.
So the remaining work would be to design a UI solution for virtualizing
this matrix of records, which could be quite different from our table
virtualization mechanism.
## Context
We've recently introduced a new workspace cache service which now acts
as a cache access and local storage for all workspace related data,
deprecating the individual specific services.
- Better performance through multiple caching/fetching strategies
- Consistent data access patterns across the codebase
- Reduced redis queries through MGET/MSET/PIPELINE with multiple cache
keys
Closes [1918](https://github.com/twentyhq/core-team-issues/issues/1918).
- For the first point in the issue, we just show the deactivated entries
along with the deactivated text.
---
- For the second point, we show a banner and control the
enabled/disabled state of save button depending on whether we're
allowing the user to create table with the typed name.
- For example, we do not want to allow the user to create a table with
reserved name, so we disable the save button without showing a banner.
- Similarly, we do not want the user to create a table with a name that
already exists in the database. In this case, we show a banner and we
also disable the save button.
- Finally, we do not want to allow the user to create a table where
singular and plural name are the same. Therefore, we disable the save
button for names like `works`.
---
- For the third point, if we add the delete button, it logically means
that we allow the user to delete a custom object/field even it has not
been deactivated yet, so did that.
- Upon deleting the object/field, if we wait for the metadata to refetch
before we navigate, this is what we see because the path does not exist
any longer after deletion and we're waiting for refetch on the path
until we navigate away.
https://github.com/user-attachments/assets/dbe0569c-db88-4285-851f-22551b1ca81e
- To avoid this page from appearing, I replaced awaiting refetch to not
awaiting refetch and redirecting while the refetch happens in the
background.
- Therefore, when we delete something, there is a slight delay for when
it is actually cleared out from the list, but the Not Found view does
not appear on the screen.
https://github.com/user-attachments/assets/47f49579-ce51-4d6a-b857-72046247bb4b
- I tried optimistically removing the object/field from the metadata,
but it leads to some issues (crashes the app) and I have not been able
to find a solution for it yet.
- Therefore, instead of getting stuck at perfection and blocking myself,
I stopped getting into the issue further and created this PR by ensuring
that the desired functionality works.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Display deactivated objects/fields by default, add delete actions with
confirmation, and unify metadata name computation (auto-suffix reserved
keywords) across front/back with conflict checks in object creation.
>
> - **Frontend (Settings/Data Model)**:
> - **Visibility/UX**: Show `Deactivated` labels for objects/fields;
filters default to include inactive (`showDeactivated`/`showInactive`
true); replace field action dropdown with chevron link.
> - **Delete flows**: Add delete buttons for custom objects/fields with
confirmation modals and background refetch to avoid Not Found flashes.
> - **Creation/Edit validation**: Add name conflict detection banner in
`SettingsDataModelObjectAboutForm` and disable Save on conflicts;
simplify `metadataLabelSchema` to use computed name; form fields
validate on change and sync API names.
> - **Shared (twenty-shared/metadata)**:
> - Add `computeMetadataNameFromLabel` util (slugify+camelCase) and
`RESERVED_METADATA_NAME_KEYWORDS`; auto-append `Custom` to reserved
names; export constants/utilities.
> - **Backend**:
> - Migrate to shared `computeMetadataNameFromLabel`; update validators
to use shared reserved keywords with new messages; allow deletion of
active custom fields/objects (keep standard guards); adjust
services/decorators accordingly.
> - **Tests/Stories**:
> - Update unit/integration snapshots for new reserved-name messages and
behaviors; add missing i18n/router decorators in stories.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
5b12615560. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
I was looking into [Dependabot Alert
107](https://github.com/twentyhq/twenty/security/dependabot/107) and
figured that the alert is caused by `vite-plugin-dts`, which is a
development dependency and does not make it into the production build
for it to be dangerous.
However, while at it, I also saw that some packages used plugins from
root package.json while others had them defined in their local
package.json. Therefore, I refactored to move plugins where they're
required and removed a redundant package.
Builds for the following succeed as intended:
- twenty-ui
- twenty-emails
- twenty-website
- twenty-front
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Changes
### 1. Fixed streaming lag with throttle parameter
**Problem:** The AI chat was experiencing lag during message streaming
because the messages array was being updated too frequently, causing all
messages to re-render too quickly.
**Solution:** Added the `experimental_throttle: 100` parameter to the
`useChat` hook configuration. This throttles message updates during
streaming to prevent excessive re-renders and improve performance.
### 2. Cleaned up useAgentChat hook return values
**Context:** The `useAgentChat` hook primarily returns values from the
underlying `useChat` hook, so there wasn't significant room for
improvement regarding the "umbrella hook" pattern. However, some
unnecessary values were being returned that weren't needed.
**Solution:**
- Removed `input` and `handleInputChange` from the `useAgentChat` hook
return. These weren't needed since input state is already managed
directly via Recoil state (`agentChatInputState`) in components.
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Throttle message streaming updates and switch AI chat input management
from context to Recoil; minor scroll behavior tweak.
>
> - **AI Chat performance**:
> - Add `experimental_throttle: 100` to `useChat` in `useAgentChat` to
reduce re-render frequency during streaming.
> - **State management**:
> - Migrate input handling to Recoil via `agentChatInputState`; remove
`input` and `handleInputChange` from `AgentChatContext` and
`useAgentChat` returns.
> - Update `AIChatTab` and `SendMessageButton` to read/write input from
Recoil and adjust hotkeys/disabled state accordingly.
> - **UX behavior**:
> - Remove smooth scroll behavior in `useAgentChatScrollToBottom`.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
911b341ea1. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
# Introduction
close https://github.com/twentyhq/core-team-issues/issues/1930
close https://github.com/twentyhq/core-team-issues/issues/1929
Migrating role and roleTarget entities to the v2 core engine, allowing
v2 caching leverage and allow migrating agent to v2 that needs role
target in prior
After agent we should be able to pass twenty standard app totally though
workspace migration
## Role target assignation
Please note that role target have 3 creation entrypoints:
- Agent
- User workspace
- ApiKey
Refactored all 3 of them to pass through a new role-target.service.ts
that consumes the v2 under the hood.
---------
Co-authored-by: Weiko <corentin@twenty.com>
## Summary
1. Changed the side panel header title font size from small (0.92rem) to
base (1rem)
2. Added baseline alignment between the title and subtitle text while
keeping the icon centered
## Changes
- Updated `StyledPageInfoTitleContainer` font size from
`theme.font.size.sm` to `theme.font.size.md`
- Added `StyledPageInfoTextContainer` wrapper to baseline-align title
and subtitle independently from the icon
<img width="448" height="191" alt="image"
src="https://github.com/user-attachments/assets/b022a89c-a68f-4449-b01a-2ec029ce995b"
/>