Fixes#15508
Addresses the issue where the "Export View" functionality was not
exporting all records from a view. Users reported that only a subset of
records were exported, even when the view contained more. This led to
incomplete data exports.
The core of the problem was found within the `useLazyFetchAllRecords`
hook. The `fetchMoreRecordsLazy` function, which is responsible for
fetching subsequent pages of data during the export process, was
inadvertently using a default page limit (`DEFAULT_SEARCH_REQUEST_LIMIT`
of 60 records) instead of the intended `pageSize` (200 records). This
discrepancy caused the export process to prematurely stop fetching
records.
The PR modifies
`packages/twenty-front/src/modules/object-record/hooks/useLazyFetchAllRecords.ts`
to explicitly pass the `limit` parameter (which correctly reflects the
`pageSize`) to the `fetchMoreRecordsLazy` function. This ensures that
all subsequent data fetches during an export operation adhere to the
configured page size, allowing for the complete retrieval of all
records.
Part of Fixing Issue #14976
### Pull Request Summary: SlashCommand Integration in Advanced Text
Editor
This pull request introduces **SlashCommand functionality** within the
Advanced Text Editor, specifically used in the **Workflow node** of
**Send Email body** components. The implementation leverages the
`@tiptap/suggestion` extension from the TipTap ecosystem, enabling
dynamic styling and command execution via a custom dropdown triggered by
typing `/`.
---
### Implementation Overview
#### 1. **Custom Extension & Dropdown Rendering**
- A new extension was created to handle SlashCommand interactions.
- This extension renders a **Dropdown component** that displays
available commands with relevant styles, icons etc.
#### 2. **Command Configuration**
- Each command includes:
- Visibility and active state logic
- Execution behavior upon selection
- All commands are initialized and configured centrally.
#### 3. **Search & Filtering**
- As users type after the `/`, the command list is **filtered based on
the query**.
- For example, typing `/car` filters and displays matching commands in
the dropdown.
#### 4. **Dropdown Lifecycle & Positioning**
- The dropdown is rendered using React lifecycle hooks provided by
`SuggestionTip`:
- `onStart`: Initializes state, sets selected command, and captures
cursor position via `DOMRect`.
- `onUpdate`, `onKeyDown`, `onExit`: Manage dropdown updates and
interactions.
- Positioning is handled via a **`useFloating` hook**, which aligns the
dropdown relative to the cursor and editor bounds.
- The dropdown is rendered in a **react-portal**, wrapped in the current
theme for consistent styling and animation.
#### 6. **State Management**
- A dedicated `SlashCommandState.ts` file manages:
- Callback functions
- Current command and selected item
- Cleanup utilities for event listeners
- Dropdown navigation (arrow keys, enter key)
#### 7. **Integration Points**
- SlashCommand functionality is now **enabled in Send Email body of the
Workflow**.
- Relevant changes have been applied to support this components in
Storybook as well.
[slash command
test.webm](https://github.com/user-attachments/assets/5c537844-8987-4ce5-9fca-b29ea93d8063)
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> Updates Portuguese (Brazil and Portugal) generated locale files,
including a new editor hint string for “Enter text or type '/' for
commands,” plus assorted translation tweaks.
>
> - **i18n/locales**:
> - **Portuguese (Brazil) `src/locales/generated/pt-BR.ts`**: Add new
editor hint message (`"Enter text or Type '/' for commands"`) and adjust
multiple translations/wording.
> - **Portuguese (Portugal) `src/locales/generated/pt-PT.ts`**: Add the
same editor hint message and refine numerous translations/labels.
> - No functional code changes; translation files regenerated/updated.
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b3d7407525ec08da1fcfafe1309bb4fd61654dac. 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@twenty.com>
**Root Cause**
Many-to-one relation filters were being exposed under the relation name
(e.g., `company`) instead of the corresponding foreign-key attribute
(e.g., `companyId`).
**Change**
- Detect many-to-one relation metadata and remap those filter keys to
`<fieldName>Id`.
- Removed some unused code unrelated to this fix.
## Overview
This PR strengthens our permission system by introducing more granular
role-based access control across the platform.
## Changes
### New Permissions Added
- **Applications** - Control who can install and manage applications
- **Layouts** - Control who can customize page layouts and UI structure
- **AI** - Control access to AI features and agents
- **Upload File** - Separate permission for file uploads
- **Download File** - Separate permission for file downloads (frontend
visibility)
### Security Enhancements
- Implemented whitelist-based validation for workspace field updates
- Added explicit permission guards to core entity resolvers
- Enhanced ESLint rule to enforce permission checks on all mutations
- Created `CustomPermissionGuard` and `NoPermissionGuard` for better
code documentation
### Affected Components
- Core entity resolvers: webhooks, files, domains, applications,
layouts, postgres credentials
- Workspace update mutations now use whitelist validation
- Settings UI updated with new permission controls
### Developer Experience
- ESLint now catches missing permission guards during development
- Explicit guard markers make permission requirements clear in code
review
- Comprehensive test coverage for new permission logic
## Testing
- ✅ All TypeScript type checks pass
- ✅ ESLint validation passes
- ✅ New permission guards properly enforced
- ✅ Frontend UI displays new permissions correctly
## Migration Notes
Existing workspaces will need to assign the new permissions to roles as
needed. By default, all new permissions are set to `false` for non-admin
roles.
**Before**
- any user with workpace_members permission was able to remove a user
from their workspace. This triggered the deletion of workspaceMember +
of userWorkspace, but did not delete the user (even if they had no
workspace left) nor the roleTarget (acts as junction between role and
userWorkspace) which was left with a userWorkspaceId pointing to
nothing. This is because roleTarget points to userWorkspaceId but the
foreign key constraint was not implemented
- any user could delete their own account. This triggered the deletion
of all their workspaceMembers, but not of their userWorkspace nor their
user nor the roleTarget --> we have orphaned userWorkspace, not
technically but product wise - a userWorkspace without a workspaceMember
does not make sense
So the problems are
- we have some roleTargets pointing to non-existing userWorkspaceId
(which caused https://github.com/twentyhq/twenty/issues/14608 )
- we have userWorkspaces that should not exist and that have no
workspaceMember counterpart
- it is not possible for a user to leave a workspace by themselves, they
can only leave all workspaces at once, except if they are being removed
from the workspace by another user
**Now**
- if a user has multiple workspaces, they are given the possibility to
leave one workspace while remaining in the others (we show two buttons:
Leave workspace and Delete account buttons). if a user has just one
workspace, they only see Delete account
- when a user leaves a workspace, we delete their workspaceMember,
userWorkspace and roleTarget. If they don't belong to any other
workspace we also soft-delete their user
- soft-deleted users get hard deleted after 30 days thanks to a cron
- we have two commands to clean the orphans roleTarget and userWorkspace
(TODO: query db to see how many must be run)
**Next**
- once the commands have been run, we can implement and introduce the
foreign key constraint on roleTarget
Fixes https://github.com/twentyhq/twenty/issues/14608
Fixes https://github.com/twentyhq/private-issues/issues/361
There's room for more improvement here -
triggerInitialRecordTableDataLoad does a lot of things, should not be
triggered so much. actually even
RecordTableVirtualizedInitialDataLoadEffect should not be triggered when
there's just a metadata field change (if we trust the name
initialDataLoad)
As title
- adds decorators in twenty-sdk
- update twenty-cli load-manifest to it gets @FieldMetadata infos +
testing
- update twenty-server so it CRUD fields properly, using
universalIdentifier
- Fix UI so we can update managed objects records
- move FieldMetadata items from twenty-server to twenty-shared
Here is what the PR does:
- Surface password state in validatePasswordResetToken, returning
hasPassword so the client can tell whether a user is setting or changing
their password.
- Consume that flag throughout the front end (mock data, stories,
GraphQL types) and update the Reset/Set Password modal to swap the
heading/button label and success toast accordingly.
- After a successful password set/reset, immediately update the
logged-in user’s hasPassword flag so the Settings screen reflects the
new state without a reload.
Modal has two states now - reset password modal uses change password
state since it made intuitive sense.
<p align="center">
<img width="404" height="397" alt="image"
src="https://github.com/user-attachments/assets/c54cc581-1248-4395-833d-0202758e1947"
/>
</p>
<p align="center">
<img width="403" height="393" alt="image"
src="https://github.com/user-attachments/assets/d8a39a95-27e6-4037-86f2-1f74176002ba"
/>
</p>
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
## Summary
Reverts commits afc518a, ae22e64, and 800b5b5 that refactored
`useAgentChat` to address umbrella hook pattern feedback.
## Issues Introduced by Refactoring
The refactoring broke several critical functionalities:
1. **Streaming fails on thread switch** - Messages don't stream properly
when switching between threads
2. **Messages lost on tab close** - When the Ask AI tab is closed, the
request is lost instead of continuing in the background
3. **Blank chat requiring force-reload** - Chats often appear blank and
require switching to another chat to force a reload (closes
[#1771](https://github.com/twentyhq/core-team-issues/issues/1771))
## Root Cause
After extensive debugging, it appears **multiple instances of `useChat`
don't work well together**. The refactored architecture inadvertently
created scenarios where multiple `useChat` instances interfere with each
other.
## Resolution
Reverting to restore functionality. The umbrella hook pattern
optimization needs a different architectural approach that doesn't rely
on multiple `useChat` instances.
## Follow-up
While the umbrella hook feedback is valid, we need to rethink the
implementation strategy:
- Find an alternative to multiple `useChat` instances
- Possibly consolidate chat state management differently
groupMode should be undefined if no groupby is set on the secondary
axis!
This default value is also the reason -- all the logic -- where
groupMode was checked for conditional rendering -- for eg
, negative data labels when there is no groupby -- the labels should
appear below wasn't happening -- since there was always a default to
groupMode!
changes -
- getting rid of the default value on the bar chart DTO for groupMode
- on front -- make sure groupMode is only set when the secondary axis
gets groupBy id and proper cleanup
Prevent users from creating v2 chart types via the api.
Only created unit tests and not integration tests (since it's not that
important, and the v2 will be released soon), but tested via the api
playground.
# Introduction
When creating a view with v2 flag activated in production result in race
condition due to request being slow and //.
That's why we're introducing a batch create on view field here
closing https://github.com/twentyhq/core-team-issues/issues/1836
## In v2
- batch create view field endpoint is available
- frontend will target the new endpoint
## In v1
- batch create view field endpoint is not available
- frontend will stick to old fake batch view field creation loop
## Polish
- use persist view field is quite verbose as contains two data model we
could aim to create an update many view fields in order to standardize
new pattern
changes -
- make iframe side panel to match others -- ie use SidePanelHeader for
title
- make url optional in configuration to match that of the other widgets
(allow partial saves) - render No data status when error or no url
- split widget sizes into two -- graph widget sizes and widget sizes
(graph widgets are a subset of chart widgets)
- on draft creation, do not fetch the full version. Avoid the fetch of
steps and trigger
- on activation, we were performing 8 queries/mutations synchronously +
2 additional for automated triggers. I refacto the call it it gets
reduced to 4 queries/mutations + 2 additional for automated triggers
## Context
If selected date field of the calendar view has readonly, we should not
allow users to drag/drop cards nor allow them to add a new record
(resulting in a permission error on the BE due to the FE updating the
said field)
## Context
Switching from kanban layout to calendar was not displaying records
properly. Adding the missing state update (similar to kanban case a few
lines above)