## 🛠️ What this PR fixes
Fixes#12268
This PR fixes the UI behavior where the "Set as Primary" button was
incorrectly shown for emails or phones that are already marked as
primary. Instead, users now see a bookmark icon indicating the entry as
primary.
## 🎥 Demo
The attached video demonstrates the updated UI where the "Set as
Primary" button is hidden for primary contacts or emails and replaced by
a bookmark icon.
https://github.com/user-attachments/assets/9afcc818-fbb4-4e7c-8fa2-093fdc7d8a26
---------
Co-authored-by: Davinder Kumar <davinder.kumar@intverse.io>
Co-authored-by: Devessier <baptiste@devessier.fr>
Since https://github.com/twentyhq/twenty/pull/12286 we are now capturing
in sentry graphql queries errors in the FE.
We want to exclude InternalServerErrors because they are already
captured in sentry from the BE.
Changes for performance improvement.
The primary improvements include replacing GraphQL queries with
REST-based client configuration fetching and making the client config
non render-blocking
We should capture graphQL exceptions thrown in the FE in Sentry.
All the more so as we have just cleaned back-end errors in sentry,
preventing 4xx errors from being wrongfully sent to sentry.
Those 4xx errors should, except for `Unauthenticated` and `Forbidden`
errors (for now - this list can evolve), trigger a sentry FE error, as
we are not suppose to let users of the product interface trigger queries
that will fail with 4xx errors (for instance a malformed input).
We still miss an efficient way to group those errors together in sentry.
It could be the message but the message may be different for each user
if it contains user-specific data, and we don't always have control on
the message.
This can be done later as we iterate on improving sentry
This PR changes the way we do automatching in the import feature.
It uses [Fuse.js](https://www.fusejs.io/) to do a fuzzy text search on
fields and sub-fields.
The labels of sub-fields are now derived from the common config constant
we have for sub-fields.
Fixes#12093
This bug was quite hard to fix because it was an issue with the
`AnimatePresence` component of the framer motion library.
After investigating the issue with @Devessier, here is what we
understood:
Since the modal component has an exit animation but wasn't wrapped
inside an `AnimatePresence` component, the animation seemed to never be
marked as complete when we closed the modal and the component did not
appear anymore but was still in the dom.
This caused an issue when closing the side panel because the state
cleanup function of the command menu is triggered when its closing
animation is complete. This cleanup function emits a right drawer close
event, which is listened by the record table row to update it's state.
The `onExitComplete` was never triggered because the exit animation of
the modal was never considered as complete, and since it's a children
animation of the command menu `AnimatePresence`, this animation was
never considered as complete either (see [PresenceChild
doc](https://github.com/motiondivision/motion/blob/main/packages/framer-motion/src/components/AnimatePresence/PresenceChild.tsx).
This caused the cleanup function to never be executed and the close
event to never be emitted, so the row stayed active.
Before:
https://github.com/user-attachments/assets/a165039b-6203-43d6-b992-dcfb4dfb8f2b
After:
https://github.com/user-attachments/assets/42eab2e8-62c9-4c25-85d6-78210d7ebe89
Ensure the form effect is not erroneously triggered when the sign-in
step is not related to email or password. This resolves potential state
inconsistencies during the authentication flow.
Fix#12176
This PR has several objectives:
- Ignore invalid and empty links in the frontend
- Ignore empty links when creating or updating a link field in the
backend
- Throw an error when trying to create or update a link field with an
invalid link
The logic is mostly the same in the frontend and the backend: we take
the initial primaryLink and the secondaryLinks, we discard all the empty
links (with `url === '' || url === null`), and the primaryLink becomes
the first remaining link.
## Frontend
There are three parts in the frontend where we have to remove the empty
links:
- LinksDisplay
- LinksFieldInput
- isFieldValueEmpty; used in RecordInlineCell
## Backend
I put the logic in
`packages/twenty-server/src/engine/core-modules/record-transformer/services/record-input-transformer.service.ts`
as it's used by the REST API, the GraphQL API, and by Create Record and
Update Record actions in the workflows.
…scope
Replaced TextInputV2 with TextInput in
SettingsSecurityApprovedAccessDomain for consistency with the input
component. Added a new hotkey scope for the REST Playground page in
PageChangeEffect to enable keyboard shortcut menu functionality.
Fix#10981
## 🛠️ What this PR fixes
Fixes#12235
The "Exit Settings" link was stuck after navigating using a keyboard
shortcut(s).
This PR ensures the Exit Settings button works correctly.
## 🎥 Demo
The attached video demonstrates the issue being fixed and the link
behaving correctly.
**Note:** You can view the shortcuts I pressed in the bottom-left corner
of the video. To ensure they are clearly visible, avoid letting the
video’s progress bar overlap them by moving the cursor away from the
video after starting playback.
https://github.com/user-attachments/assets/4d705ddd-7b48-45c1-a292-127b9a88b68d
---------
Co-authored-by: Davinder Kumar <davinder.kumar@intverse.io>
We previously used classnames to exclude elements from the click outside
listener.
With this PR we can now use `data-click-outside-id` instead of
`classNames` to target the elements we want to exclude from the click
outside listener.
We can also add `data-globally-prevent-click-outside` to a component to
globally prevent triggering click outside listeners for other
components. This attribute is especially useful for confirmation modals
and snackbar items.
Fixes#11785:
https://github.com/user-attachments/assets/318baa7e-0f82-4e3a-a447-bf981328462d
Fixes https://github.com/twentyhq/twenty/issues/11566 + translates dates
- Date display bug: We had an issue with date (not date time) display
depending on the timezone the user had selected. The date is stored in
the db as yyyy-mm-dd, eg. 2025-05-01 for **May 1st, 2025**. When
returned this date is formatted in a UTC DateTime at midnight, so
2025-05-1 00:00:00. Then when displaying the date we were converting
this date using the timeZone, so 2025-04-30 17:00:00, thus displaying
**April 30th, 2025**. The fix chosen is that we should not take into
account the timezone for date (not date time!) displays as we always
want to show the same date.
- Date translation: dates were not translated, not in their default
display (_May 1st, 2025_) nor in their relative display (_about a month
ago_). The lib we use for date formatting, date-fns, offers a
translation option with pre-built `Locale`s from their lib.
Unfortunately and surprisingly we cannot just use directly string locale
codes (like `fr-FR`), cf [open issue on
date-fns](https://github.com/date-fns/date-fns/issues/3660). A util was
introduced to offset this by dynamically importing the right date-fns
Locale based on the locale code.
Fixes https://github.com/twentyhq/twenty/issues/12125
The root cause of the infinite loop was the calendar cursor. In some
cases, it was not properly displayed and was causing the loop because of
its animation that was always restarting.
We agreed with @FelixMalfait and @Bonapara that given the current
importance of the feature and the amount of issues associated, we remove
the cursor for now.
Fixes https://github.com/twentyhq/core-team-issues/issues/950
This issue was due to the memoization inside `useIsMatchingLocation`,
which was rerendered only if the pathname changed but not the search
params.
After discussion with @lucasbordeau, we decided to remove the hook
`useIsMatchingLocation` and to create an equivalent util function which
takes the location as an argument.
---------
Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
# Introduce focus stack to handle hotkeys
This PR introduces a focus stack to track the order in which the
elements are focused:
- Each focused element has a unique focus id
- When an element is focused, it is pushed on top of the stack
- When an element loses focus, we remove it from the stack
This focus stack is then used to determine which hotkeys are available.
The previous implementation lead to many regressions because of race
conditions, of wrong order of open and close operations and by
overwriting previous states. This implementation should be way more
robust than the previous one.
The new api can be incrementally implemented since it preserves
backwards compatibility by writing to the old hotkey scopes states.
For now, it has been implemented on the modal components.
To test this PR, verify that the shortcuts still work correctly,
especially for the modal components.
Chrome doesn't really respect preloading and was loading it before other
important assets, slowing down the app while in 99% of sessions people
don't check the REST API playground
follow up #12033
in #12033, SettingsDataModelFieldRelationForm I changed the the use of
objectMetadataItems to activeObjectMetadataItems, which filtered out
system objects. The naming was one factor for this confusion
Renaming it everywhere to specify that they don't include system objects
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
This pull request introduces changes to improve handling of nullable
values in link-related data structures and simplifies field value
generation logic. Key updates include adjustments to type definitions,
utility functions, and component logic to support `null` values for
links, along with the removal of the `generateDefaultFieldValue`
function in favor of `generateEmptyFieldValue`.
There will be a few more follow-up Pull Requests.
---
Closes https://github.com/twentyhq/twenty/issues/11844
### Solution
> After discussion with charles & weiko, we chose the long term
solution.
>
> Fix FE to request checkUserExists resolver with lowercased emails
> Add a decorator on User (and AppToken for invitation), to lowercase
email at user (appToken) creation. ⚠️ It works for TypeOrm .save method
only (there is no user email update in codebase, but in future it
could..)
> Add email lowercasing logic in external auth controller
> Fix FE to request sendInvitations resolver with lowercased emails
> Add migration command to lowercase all existing user emails and
invitation emails
> For other BE resolvers, we let them permissive. For example, if you
made a request on CheckUserExists resolver with uppercased email, you
will not found any user. We will not transform input before checking for
existence.
[link to comment
](https://github.com/twentyhq/twenty/pull/12130#discussion_r2098062093)
### Test 🚧
- sign-in and up from main subdomain and workspace sub domain > Google
Auth (lowercased email) ✔️ | Microsoft Auth (uppercased email ✔️ &
lowercased email) | LoginPassword (uppercased email ✔️& lowercased
email✔️)
- invite flow with uppercased and lowercased ✔️
- migration command + sign-in ( former uppercased microsoft email ✔️) /
sign-up ( former uppercased invited email ✔️)
closes https://github.com/twentyhq/private-issues/issues/278, closes
https://github.com/twentyhq/private-issues/issues/275, closes
https://github.com/twentyhq/private-issues/issues/279