## Summary
- Re-enable one lint rule that was temporarily disabled during the
ESLint-to-Oxlint migration:
- **`twenty/sort-css-properties-alphabetically`** in twenty-front — 578
violations auto-fixed across 390 files
- Document why **`typescript/consistent-type-imports`** cannot be
auto-fixed in twenty-server: NestJS relies on `emitDecoratorMetadata`
for DI, so converting constructor parameter imports to `import type`
erases them at compile time and breaks dependency injection at runtime
- Right-size CI runners, reducing 8-core usage from 18 jobs to 3:
| Change | Jobs | Rationale |
|--------|------|-----------|
| **Keep 8-core** | `ci-merge-queue/e2e-test`,
`ci-front/front-sb-build`, `ci-front/front-build` | Heavy builds needing
max CPU + memory (10GB NODE_OPTIONS, full Storybook webpack bundling) |
| **8-core → 4-core** | `ci-server` (build, lint-typecheck, validation,
test, integration-test), `ci-front/front-sb-test`,
`ci-zapier/server-setup`, `ci-sdk/sdk-e2e-test` | Already sharded into
10-12 parallel instances, I/O-bound (DB/Redis), or moderate single
builds |
| **8-core → 2-core** | `ci-emails/emails-test` | Trivially lightweight
(build + curl health check) |
| **Removed** | `ci-front/front-chromatic-deployment` | Dead code —
permanently disabled with `if: false` |
- Fix merge queue CI issues:
- **Concurrency**: Use `merge_group.base_ref` instead of unique merge
group ref so new queue entries cancel previous runs
- **Required status checks**: Add `merge_group` trigger to all 6
required CI workflows (front, server, shared, website, docker-compose,
sdk) with `changed-files-check` auto-skipped for merge_group events —
status check jobs auto-pass without re-running full CI
- **Build caching**: Add Nx build cache restore/save to E2E test job
with fallback to `main` branch cache for faster frontend and server
builds
## Test plan
- [ ] CI passes on this PR (verifies lint rule auto-fix works)
- [ ] Verify 4-core runner jobs complete within their 30-minute timeouts
- [ ] Verify merge queue status checks auto-pass (ci-front-status-check,
ci-server-status-check, etc.)
- [ ] Verify merge queue E2E concurrency cancels previous runs when a
new PR enters the queue
## Summary
Completes the migration of the frontend styling system from **Emotion**
(`@emotion/styled`, `@emotion/react`) to **Linaria** (`@linaria/react`,
`@linaria/core`), a zero-runtime CSS-in-JS library where styles are
extracted at build time.
This is the final step of the migration — all ~494 files across
`twenty-front`, `twenty-ui`, `twenty-website`, and `twenty-sdk` are now
fully converted.
## Changes
### Styling Migration (across ~480 component files)
- Replaced all `@emotion/styled` imports with `@linaria/react`
- Converted runtime theme access patterns (`({ theme }) => theme.x.y`)
to build-time `themeCssVariables` CSS custom properties
- Replaced `useTheme()` hook (from Emotion) with
`useContext(ThemeContext)` where runtime theme values are still needed
(e.g., passing colors to non-CSS props like icon components)
- Removed `@emotion/react` `css` helper usages in favor of Linaria
template literals
### Dependency & Configuration Changes
- **Removed**: `@emotion/react`, `@emotion/styled` from root
`package.json`
- **Added**: `@wyw-in-js/babel-preset`, `next-with-linaria` (for
twenty-website SSR support)
- Updated Nx generator defaults from `@emotion/styled` to
`@linaria/react` in `nx.json`
- Simplified `vite.config.ts` (removed Emotion-specific configuration)
- Updated `twenty-website/next.config.js` to use `next-with-linaria` for
SSR Linaria support
### Storybook & Testing
- Removed `ThemeProvider` from Emotion in Storybook previews
(`twenty-front`, `twenty-sdk`)
- Now relies solely on `ThemeContextProvider` for theme injection
### Documentation
- Removed the temporary `docs/emotion-to-linaria-migration-plan.md`
(migration complete)
- Updated `CLAUDE.md` and `README.md` to reflect Linaria as the styling
stack
- Updated frontend style guide docs across all locales
## How it works
Linaria extracts styles at build time via the `@wyw-in-js/vite` plugin.
All expressions in `styled` template literals must be **statically
evaluable** — no runtime theme objects or closures over component state.
- **Static styles** use `themeCssVariables` which map to CSS custom
properties (`var(--theme-color-x)`)
- **Runtime theme access** (for non-CSS use cases like icon `color`
props) uses `useContext(ThemeContext)` instead of Emotion's `useTheme()`
## Summary
Removes the `recoil` dependency entirely from `package.json` and
`twenty-front/package.json`, completing the migration to Jotai as the
sole state management library.
Removes all Recoil infrastructure: `RecoilRoot` wrapper from `App.tsx`
and test decorators, `RecoilDebugObserver`, Recoil-specific ESLint rules
(`use-getLoadable-and-getValue-to-get-atoms`,
`useRecoilCallback-has-dependency-array`), and legacy Recoil utility
hooks/types (`useRecoilComponentState`, `useRecoilComponentValue`,
`createComponentState`, `createFamilyState`, `getSnapshotValue`,
`cookieStorageEffect`, `localStorageEffect`, etc.).
Renames all `V2`-suffixed Jotai state files and types to their canonical
names (e.g., `ComponentStateV2` -> `ComponentState`,
`agentChatInputStateV2` -> `agentChatInputState`, `SelectorCallbacksV2`
-> `SelectorCallbacks`), and removes the now-redundant V1 counterparts.
Updates ~433 files across the codebase to use the renamed Jotai imports,
remove Recoil imports, and clean up test wrappers (`RecoilRootDecorator`
-> `JotaiRootDecorator`).
## Summary
Moves the custom ESLint rules from `tools/eslint-rules` to
`packages/twenty-eslint-rules` for better organization within the
monorepo packages structure.
## Changes
- Move `eslint-rules` from `tools/` to `packages/twenty-eslint-rules`
- Use `loadWorkspaceRules` from `@nx/eslint-plugin` to load custom rules
- Update all ESLint configs to use the `twenty/` rule prefix instead of
`@nx/workspace-`
- Update `project.json`, `jest.config.mjs` with new paths
- Update `package.json` workspaces and `nx.json` cache inputs
- Update Dockerfile reference
## Technical Details
The custom ESLint rules are now loaded using Nx's `loadWorkspaceRules`
utility which:
- Handles TypeScript transpilation automatically
- Allows loading workspace rules from any directory
- Provides a cleaner approach than the previous `@nx/workspace-`
convention
## Testing
- Verified all 17 custom ESLint rules load correctly from the new
location
- Verified linting works on dependent packages (twenty-front,
twenty-server, etc.)
Upgraded from 8.6.15 to 9.1.17 in two steps:
- 8.6.15 -> 9.0.0
- 9.0.0 -> 9.1.17
I had to disable `storybook-addon-cookie` since it is not supported for
Storybook 9. However, I do intend to upgrade to Storybook 10 when this
is merged, so we can replace the aforementioned add-on with this fork
specifically created to support Storybook 10 and above:
https://www.npmjs.com/package/@storybook-community/storybook-addon-cookie.
Additionally, once we upgrade to Version 10 successfully, I will start
looking into integrating the official Vitest add-on.
## Summary
This PR enforces the use of `@/` alias for imports instead of relative
parent imports (`../`).
## Changes
### ESLint Configuration
- Added `no-restricted-imports` pattern in `eslint.config.react.mjs` to
block `../*` imports with the message "Relative parent imports are not
allowed. Use @/ alias instead."
- Removed the non-working `import/no-relative-parent-imports` rule
(doesn't work properly in ESLint flat config)
### VS Code Settings
- Added `javascript.preferences.importModuleSpecifier: non-relative` to
`.vscode/settings.json` (TypeScript setting was already there)
### Code Fixes
- Fixed **941 relative parent imports** across **706 files** in
`packages/twenty-front`
- All `../` imports converted to use `@/` alias
## Why
- Consistent import style across the codebase
- Easier to move files without breaking imports
- Better IDE support for auto-imports
- Clearer understanding of where imports come from
## Summary
This PR adds the `lingui/no-unlocalized-strings` ESLint rule to detect
untranslated strings and fixes translation issues across multiple
components.
## Changes
### ESLint Configuration (`eslint.config.react.mjs`)
- Added comprehensive `ignore` patterns for non-translatable strings
(CSS values, HTML attributes, technical identifiers)
- Added `ignoreNames` for props that don't need translation (className,
data-*, aria-*, etc.)
- Added `ignoreFunctions` for console methods, URL APIs, and other
non-user-facing functions
- Disabled rule for debug files, storybook, and test files
### Components Fixed (~19 files)
- Object record components (field inputs, pickers, merge dialogs)
- Settings components (accounts, admin panel)
- Serverless function components
- Record table and title cell components
## Status
🚧 **Work in Progress** - ~124 files remaining to fix
This PR is being submitted as draft to allow progressive fixing of
remaining translation issues.
## Testing
- Run `npx eslint "src/**/*.tsx"` in `packages/twenty-front` to check
remaining issues
## Description
Fixed the height of the options menu button in the side panel footer to
be 24px instead of 32px, matching the height of other buttons in the
footer.
## Changes
- Added `size="small"` prop to the `Button` component in
`OptionsDropdownMenu.tsx`
- This ensures consistent button sizing across the side panel footer
## Before
The options menu button was 32px high (medium size), making it larger
than other footer buttons.
<img width="543" height="421" alt="image"
src="https://github.com/user-attachments/assets/3c4fdfd0-73d1-4884-a639-3382090dfe15"
/>
## After
The options menu button is now 24px high (small size), consistent with
other side panel footer buttons.
<img width="1000" height="824" alt="CleanShot 2025-11-26 at 18 50 43@2x"
src="https://github.com/user-attachments/assets/798e7975-a7a8-4c00-b2e7-c0d1261249f8"
/>
## Widget duplication
- Created a shared component for the option menu shared by the record
page, the dashboards and the workflows
- Fix arrow selection in the option menu in workflows, which wasn't
working
- Scroll to the new widget after creation and open the new widget
settings
https://github.com/user-attachments/assets/47b8dade-44bd-4ba2-a81c-01b09e8718d3
This PR essentially refactors some hard-coded values for width and
height in the table.
It also fixes a few differences from the Figma design, on the checkbox
column width and the top bar and view bar left alignment with the table.
The blue color has been set like before the refactor of the focus portal
(`theme.adaptiveColors.blue4`)
Fixes in https://github.com/twentyhq/core-team-issues/issues/1490 :
- Fix first drag and drop column width that has changed from main (see
Figma)
- Unify all widths, heights, z-index, etc. with constants
- Put same blue as before for focused portal
Also removed `focus-active` class because we now use a portal for the
focus.
The goal of this PR is to test if Twenty can support a large number of
members, a question which was raised by a large company that is
considering moving away from Salesforce.
I was expecting the currentWorkspaceMembersState to cause a lot more
issue. It would be very hard to get rid of it in the context of actors,
I think that would require a big refactoring. I thought we'd have to do
it but it turns out the perf are pretty good. One thing we need to
improve is the pagination on the roles page, we'll wait for @Bonapara to
update that
This PR prepares the refactor of record field definition and column
definition.
We need to separate the two concepts of FieldInput and FieldContext at
the cell level, and the new RecordField concept that will replace
FieldDefinition at the metadata and state level.
So we create a new ui sub-folder in the already existing record-field
folder, in order to separate those two concepts that are still very
close.
This PR removes any V2 naming in state management logic and some minor
utils and hooks.
It has a lot of changes but nearly all of them were made by the rename
functionality of vscode which is deterministic, so it shouldn't
introduce any regression.
QA has been made on this PR on the main features of the app without any
noticeable issue.
Also renamed some other v2 naming related items :
- TextInputV2 => TextInput
- TextInput => SettingsTextInput
- ObjectFilterDropdownFilterSelectMenuItemV2 =>
ObjectFilterDropdownFilterSelectMenuItem
- useInitDraftValueV2 => useInitDraftValue
- useOpenRecordTableCellV2 => useOpenRecordTableCell
This PR removes every legacy state management logic left in the code
base, we only keep our last component state management logic.
Removed :
- Scoped states logic
- Dropdown scope logic
- Scope id naming
- Component state v1
- Component state v2_alpha
# QA
| Component | Comments |
| --- | --- |
| AttachementDropdown | Ok |
| ObjectTasks | Ok |
| ActivityRichTextEditor | Ok |
| App | Ok dialogs work |
| AppRouterProviders | Ok dialogs work |
| RecordBoardScrollToFocusedCardEffect | Ok |
| RecordBoard | Ok |
| RecordBoardCard | OK |
| useSelectAllCards | Ok |
| RecordInlineCell | Ok |
| useInlineCell | Ok |
| RecordDetailRelationRecordsListItem | Ok |
| RecordDetailRelationSectionDropdownToMany | Ok |
| RecordDetailRelationSectionDropdownToOne | Ok |
| useHandleContainerMouseEnter | Ok |
| useResetTableRowSelection | Ok |
| useSelectAllRows | Ok |
| useSetRecordTableData | Ok |
| useRecordTable | Ok |
| useRecordTableMoveFocusedCell | Ok |
| useRecordTableMoveFocusedRow | Ok |
| useMoveHoverToCurrentCell | OK |
| useTriggerActionMenuDropdown | Ok |
| RecordTableBodyDragDropContextProvider | Ok |
| RecordTableHeaderCell | Ok |
| useSetCurrentRowSelected | Ok |
| useRecordTitleCell | Ok |
| SettingsObjectFieldActiveActionDropdown | Ok |
| SettingsObjectFieldInactiveActionDropdown | Ok |
| SettingsObjectFieldItemTableRow | Ok |
| SettingsObjectInactiveMenuDropDown | Ok |
| SettingsRoleEditEffect | Ok |
| SettingsRolesQueryEffect | Ok |
| Dropdown | Ok |
| useSelectableList | Ok |
| useSelectableListHotKeys | Ok |
| useSelectableListListenToEnterHotkeyOnItem | Ok |
| useNavigationSection | Ok |
| useCreateViewFromCurrentState | Ok |
| useDeleteViewFromCurrentState | Ok |
| useUpdateViewFromCurrentState | Ok |
| ViewPickerFavoriteFoldersDropdown | Ok |
| useCreateViewFromCurrentView | Ok |
| ViewBarDetails | Ok |
| WorkflowRunVisualizer | Ok |
| useHandleWorkflowRunDiagramCanvasInit | Ok |
| WorkflowDiagramCanvasBase | Ok |
| WorkflowRunVisualizerEffect | Ok |
| useRemoveStepFilter | Ok |
| useRemoveStepFilterGroup | Ok |
| useUpsertStepFilterSettings | Ok |
| WorkflowFindRecordsFilters | Ok |
| SettingsObjects | Ok |
resolve#13253
This PR enables the use of Google Place Autocomplete and Place Details
APIs in the backend. It allows users to automatically fill in address
fields by typing into the address1 input. The input is debounced, then
the Autocomplete API is called. Once the user selects an address, the
Place Details API is used to parse and fill in the individual address
fields.
https://github.com/user-attachments/assets/e04b8474-25b8-48f5-83d0-2074f8d5fc94
---------
Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Félix Malfait <felix@twenty.com>
This PR improves dropdown menu headers for filter and sort dropdown in
view bar and editable filter chips.
It adds what's necessary to navigate back or close the dropdown, so that
we don't rely solely on click outside to exit the dropdown.
This PR also refactors the components so that we clearly identify the
two code paths that can use filter dropdowns : view bar and filter chip,
everything that can be DRY stays in the object-filter-dropdown module
but we try to have our wrapping components in each distinct module
instead of blending everything with ternaries inside
object-filter-dropdown module.
The vector search input value wasn't correctly handled across the
different dropdowns, due to a wrong component instance management, since
the dropdown menu header improvement put this into light, I also
refactored the state management of the vector search input.
@Bonapara please check the QA video and tell me if it's ok, I didn't add
dropdown menu header on the advanced filter field list dropdown because
it's a select more than a standalone dropdown, what do you think ?
QA :
https://github.com/user-attachments/assets/17080f32-f302-436c-937b-3577715b7e84
QA Vector search fix :
https://github.com/user-attachments/assets/6367bbf6-8a98-4b53-86cf-6ba92be130eb
Fixes https://github.com/twentyhq/core-team-issues/issues/640
Fixes https://github.com/twentyhq/core-team-issues/issues/1206
This PR removes useDropdown barrel hook and refactors the legacy
useDropdown states to the last version of our recoil component state
management.
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This PR replaces the many calls of useDropdown by the new standalone
hooks : useCloseDropdown, useOpenDropdown and useToggleDropdown.
This will allow to remove useDropdown and then the dropdown recoil
component state v1.
A big round of QA has been made, with some bugs caught along the way.
Closes https://github.com/twentyhq/core-team-issues/issues/1155
Closes https://github.com/twentyhq/core-team-issues/issues/618
## QA
Component|Status|Comment
|---|---|---|
CurrentWorkspaceMemberFavorites|Ok|
FavoriteFolderPickerFooter|Ok|
AdvancedFilterAddFilterRuleSelect|Ok|
AdvancedFilterRecordFilterGroupOptionsDropdown|Ok|
AdvancedFilterRecordFilterOperandSelectContent|Ok|
AdvancedFilterRecordFilterOptionsDropdown|Ok|
useAdvancedFilterFieldSelectDropdown|Ok|
ObjectFilterDropdownBooleanSelect|Ok|
ObjectFilterDropdownOptionSelect|Ok|
ObjectOptionsDropdown|Ok|
ObjectOptionsDropdownLayoutContent|Ok|
ObjectSortDropdownButton|Ok|
useCloseSortDropdown|Ok|
FormDateTimeFieldInput|Ok|Bug detected, cannot select a month or a year,
see issue https://github.com/twentyhq/twenty/issues/12922
FormSingleRecordPicker|Ok|
MultiItemFieldMenuItem|Ok|
RecordDetailRelationRecordsListItem|Ok|
RecordDetailRelationSection|Ok|
RecordDetailRelationSectionDropdownToMany|Ok|
RecordDetailRelationSectionDropdownToOne|Ok|
RecordTableColumnAggregateFooterDropdownSubmenuContent|Ok|
RecordTableColumnAggregateFooterAggregateOperationMenuItems|Ok|
RecordTableColumnAggregateFooterMenuContent|Ok|
RecordTableColumnAggregateFooterValueCell|Ok|
RecordTableColumnHeadDropdownMenu|Ok|
RecordTableHeaderPlusButtonContent|Ok|
useTriggerActionMenuDropdown|Ok|
MultipleSelectDropdown|Ok|
RecordBoardColumnHeaderAggregateDropdownButton|Ok|
SettingsDataModelFieldSelectFormOptionRow|Ok|
SettingsDataModelNewFieldBreadcrumbDropDown|Ok|
SettingsObjectFieldActiveActionDropdown|Ok|
SettingsObjectFieldInactiveActionDropdown|Ok|
SettingsObjectInactiveMenuDropDown|Ok|
SettingsSecurityApprovedAccessDomainRowDropdownMenu|Couldn’t test|
SettingsSecuritySSORowDropdownMenu|Couldn’t test|
SettingsAccountsRowDropdownMenu|Ok|
SettingsRoleAssignment|Ok|
SettingsServerlessFunctionTabEnvironmentVariableTableRow|Couldn’t test|
MatchColumnToFieldSelect|Ok|
SubMatchingSelectDropdownButton|Ok|Removed conflicting duplicate open
dropdown
SubMatchingSelectRowRightDropdown|Ok|
CurrencyPickerDropdownButton|Ok|
IconPicker|Ok|
DateTimePicker|Ok|
PhoneCountryPickerDropdownButton|OK|
Select|Ok|
Dropdown|Ok|Not QAing all dropdowns in the app because the ones of this
QA are enough to show up that Dropdown is behaving correctly on a lot of
use cases
DropdownMenuInnerSelect|Ok|
TabList|Ok|Removed onClickOutside called in dropdown clickable
component, validated with Raph who recently worked on this
DateInput|Ok|
MultiWorkspaceDropdownDefaultComponents|Ok|
AdvancedFilterChip|Ok|
EditableFilterDropdownButton|Ok|
UpdateViewButtonGroup|Ok|
ViewBarDetailsAddFilterButton|Ok|
ViewBarFilterButton|Ok|
ViewBarFilterDropdown|Ok|
ViewBarFilterDropdownAdvancedFilterButton|Ok|
ViewPickerDropdown|Ok|
ViewPickerListContent|Ok|
ViewPickerOptionDropdown|Ok|
WorkflowEditTriggerDatabaseEventForm|Ok|
WorkflowVariablesDropdownWorkflowStepItems|Ok|
AttachmentDropdown|Ok|
SupportDropdown|Ok|
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This PR is a follow-up of the first refactor of dropdown hooks :
https://github.com/twentyhq/twenty/pull/12875
In this PR we continue by focusing on the replacement of those two
states that are still using the v1 of component states :
- isDropdownOpenComponentState
- dropdownPlacementComponentState
When then remove those two old states and now only use the new component
state v2.
## QA
Component | Status | Comments
-- | -- | --
RecordDetailRelationSectionDropdownToMany | Ok |
RecordDetailRelationSectionDropdownToOne | Ok |
WorkflowVariablesDropdown | Ok |
DropdownInternalContainer | Ok | Tested on tables and boards fields
# What this PR does
This PR introduces what’s needed to progressively refactor the
useDropdown hooks we have.
It removes useDropdownV2 and renames useDropdown used for multi-page
dropdowns to useDropdownContextStateManagement
## The 3 useDropdown hooks
There are currently 3 useDropdown hooks :
One is used for managing states in some dropdowns that have multiple
inner pages with contexts and without recoil. It is limited and would
need a separate refactoring, thus I just renamed it.
Then we have useDropdown and useDropdownV2, which followed our multiple
versions of recoil state management wrappers.
Now that the state management has been stabilized, we can merge
everything on the last version.
## What this refactor will allow next
This refactor will allow to refactor the legacy recoil state management,
because useDropdown is depending on legacy recoil states with scopeId.
Because there are only a dozen of those legacy states left, and the
dropdown’s ones are the harder to refactor, because swapping them as-is
causes a big QA, and if we have a big QA to do on all dropdowns, better
refactor the whole dropdown management and have everything clean.
After this refactor, we will be able to delete the legacy dropdown
states, and proceed with the other legacy states, then removing all the
legacy recoil state mangament.
## How do we allow progressive refactoring ?
There are many places where useDropdown is used.
To have an easier refactoring process, we want to merge multiple small
pull requests so that it is easier to QA and review.
For this we will maintain both legacy component state and component
state V2 in parallel for isDropdownOpen, so that the new hooks
`useOpenDropdown` , `useCloseDropdown` are doing the same thing than
`useDropdown` and `useDropdownV2` .
Thus for the moment, whether we use the legacy hooks or the new ones,
the effects are the same.
And we can have dropdowns operating on the old states and the new states
living side by side in the app.
## QA
Component | Status | Comments
-- | -- | --
CommandMenuActionMenuDropdown | Ok |
RecordIndexActionMenuDropdown | Ok |
RecordShowRightDrawerOpenRecordButton | Ok |
useCloseActionMenu | Ok |
CommandMenuContextChipGroups | Ok |
useCommandMenuCloseAnimationCompleteCleanup | Ok |
ObjectOptionsDropdown | Ok |
ObjectOptionsDropdownContent | Ok |
ObjectOptionsDropdownFieldsContent | Ok |
ObjectOptionsDropdownHiddenFieldsContent | Ok |
ObjectOptionsDropdownHiddenRecordGroupsContent | Ok |
ObjectOptionsDropdownLayoutContent | Ok |
ObjectOptionsDropdownLayoutOpenInContent | Ok |
ObjectOptionsDropdownMenuContent | Ok |
ObjectOptionsDropdownRecordGroupFieldsContent | Ok |
ObjectOptionsDropdownRecordGroupsContent | Ok |
ObjectOptionsDropdownRecordGroupSortContent | Ok |
RecordBoardColumnHeaderAggregateDropdown | Ok |
AggregateDropdownContent | Ok |
RecordBoardColumnHeaderAggregateDropdownFieldsContent | Ok |
RecordBoardColumnHeaderAggregateDropdownMenuContent | Ok |
RecordBoardColumnHeaderAggregateDropdownMenuContent | Ok |
RecordBoardColumnHeaderAggregateDropdownOptionsContent | Ok |
RecordBoard | Ok | Used closeAnyOpenDropdown instead for a better UX
RecordBoardCard | Ok |
useRecordBoardSelection | Ok |
RecordTableColumnAggregateFooterDropdownContent | Ok |
RecordTableColumnFooterWithDropdown | Ok |
useOpenRecordFilterChipFromTableHeader | Ok |
useCloseAnyOpenDropdown | Ok |
useCloseDropdownFromOutside | Removed | Removed because unused
useDropdownV2 | Removed | Removed because all calls have been removed
useOpenDropdownFromOutside | Removed | Removed because unused
useCloseAndResetViewPicker | Ok |
WorkflowVariablesDropdown | Ok |
This PR is the first part of a refactoring aiming to deprecate the
hotkey scopes api in favor of the new focus stack api which is more
robust.
The refactored components in this PR are the dropdowns and the side
panel/command menu.
- Replaced `useScopedHotkeys` by `useHotkeysOnFocusedElement` for all
dropdown components, selectable lists and the command menu
- Introduced `focusId` for all dropdowns and created a common hotkey
scope `DropdownHotkeyScope` for backward compatibility
- Replaced `setHotkeyScopeAndMemorizePreviousScope` occurrences with
`usePushFocusItemToFocusStack` and `goBackToPreviousHotkeyScope` with
`removeFocusItemFromFocusStack`
Note: Test that the shorcuts and arrow key navigation still work
properly when interacting with dropdowns and the command menu.
Bugs that I have spotted during the QA but which are already present on
main:
- Icon picker select with arrow keys doesn’t work inside dropdowns
- Some dropdowns are not selectable with arrow keys (no selectable list)
- Dropdowns in dropdowns don’t reset the hotkey scope correctly when
closing
- The table click outside is not triggered after closing a table cell
and clicking outside of the table
This PR introduces a new generic UI component DropdownMenuInnerSelect,
that improves the UI by allowing to have both a dropdown menu header and
a select in the header.
In this PR we implement it just for filter dropdown components.
Fixes https://github.com/twentyhq/core-team-issues/issues/1001
This PR refactors the `DropdownMenuItemsContainer` component and
simplifies its inner parts, which have been modified over months for
different needs without taking the time to have a global approach.
It should however be noted that due to the recent refactor of the
`DropdownContent`, it is now much easier to refactor
`DropdownMenuItemsContainer`, mainly because of the width management
being nicely handled by `DropdownContent` now.
Fixes https://github.com/twentyhq/twenty/issues/11766
# Changes
The `width` props of `DropdownMenuItemsContainer` and its usage in
calling components have been removed.
The multiple ternaries inside `DropdownMenuItemsContainer` have been
reduced to one ternary on `scrollable` props.
The `ScrollWrapper` usage has been removed from
`DropdownMenuItemsContainer`, because the only thing we need is to have
a simple `overflow-y: scroll;` CSS property.
Why ? Because it was previously relevant to have a `ScrollWrapper`, when
we were using an external library, but now that `ScrollWrapper` is a
simple `div` with overflowing, which only benefit is to expose a hook to
imperatively toggle this overflowing behavior from outside (mainly
useful for table fixed row and column), and that we don’t need this for
`DropdownMenuItemsContainer`, then it follows that we just need a simple
overflowing `div` container, which simplifies everything and boils down
our `DropdownMenuItemsContainer` to a straightforward and standard CSS
stack.
We remove the temporary `scrollWrapperHeightAuto` props that was used to
fix a bug in a previous PR, we also rollback `ScrollWrapper` to its
previous state with `width: 100%` and `height: 100%` and removed
`heightAuto` props.
The `hasMaxHeight` props is kept, but the `168` pixels value is
extracted in a constant.
# QA
Component | Comment
-- | --
CommandMenuActionDropdown | Reported bug
https://github.com/twentyhq/twenty/issues/12541
RecordIndexActionMenuDropdown |
AttachmentDropdown | Cannot test because cannot add a file (currently
broken, maybe because of permissions ?)
CommandMenuContextChipGroups |
FavoriteFolderNavigationDrawerItemDropdown |
FavoriteFolderPicker |
FavoriteFolderPickerFooter |
AdvancedFilterAddFilterRuleSelect |
AdvancedFilterFieldSelectMenu |
AdvancedFilterRecordFilterGroupOptionsDropdown |
AdvancedFilterRecordFilterOperandSelect |
AdvancedFilterRecordFilterOptionsDropdown |
AdvancedFilterSubFieldSelectMenu |
ObjectFilterDropdownBooleanSelect |
ObjectFilterDropdownCountrySelect |
ObjectFilterDropdownCurrencySelect |
ObjectFilterDropdownNumberInput |
ObjectFilterDropdownOptionSelect | Fixed “No result” case
ObjectFilterDropdownRecordRemoveFilterMenuItem | Removed because unused
ObjectFilterDropdownTextInput |
ObjectOptionsDropdownFieldsContent | Spotted bug with icon eye
https://github.com/twentyhq/twenty/issues/12545
ObjectOptionsDropdownHiddenFieldsContent | Spotted bug with icon eye
https://github.com/twentyhq/twenty/issues/12545
ObjectOptionsDropdownLayoutContent | Refactored
DropdownMenuItemsContainer usage with DropdownMenuSeparator, spotted bug
switch view type https://github.com/twentyhq/twenty/issues/12546
ObjectOptionsDropdownMenuContent | Refactored DropdownMenuItemsContainer
usage with DropdownMenuSeparator
ObjectOptionsDropdownLayoutOpenInContent |
ObjectOptionsDropdownMenuViewName |
ObjectOptionsDropdownRecordGroupFieldsContent |
ObjectOptionsDropdownRecordGroupSortContent |
ObjectSortDropdownButton |
RecordBoardColumnDropdownMenu |
RecordBoardColumnDropdownMenu |
RecordBoardColumnHeaderAggregateDropdownFieldsContent |
RecordBoardColumnHeaderAggregateDropdownMenuContent |
RecordBoardColumnHeaderAggregateDropdownOptionsContent |
MultiItemFieldInput | Added hasMaxHeight on list of items
MultiItemFieldMenuItem |
RecordGroupsVisibilityDropdownSection |
MultipleRecordPicker |
MultipleRecordPickerMenuItems |
SingleRecordPickerMenuItems |
SingleRecordPickerMenuItemsWithSearch |
RecordDetailRelationRecordsListItem |
RecordTableColumnAggregateFooterDropdownSubmenuContent |
RecordTableColumnAggregateFooterMenuContent |
RecordTableHeaderPlusButtonContent |
RecordTableHeaderPlusButtonContent |
MultipleSelectDropdown |
SettingsAccountsRowDropdownMenu |
ConfigVariableDatabaseInput |
ConfigVariableOptionsDropdownContent |
SettingsDataModelNewFieldBreadcrumbDropDown |
SettingsDataModelFieldSelectFormOptionRow |
SettingsObjectFieldActiveActionDropdown |
SettingsObjectFieldInactiveActionDropdown |
SettingsObjectInactiveMenuDropDown |
SettingsIntegrationDatabaseConnectionSummaryCard |
SettingsRoleAssignmentWorkspaceMemberPickerDropdown |
SettingsRolePermissionsObjectLevelObjectPickerDropdownContent | Cannot
test
SettingsSecurityApprovedAccessDomainRowDropdownMenu | Cannot test
SettingsSecuritySSORowDropdownMenu | Cannot test
SettingsServerlessFunctionTabEnvironmentVariableTableRow | Cannot test
MatchColumnSelectFieldSelectDropdownContent |
MatchColumnSelectSubFieldSelectDropdownContent |
SubMatchingSelectInput |
SupportDropdown |
IconPicker |
Select |
SelectInput |
CurrencyPickerDropdownSelect |
PhoneCountryPickerDropdownSelect |
CustomSlashMenu |
TabListDropdown | Cannot test
MultiWorkspaceDropdownDefaultComponents | Removed unnecessary
StyledDropdownMenuItemsContainer
MultiWorkspaceDropdownThemesComponents |
MultiWorkspaceDropdownWorkspacesListComponents |
UpdateViewButtonGroup |
ViewBarFilterDropdownFieldSelectMenu |
ViewFieldsVisibilityDropdownSection |
ViewPickerContentCreateMode |
ViewPickerContentEditMode |
ViewPickerListContent | Add hasMaxHeight to limit the height of view
list
ViewPickerOptionDropdown |
WorkflowEditTriggerDatabaseEventForm |
WorkflowVariablesDropdownFieldItems |
WorkflowVariablesDropdownObjectItems |
WorkflowVariablesDropdownWorkflowStepItems |
<!-- notionvc: a3a87101-9944-4b03-a29d-b2974d5ffa9d -->
---------
Co-authored-by: Charles Bochet <charles@twenty.com>