# Introduction
In this PR we've migrated `twenty-shared` from a `vite` app
[libary-mode](https://vite.dev/guide/build#library-mode) to a
[preconstruct](https://preconstruct.tools/) "atomic" application ( in
the future would like to introduce preconstruct to handle of all our
atomic dependencies such as `twenty-emails` `twenty-ui` etc it will be
integrated at the monorepo's root directly, would be to invasive in the
first, starting incremental via `twenty-shared`)
For more information regarding the motivations please refer to nor:
- https://github.com/twentyhq/core-team-issues/issues/587
-
https://github.com/twentyhq/core-team-issues/issues/281#issuecomment-2630949682
close https://github.com/twentyhq/core-team-issues/issues/589
close https://github.com/twentyhq/core-team-issues/issues/590
## How to test
In order to ease the review this PR will ship all the codegen at the
very end, the actual meaning full diff is `+2,411 −114`
In order to migrate existing dependent packages to `twenty-shared` multi
barrel new arch you need to run in local:
```sh
yarn tsx packages/twenty-shared/scripts/migrateFromSingleToMultiBarrelImport.ts && \
npx nx run-many -t lint --fix -p twenty-front twenty-ui twenty-server twenty-emails twenty-shared twenty-zapier
```
Note that `migrateFromSingleToMultiBarrelImport` is idempotent, it's atm
included in the PR but should not be merged. ( such as codegen will be
added before merging this script will be removed )
## Misc
- related opened issue preconstruct
https://github.com/preconstruct/preconstruct/issues/617
## Closed related PR
- https://github.com/twentyhq/twenty/pull/11028
- https://github.com/twentyhq/twenty/pull/10993
- https://github.com/twentyhq/twenty/pull/10960
## Upcoming enhancement: ( in others dedicated PRs )
- 1/ refactor generate barrel to export atomic module instead of `*`
- 2/ generate barrel own package with several files and tests
- 3/ Migration twenty-ui the same way
- 4/ Use `preconstruct` at monorepo global level
## Conclusion
As always any suggestions are welcomed !
## Context
Reverting back the removal of "Log out" button. While it is now
accessible from the workspace picker, suspended workspaces don't have
access to that picker and are locked in the settings pages so I'm adding
back the log out button in the settings menu
<img width="225" alt="Screenshot 2025-03-21 at 15 52 40"
src="https://github.com/user-attachments/assets/d5453868-d043-49e9-9207-2cfdd65838da"
/>
closes#11013
Fixes the issue where users couldn't delete all text in select field
options. Removed the error throw for empty strings in the
computeOptionValueFromLabel function, allowing proper text deletion.
This error handling was redundant since the form validation already
prevents submission with empty values.
- Removed logout item from settings navigation drawer
- Removed logout locator and method from E2E tests
- Removed logout item from NavigationDrawer story
The logout functionality is now exclusively available through the menu
switcher, making the UI more consistent and reducing duplication.
Closes#11036
<img width="851" alt="Screenshot 2025-03-19 at 9 46 33 PM"
src="https://github.com/user-attachments/assets/3d73ec84-a2b7-4c4d-9605-dc83a9a760c1"
/>
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
- Move the JsonTree component and the other components to twenty-ui
- Rely on a React Context to provide translations
## Future work
It would be good to migrate the `createRequiredContext` function to
`twenty-ui`. I didn't want to migrate it in this PR but would have liked
to use it.
## Context
Some users were able to set an empty URL as webhook targetUrl, which was
breaking the Webhook List and Detail pages
## Fix
- Making sure to protect getHostNameOrThrow by isValidUrl
- rework webhook form to prevent creation of invalid webhooks
Fixes https://github.com/twentyhq/twenty/issues/10822
## Issue
https://discord.com/channels/1130383047699738754/1349428521075871846
@Devessier found a regression where the TabList was getting too tall in
some places. This happened because:
1. The ScrollWrapper inside TabList has `height: 100%` by default
2. The parent container in ShowPageSubContainer uses `display: flex`
when tabs should be shown
3. This combination makes the ScrollWrapper expand to fill the available
space
## Fix
Added a wrapper `<div>` around the ScrollWrapper in the TabList
component. This works because:
1. It creates a new flex container that contains the ScrollWrapper's
expansion
2. It preserves the flex context needed by ShowPageSubContainer for
proper layout
3. It maintains all visual styles including the tab borders
## Technical Details
While using `heightMode="fit-content"` on ScrollWrapper might seem like
a fix, it breaks the interaction between TabList and its parent
containers that use flex layout for positioning.
before:
<img width="537" alt="Screenshot 2025-03-13 at 02 16 03"
src="https://github.com/user-attachments/assets/9d4ddc81-68e8-44fe-8d32-da1d8e52492c"
/>
after:
<img width="518" alt="Screenshot 2025-03-13 at 02 11 50"
src="https://github.com/user-attachments/assets/dc8866c9-7dc3-4b59-8c18-d08233fc2143"
/>
# Introduction
This PR contains several SNAPSHOT files explaining big +
While refactoring the Object Model settings page in
https://github.com/twentyhq/twenty/pull/10653, encountered a critical
issue when submitting either one or both names with `""` empty string
hard corrupting a workspace.
This motivate this PR reviewing server side validation
I feel like we could share zod schema between front and back
## Refactored server validation
What to expect from Names:
- Plural and singular have to be different ( case insensitive and
trimmed check )
- Contains only a-z A-Z and 0-9
- Follows camelCase
- Is not empty => Is not too short ( 1 )
- Is not too long ( 63 )
- Is case insensitive( fooBar and fOoBar now rejected )
What to expect from Labels:
- Plural and singular have to be different ( case insensitive and
trimmed check )
- Is not empty => Is not too short ( 1 )
- Is not too long ( 63 )
- Is case insensitive ( fooBar and fOoBar now rejected )
close https://github.com/twentyhq/twenty/issues/10694
## Creation integrations tests
Created new integrations tests, following
[EachTesting](https://jestjs.io/docs/api#testeachtablename-fn-timeout)
pattern and uses snapshot to assert errors message. These tests cover
several failing use cases and started to implement ones for the happy
path but object metadata item deletion is currently broken unless I'm
mistaken @Weiko is on it
## Notes
- [ ] As we've added new validation rules towards names and labels we
should scan db in order to standardize existing values using either a
migration command or manual check
- [ ] Will review in an other PR the update path, adding integrations
tests and so on
CSS was loaded in a global context (full screen which might be re-used
for other use cases in the future) instead of a local context.
\+ small update on .env.example
### Context
For calendar and message sync job health monitoring, we used to
increment a counter in redis cache which could lead to concurrency
issue.
### Solution
- Update to a set structure in place of counter + use sAdd redis method
which is atomic
- Each minute another counter was incremented on a new cache key ->
Update to a 15s window
- Remove ONGOING status not needed. We only need status at job end (or
fail).
### Potential improvements
- Check for cache key existence before fetching data to avoid useless
call to redis ?
closes https://github.com/twentyhq/twenty/issues/10070
# Introduction
This PR contains around ~+300 tests + snapshot additions
Please check both object model creation and edition
Closes https://github.com/twentyhq/core-team-issues/issues/355
Refactored into two agnostic forms the Object Model settings page for
instance `/settings/objects/notes#settings`.
## `SettingsDataModelObjectAboutForm`
Added a new abstraction `SettingsUpdateDataModelObjectAboutForm` to wrap
`SettingsDataModelObjectAboutForm` in an `update` context

Schema:
```ts
const requiredFormFields = objectMetadataItemSchema.pick({
description: true,
icon: true,
labelPlural: true,
labelSingular: true,
});
const optionalFormFields = objectMetadataItemSchema
.pick({
nameSingular: true,
namePlural: true,
isLabelSyncedWithName: true,
})
.partial();
export const settingsDataModelObjectAboutFormSchema =
requiredFormFields.merge(optionalFormFields);
```
## `SettingsDataModelObjectSettingsFormCard`
Update on change

Schema:
```ts
export const settingsDataModelObjectIdentifiersFormSchema =
objectMetadataItemSchema.pick({
labelIdentifierFieldMetadataId: true,
imageIdentifierFieldMetadataId: true,
});
```
## Error management and validation schema
Improved the frontend validation form in order to attest that:
- Names are in camelCase
- Names are differents
- Names are not empty string ***SHOULD BE DONE SERVER SIDE TOO*** ( will
in a next PR, atm it literally breaks any workspace )
- Labels are differents
- Labels aren't empty strings
Hide the error messages as we need to decide what kind of styling we
want for our errors with forms
( Example with error labels )

During sign-up, new users setting new workspaces are required to choose
a billing plan (30-days or 7 days). They are then redirected to
billing.twenty.com to confirm and configure their plan choice.
Then they are quickly redirected to /settings/billing before being
redirected to /create-workspace.
The problem is that even though /create-workspace is not a gated path,
/settings/billing is: it is a path gated by WORKSPACE permission which
has not been granted to the user at this stage. therefore the user is
not redirected to /create-workspace since they do not reach
/settings/billing path but is redirected to the profile page instead.
(To see this feature flag must be removed + billing enabled: you can use
this branch [from this closed
PR](https://github.com/twentyhq/twenty/pull/10570)).
The chosen workaround is to bypass, in the FE, the permission check for
WORKSPACE permission if the workspace's activation status is
PENDING_CREATION. There is no need for any BE change.
In this PR
- updateWorkspaceMemberRole api was changed to stop allowing null as a
valid value for roleId. it is not possible anymore to just unassign a
role from a user. instead it is only possible to assign a different role
to a user, which will unassign them from their previous role. For this
reason in the FE the bins icons next to the workspaceMember on a role
page were removed
- updateWorkspaceMemberRole will throw if a user attempts to update
their own role
- tests tests tests!
Removed redundant handleSave and handleSubmit props in domain settings.
Integrated form submission logic directly into form components, ensuring
consistent behavior and reducing complexity. Updated button components
to explicitly support the "type" attribute for improved accessibility
and functionality.
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Prepare for better version upgrade system + split admin panel into two
permissions + fix GraphQL generation detection
---------
Co-authored-by: ehconitin <nitinkoche03@gmail.com>