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 fixes a bug that occurs during filter operand changes.
As a date filter can contain values that have a different shape, mainly
date ISO string and hard-coded relative dates, changing the operand
without resetting the value to its default was causing a crash.
This PR also extracts the logic that computes the right part of a filter
chip into a util instead of a difficult to understand ternary, thus
solving small bugs in the value displayed also.
Fixes https://github.com/twentyhq/twenty/issues/12778
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
Opening a date picker when creating a filter now directly applies
today's date to avoid any in-between state issues.
This allows the date picker and the operand selection to behave nicely
when creating a date filter.
Fixes https://github.com/twentyhq/core-team-issues/issues/1049
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>
Description:
Resolved a bug where pressing the Escape key did not clear the filter
chips when no filter value was present.
Added a call to onClickOutside inside the useScopedHotkeys hook to
ensure filter chips are removed when Escape is pressed and the dropdown
is open but empty.
https://github.com/user-attachments/assets/42ed35b0-f5a8-4d26-8407-fdd5e2cc4a42fix#12319
# Introdution
Reverting introduced bug by
https://github.com/twentyhq/twenty/pull/12082
We need to address the bug that was "fixed" by this in order to refresh
the recordFilters state, will have a look with @lucasbordeau 🙏
# Introduction
Diff description: ~500 tests and +500 additions
close https://github.com/twentyhq/core-team-issues/issues/731
## What has been done here
In a nutshell on a field metadata type ( `SELECT MULTI_SELECT` ) update,
we will be browsing all `ViewFilters` in a post hook searching for some
referencing related updated `fieldMetadata` select. In order to update
or delete the `viewFilter` depending on the associated mutations.
## How to test:
- Add FieldMetadata `SELECT | MULTI_SELECT` to an existing or a new
`objectMetadata`
- Create a filtered view on created `fieldMetadata` with any options you
would like
- Remove some options ( in the best of the world some that are selected
by the filter ) from the `fieldMetadata` settings page
- Go back to the filtered view, removed or updated options should have
been hydrated in the `displayValue` and the filtered data should make
sense
## All filtered options are deleted edge case
If an update implies that a viewFilter does not have any existing
related options anymore, then we remove the viewFilter
## Testing
```sh
PASS test/integration/metadata/suites/field-metadata/update-one-field-metadata-related-record.integration-spec.ts (27 s)
update-one-field-metadata-related-record
SELECT
✓ should delete related view filter if all select field options got deleted (2799 ms)
✓ should update related multi selected options view filter (1244 ms)
✓ should update related solo selected option view filter (1235 ms)
✓ should handle partial deletion of selected options in view filter (1210 ms)
✓ should handle reordering of options while maintaining view filter values (1487 ms)
✓ should handle no changes update of options while maintaining existing view filter values (1174 ms)
✓ should handle adding new options while maintaining existing view filter (1174 ms)
✓ should update display value with options label if less than 3 options are selected (1249 ms)
✓ should throw error if view filter value is not a stringified JSON array (1300 ms)
MULTI_SELECT
✓ should delete related view filter if all select field options got deleted (1127 ms)
✓ should update related multi selected options view filter (1215 ms)
✓ should update related solo selected option view filter (1404 ms)
✓ should handle partial deletion of selected options in view filter (1936 ms)
✓ should handle reordering of options while maintaining view filter values (1261 ms)
✓ should handle no changes update of options while maintaining existing view filter values (1831 ms)
✓ should handle adding new options while maintaining existing view filter (1610 ms)
✓ should update display value with options label if less than 3 options are selected (1889 ms)
✓ should throw error if view filter value is not a stringified JSON array (1365 ms)
Test Suites: 1 passed, 1 total
Tests: 18 passed, 18 total
Snapshots: 18 passed, 18 total
Time: 27.039 s
```
## Out of scope
- We should handle ViewFilter validation when extracting its definition
from the metadata
https://github.com/twentyhq/core-team-issues/issues/1009
## Concerns
- Are we able through the api to update an RATING fieldMetadata ? ( if
yes than that's an issue and we should handle RATING the same way than
for SELECT and MULTI_SELECT )
- It's not possible to group a view from a MULTI_SELECT field
The above points create a double nor a triple "lecture" to the post hook
effect:
- ViewGroup -> only SELECT
- VIewFilter -> only SELECT || MULTI_SELECT
- Rating nothing
I think we should determine the scope of all of that
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
This PR refactors all the dropdown content wrapping mechanism across the
entire app.
It refactors the internals of the `Dropdown` component and introduces a
new generic `DropdownContent` component that is a generic wrapper used
for each dropdown.
## Why this PR ?
Because we’ve been experiencing continuous regressions for months on the
dropdown content width, with weird scrolling behaviors in some and not
in others, and every time a solution was found for a particular set of
dropdowns, it broke another set of dropdowns, which wasn’t noticed
because doing the QA of all dropdowns of the app is very difficult for
fixing an apparently small bug.
## Don’t we already have a `DropdownMenu` component ?
Indeed, this new `DropdownContent` is almost like `DropdownMenu` and
took inspiration from it but `DropdownContent` acts as a generic content
container that sets the width of the whole dropdown, whether we have a
menu or not.
## Why don’t we put it directly in Dropdown internals ?
Because the Dropdown component is using a complex logic with floating-ui
middleware to compute its position and size, and for this logic to work
correctly, it cannot be responsible for the “wanted” width of its
content, because the children components, which the dropdown is not
aware of, can request different widths after the dropdown has been
mounted.
A good example with multiple use cases inside the same dropdown can be
found in `AdvancedFilterDropdownFilterInput`
Thus, it is the responsibility of the content of the dropdown to
determine the width it wants to have.
## What is the difference with DropdownMenuItemsContainer ?
We can have multiple `DropdownMenuItemsContainer` in a dropdown,
alongside other components like `DropdownMenuSeparator` or
`DropdownMenuHeader`, and each of those components behaves differently
regarding to its width, paddings, etc. Therefore it is logical that the
`DropdownMenuItemsContainer` cannot be responsible for the whole
dropdown content width, and trying to do so has been the cause of many
regressions for months.
Now `DropdownMenuItemsContainer` is taking a width of `auto` by default,
which is the best to adapt to a parent which has a defined width.
## How do I set the width of my dropdown now ?
By passing a pixel width to the props `widthInPixels` of
`DropdownContent`, which only accepts numbers to avoid any confusion
with `auto` , `100%` or `160px` and other specific width variables.
The `dropdownWidth` props has been removed from `<Dropdown>` to avoid
any confusion.
Also the `DropdownMenuItemsContainer` is now using `auto` as its default
width to fill the available space inside `DropdownContent` .
It is highly recommended to use the enum `GenericDropdownContentWidt` to
define your width.
## Where to use this new `DropdownContent` component ?
There are two main use cases.
If the dropdown content is defined directly inline in the Dropdown
props, then it is recommended to use it here too.
On the other hand if the dropdown content is abstracted in another
component, it’s recommended to use this new component alongside the
others components like `DropdownMenuItemsContainer`.
A good rule of thumb is to place `DropdownContent` where
`DropdownMenuItemsContainer`, `DropdownMenuSearchInput`, etc. are
placed.
## What if I have a custom width ?
Just define a constant like `ICON_PICKER_DROPDOWN_CONTENT_WIDTH` and use
it with the props `widthInPixels` .
Otherwise there’s a `GenericDropdownContentWidth` enum. The default
value being `GenericDropdownContentWidth.Medium` (or 200px), which most
dropdowns use.
## QA
Component | Comment
-- | --
AttachmentDropdown | Fixed overflowing (thanks to DropdownContent)
RecordIndexActionMenuDropdown |
CommandMenuActionMenuDropdown |
SupportDropdown | Fixed overflowing (thanks to DropdownContent)
MessageThreadSubscribersDropdownButton | Removed because unused
FavoriteFolderNavigationDrawerItemDropdown | Set width at Narrow
FavoriteFolderPicker |
ViewPickerOptionDropdown |
PageFavoriteFolderDropdown | Removed because unused
AdvancedFilterAddFilterRuleSelect |
AdvancedFilterAddFilterRuleSelect |
AdvancedFilterFieldSelectMenu |
AdvancedFilterRecordFilterGroupOptionsDropdown |
AdvancedFilterRecordFilterOperanceSelect | Set width at Narrow
AdvancedFilterLogicalOperatorDropdown | Set width at Narrow
AdvancedFilterRecordFilterOptionsDropdown |
AdvancedFilterRootRecordFilterGroup | Fixed broken horizontal scrolling
behavior
AdvancedFilterSubFieldSelectMenu |
AdvancedFilterDropdownFilterInput |
ObjectFilterDropdownBooleanSelect |
ObjectFilterDropdownCountrySelect | Fixed broken menu items container
ObjectFilterDropdownCurrencySelect | Set width to Large
ObjectFilterDropdownFilterInput |
ObjectFilterDropdownOperandDropdown | Fixed width that was not fixed
ObjectFilterDropdownFilterInput | Fixed width that wasn’t the same for
EditableFilterChip
ObjectFilterDropdownOperandSelect | Refactored
ObjectOptionsDropdownRecordGroupFieldsContent | Added missing separator
ObjectOptionDropdownFieldsContent |
ObjectOptionsDropdownHiddenFieldsContent |
ObjectOptionsDropdownLayoutContent |
ObjectOptionsDropdownLayoutOpenInContent |
ObjectOptionsDropdownMenuContent |
ObjectOptionsDropdownRecordGroupFieldsContent |
ObjectOptionsDropdownRecordGroupsContent |
ObjectOptionsDropdownRecordGroupSortContent |
ObjectOptionsDropdownHiddenRecordGroupsContent | Removed unnecessary
DropdownMenuItemsContainer
RecordBoardColumnHeaderAggregateDropdown | Fixed overflowing (thanks to
DropdownContent)
RecordBoardColumnHeaderAggregateDropdownFieldsContent | Fixed
overflowing (thanks to DropdownContent)
RecordBoardColumnHeaderAggregateDropdownMenuContent | Fixed overflowing
(thanks to DropdownContent)
RecordBoardColumnHeaderAggregateDropdownOptionsContent | Fixed
overflowing (thanks to DropdownContent)
MultiItemFieldInput | Fixed overflowing (thanks to DropdownContent)
MultiItemFieldMenuItem |
MultipleRecordPicker | Fixed overflowing (thanks to DropdownContent)
SingleRecordPicker |
RecordTableColumnAggregateDropdownSubmenuContent |
RecordTableColumnAggregateFooterMenuContent |
RecordTableColumnHeadDropdownMenu | Fixed overflowing (thanks to
DropdownContent)
RecordTableHeaderPlusButtonContent |
MultipleSelectDropdown | Broken width fixed
ObjectSortDropdownButton |
RecordDetailRelationRecordsListItem |
ConfigVariableDatabaseInput |
ConfigVariableOptionsDropdownContent |
SettingsObjectFieldActiveActionDropdown | Fixed overflowing (thanks to
DropdownContent)
SettingsObjectFieldDisabledActionDropdown | Set width at Narrow
SettingsObjectSummaryCard | Removed because unused
SettingsDataModelFieldSelectFormOptionRow |
SettingsDataModelNewFieldBreadcrumbDropdown |
SettingsObjectInactiveMenuDropDown |
SettingsRoleAssignementWorkspaceMemberPickerDropdown |
SettingsRolePermissionObjectLevelObjectPickerDropdownContent |
SettingsSecurityApprovedAccessDomainRowDropdownMenu | Couldn’t test
SettingsSecuritySSORowDropdownMenu | Couldn’t test
SettingsAccountsRowDropdownMenu | Fixed overflowing (thanks to
DropdownContent)
SettingsIntegrationDatabaseConnectionSummaryCard | Couldn’t test
SettingsServerlessFunctionTablEnvironmentVariableTableRow | Deactivated
scope
MatchColumnSelectFieldSelectDropdownContent | Removed now unnecessary
width on DropdownMenuItemsContainer
MatchColumnSelectSubFieldSelectDropdownContent |
SubMatchingSelectInput |
CurrencyPickerDropdownSelect |
IconPicker | Fixed overflowing (thanks to DropdownContent)
PhoneCountryPickerDropdownSelect |
Select | Refactored to drilldown wanted width of content, in this case
it’s intended
ExpandedListDropdown |
ShowPageAddButton | Removed because unused
MultiWorkspaceDropdownDefaultComponent |
MultiWorkspaceDropdownThemesComponent |
MultiWorkspaceDropdownWorkspacesListComponent |
AdvancedFilterDropdownButton |
EditableFilterChip |
EditableFilterDropdownButton |
UpdateViewButtonGroup |
ViewBarFilterDropdown |
ViewBarFilterDropdownFieldSelectMenu |
ViewPickerContentCreateMode |
ViewPickerContentEditMode |
ViewPickerListContent |
WorkflowEditTriggerDatabaseEventForm |
WorkflowVariablesDropdownFieldItems |
WorkflowVariablesDropdownObjectItems |
WorkflowVariablesDropdownWorkflowStepItems |
CommandMenuContextChipGroups |
RecordBoardColumnDropdownMenu |
MultiSelectInput |
SelectInput |
CustomSlashMenu |
DropdownMenu | Removed and replaced by DropdownContent
OverlayContainer and around |
<!-- notionvc: 1e23bdb8-2dda-4f8d-a64d-ecc829a768a2 -->
## Miscellaneous
Side notes :
- The `Select` component is now wrapping the `DropdownContent` because
it computes a dynamic width.
- The advanced filter dropdown has been fixed, it was broken when
resizing the window horizontally, we couldn’t scroll. This specific edge
case was taken into account when refactoring the whole dropdown content
system
- As discussed with Nitin, data-select-disable will probably be removed
entirely, so I let it as is, because right now it is not used by the
refactored d&d selection.
- Duplicate separators under DropdownMenuHeader have been removed.
Fixes : https://github.com/twentyhq/twenty/issues/12327
Fixes : https://github.com/twentyhq/core-team-issues/issues/951
In this PR:
- deprecating listenClickOutside ComparePixel mode as this is not
accurate. We were using to avoid portal issue with CompareHtmlRef mode
but this is still an issue when portalled content overflows the
container.
- add ClickOutsideContext to specify excluded className so portal
children can use it easily (part of the tooling)
- fix stories
- remove avoidPortal from dropdown as this was not used
This PR implements what's missing for ACTOR sub-field filtering,
filtering on the source sub-field was already working.
We can now filter on name sub-field.
Since the sub-fields are different types and cannot be filtered both by
text, we consider that a simple filter on ACTOR is filtering on the
source, we have to go to advanced filter to have the name filter
sub-field.
This PR implements sub-field filtering for the PHONES field type.
What was tricky was to have filtering work correctly on the
additionalPhones sub-field, which is an array of objects and is treated
as a RawJsonFilter. Now that it works for this sub-field, we can
implement the same logic for other similar sub-field like
additionalEmails and secondaryLinks.
This PR adds what's needed to filter on the ADDRESS sub-fields, notably
the country sub-field, that requires a country multi select component,
which was created in this PR (ObjectFilterDropdownCountrySelect)
This PR refactors the common logic between advanced filter dropdown
field selection logic and view bar filter dropdown field selection
logic, notably in useFilterDropdownSelectableFieldMetadataItems.
There are now new components to identify clearly what's tied to view bar
or advanced filter, it could be further simplified or factorized, but as
it is right now, it's simple enough to be maintained easily even if a
little bit too verbose, which is often the best trade-off we should aim
for.
Improvements :
- Added the CompositeFieldSubFieldName where needed
- Fixes bug in advanced filter dropdown input
- Fixes dropdown content width bug in advanced filter dropdown input
- Fixes a bug when inputing a Currency filter without a sub-field in
view bar filter dropdown
- Used DropdownMenuSearchInput instead of a custom StyledInput which was
doing exactly the same thing
- Factorized the state setting logic in
useSetAdvancedFilterDropdownStates in an anonymous function
setAdvancedFilterDropdownStates
- Created useSelectFilterFromViewBarFilterDropdown hook to have a more
meaningful and clear logic to abstract what happens when we select a
field to filter in the view bard field select dropdown
- Fixes a bug with advanced filter operand dropdown select which wasn't
modifying the current record filter and creating a stale state.
Fixes https://github.com/twentyhq/core-team-issues/issues/612
This PR cleans up after the refactor of selected filter state and apply
filter logic on record filter.
Since everything is now using the new
objectFilterDropdownCurrentRecordFilter state to derive the value for
all types, we don't need to maintain states for selected record ids and
selected options and the ViewBarFilterEffect that was initializing them.
Details :
- Removed objectFilterDropdownSelectedRecordIdsComponentState
- Removed objectFilterDropdownSelectedOptionValuesComponentState
- Removed ViewBarFilterEffect
This PR refactors the generic module object dropdown filter input.
We have multiple components for each filter type and each one was using
selectedFilterState and the applyRecordFilter hook to read and set its
value.
The main issue was that each component was forced to pass every property
of a RecordFilter to applyRecordFilter to only modify the value
property, thus creating a lot of unnecessary dependencies and tight
coupling between every component and hook that used the record filters.
Now we have each component only reading from a new
objectFilterDropdownCurrentRecordFilterComponentState, scoped to a
ObjectFilterDropdownComponentInstanceContext, thus whether we're in a
view bar dropdown, an editable filter chip dropdown or an advanced
filter dropdown, we know where to read the filter value from.
This component state might even be simplified by only storing the record
filter id, thus avoiding having to synchronize this state with its
counterpart in currentRecordFilterComponentState, but we should try
after the main refactor effort, as those two states aren't in the same
instance context.
We implement a new applyObjectFilterDropdownFilterValue hook to handle
the value setting from an object filter dropdown input component.
There's also a new useApplyObjectFilterDropdownOperand for doing the
same but for operand.
Another important thing that had to be done to keep a synchronous code
path was to set the states of each advanced filter row at the advanced
filter dropdown onOpen event, using useSetAdvancedFilterDropdownStates.
Finally we remove : useApplyRecordFilter, useSelectFilterUsedInDropdown
and selectedFilterComponentState which were making all of this zone
difficult to work with.
Closes https://github.com/twentyhq/core-team-issues/issues/718
Closes https://github.com/twentyhq/core-team-issues/issues/720
This PR refactors the non-generic part around ObjectFilterDropdown which
has been left in statu quo for months.
It also removes unused components.
Overall this PR is doing renaming and it re-organizes files into their
relevant modules.
This clarifies a lot what's at the intersection between
object-filter-dropdown and views modules.
This PR was originally about removing any remaining useEffect around
ObjectFilterDropdown but there wasn't any.
## Details
### Removed unused files
- GenericEntityFilterChip
- SingleEntityObjectFilterDropdownButton (was used for the Task/Note
standalone page which doesn't exist anymore)
### Re-organized non-generic components into ViewBarFilterDropdown
- Use VIEW_BAR_FILTER_DROPDOWN_ID instead of OBJECT_FILTER_DROPDOWN_ID
- Use FILTER_FIELD_LIST_ID for selectable list
- Refactored ObjectFilterDropdownButton into a simple
ViewBarFilterDropdown
- Renamed MultipleFiltersDropdownContent to ViewBarFilterDropdownContent
- Renamed MultipleFiltersButton to ViewBarFilterButton
- Integrated MultipleFiltersDropdownButton to ViewBarFilterDropdown
- Renamed AdvancedFilterButton to ViewBarDetailsAddFilterButton
### Tests
Fixed storybook test for ViewBarFilterDrodpown
This PR is refactoring a part of the ongoing filter refactor that was
blocking other refactor in that area.
Precisely, the dropdown filter that was used with the editable filter
chip was initialized by two conflicting useEffect, causing many unwanted
and hard to tackle bugs when modifying other places in the code that
used the same dropdown.
We also remove a difficult to maintain pattern around
onToggleColumnFilterComponentState, which was storing a click handler in
a state, we want to avoid this pattern.
The hook useHandleToggleColumnFilter is also removed and replaced by
useOpenRecordFilterChipFromTableHeader.
The code is now synchronous and starts from the user click event that is
triggered on a table cell header filter button click.
Also :
- Created a useSetEditableFilterChipDropdownStates that allows to
separate the code path of filter chip dropdown from the code path of
view bar global filter dropdown (will be continued in another refactor)
- Added useCreateEmptyFilterFromFieldMetadataItem to abstract empty
filter creation when opening a filter dropdown (will be used for other
refactor)
- Created a useOpenDropdownFromOutside hook that will also be used for
other refactor on filter
- Deleted EditableFilterDropdownButtonEffect
- Removed call to ViewBarFilterEffect (will be completely removed in
other refactors)
This PR implements sub-field filtering on CURRENCY field type and
improves many related zones.
- Created a ObjectFilterDropdownCurrencySelect dropdown component for
filtering on multiple currencies
- Added currencyCode sub-field to CurrencyFilter type
- Created getDefaultSubFieldNameForCompositeFilterableFieldType to avoid
situation where we don't have any sub field name in sub field filtering
situations.
- Implemented filtering for currencyCode in
computeFilterRecordGqlOperationFilter
- Implemented CURRENCY type in getRecordFilterOperands
- Implemented isMatchingCurrencyFilter for using in
isRecordMatchingFilter for proper optimistic rendering
- Created turnCurrencyIntoSelectableItem to help
ObjectFilterDropdownCurrencySelect
Testing :
- Added test for currency sub fields in getOperandsForFilterType
- Completely reworked isMatchingCurrencyFilter test
Improvements :
- Created a unique CURRENCIES constant to avoid re-creating it at
various places
- Derive the type FilterableFieldType from a constant array
FILTERABLE_FIELD_TYPES, so it's easier to work with
- Added areCompositeTypeSubFieldsFilterable
- Fixed a bug with empty value '[]' that was preventing the auto-removal
of a filter chip
Miscellaneous :
- Created isExpectedSubFieldName util to do a type-safe check of a
subFieldName
- Better naming : renamed isCompositeField to isCompositeFieldType
- Created isCompositeTypeFilterableWithAny to specify which field types
are filterable by any sub field
- Better naming : renamed
ObjectFilterDropdownFilterSelectCompositeFieldSubMenu to
ObjectFilterDropdownSubFieldSelect
- Better naming : renamed ObjectFilterDropdownFilterSelect to
ObjectFilterDropdownFieldSelect
- Created isEmptinessOperand util instead of duplicating the same
hard-coded check in multiple places
- Better naming : used subFieldName instead of compositeFieldName for
consistency
- UseEffect removal : removed unnecessary useEffect in
MultipleSelectDropdown
Fixes a bug where Empty and Not weren't appearing in filter chip in
particular cases
Fixes https://github.com/twentyhq/core-team-issues/issues/498
Fixes https://github.com/twentyhq/twenty/issues/7558
This PR implements what's missing to have sub-field filtering.
There is a backend modification to save subFieldName, we just add this
field on view filter workspace entity.
This PR adds subFieldName where missing in frontend, notably in
applyFilter calls, that will be refactored soon.
Also fixes a bug in ViewBar where Add Filter button was at the right
side of the ViewBar, while it should be right after the chips section.
Another bug fixed where we wouldn't delete an empty record filter on
dropdown click outside from the view bar, which was already the case
where using the filter chip dropdown.
<img width="512" alt="image"
src="https://github.com/user-attachments/assets/e9a2f8d2-a66f-4800-853a-4df5c6b627a9"
/>
<img width="495" alt="image"
src="https://github.com/user-attachments/assets/7542697b-0689-4095-9c3c-b5e47875355f"
/>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This PR fixes a bug that happened when navigating to a filtered view
from a record show page related record section, clicking on 'All'.
The problem was that the QueryParamsFiltersEffect effect component was
overwriting the currentRecordFilter of a different object metadata item
than the current view.
Which when we navigated back on the original view, had emptied the
filters, while they shouldn't change if we only navigate without
refreshing the app.
Fixes https://github.com/twentyhq/core-team-issues/issues/657
This PR is simply removing the : character on the filter chip when the
filter value is empty.
The issue originally was about removing the filter chip when closing the
filter value dropdown with an empty value but it is already the default
behavior.
Fixes https://github.com/twentyhq/core-team-issues/issues/658
1. Removing tokenPair internal variable of ApolloFactory. We will relay
on cookieStorage
2. setting the cookie explicitely instead of only relaying on recoil
cookieEffect which is too late
This PR was originally about fixing advanced filter dropdown auto resize
to avoid breaking the app main container, but the regression is not
limited to advanced filter dropdown, so this PR fixes the regression for
every dropdown in the app.
This PR adds a max dropdown max width to allow resizing dropdowns
horizontally also, which can happen easily for the advanced filter
dropdown.
In this PR we also start removing `fieldMetadataItemUsedInDropdown` in
component `AdvancedFilterDropdownTextInput` because it has no impact
outside of this component which is used only once.
The autoresize behavior determines the right padding-bottom between
mobile and PC.
Mobile :
<img width="604" alt="Capture d’écran 2025-04-07 à 16 03 12"
src="https://github.com/user-attachments/assets/fbdd8020-1bfc-4e01-8a05-3a9f114cdd40"
/>
PC :
<img width="757" alt="Capture d’écran 2025-04-07 à 16 03 30"
src="https://github.com/user-attachments/assets/f80a5967-8f60-40bb-ae3c-fa9eb4c65707"
/>
Fixes https://github.com/twentyhq/core-team-issues/issues/725
Fixes https://github.com/twentyhq/twenty/issues/11409
---------
Co-authored-by: Charles Bochet <charles@twenty.com>
# Introduction
closes https://github.com/twentyhq/core-team-issues/issues/591
Same than for `twenty-shared` made in
https://github.com/twentyhq/twenty/pull/11083.
## TODO
- [x] Manual migrate twenty-website twenty-ui imports
## What's next:
- Generate barrel and migration script factorization within own package
+ tests
- Refactoring using preconstruct ? TimeBox
- Lint circular dependencies
- Lint import from barrel and forbid them
### Preconstruct
We need custom rollup plugins addition, but preconstruct does not expose
its rollup configuration. It might be possible to handle this using the
babel overrides. But was a big tunnel.
We could give it a try afterwards ! ( allowing cjs interop and stuff
like that )
Stuck to vite lib app
Closed related PRs:
- https://github.com/twentyhq/twenty/pull/11294
- https://github.com/twentyhq/twenty/pull/11203
This PR fixes the issue about the easy fast follow-up part on advanced
filter.
Fixes https://github.com/twentyhq/core-team-issues/issues/675
Changes :
- Changed horizontal gap to spacing(1) for AdvancedFilterDropdownRow
- Created a DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET for all
sub-dropdowns in advanced filter dropdown with a y-offset of 2px.
- Created a DropdownOffset type
- Used a padding-left of spacing(2.25) in
AdvancedFilterLogicalOperatorCell to allign the disabled text with the
text in the Select component
- Added IconTrash and accent danger on
AdvancedFilterRecordFilterGroupOptionsDropdown and
AdvancedFilterRecordFilterOptionsDropdown
- Removed unnecessary CSS properties on
AdvancedFilterRootRecordFilterGroup
- Set dropdownMenuWith to 280 for AdvancedFilterValueInputDropdownButton
- Fixed Dropdown generic clickable component container that was
expanding
- Set IconFilter instead of IconFilterCog in AdvancedFilterChip
- Set AdvancedFilterDropdownButton dropdown content width to 650 instead
of 800
- Refactored generic IconButton component so that it disambiguates
secondary and tertiary variant for the color CSS props
[#11218](https://github.com/twentyhq/twenty/issues/11218) Fixed Filter
Reset Button height
- Replaced the default button with LightButton to align with Figma
design specs which Restores expected button size and appearance.
- Ensured the correct height, padding, and styling are applied
automatically.
- Wrapped the button inside StyledChipcontainer for consistency.
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
Co-authored-by: Charles Bochet <charlesBochet@users.noreply.github.com>
# 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 !
This PR essentially focuses on a refactor of the component hierarchy and
naming in advanced filter dropdown, to make it more readable and easy to
maintain.
This refactor was required because this area of the code is recursive,
so it's better to see the same abstract components in the recursion,
instead of trying to guess whether we have the same components than the
level above or not.
Also keep in mind that this refactor is meant to separate the advanced
filter code path from the view bar simple filter code path, while
reusing what's reusable, so here we have a first attempt at finding the
sweet spot, that we'll be able to duplicate on other filter dropdown use
cases.
- We now use AdvancedFilterRecordFilterGroupRow and
AdvancedFilterRecordFilterRow to make it clearer in the advanced filter
dropdown recursion where we are.
- Children component of AdvancedFilterRecordFilterRow have been
abstracted at the same level to make reading easier
- The field selection dropdown is now in a self-explanatory component
that follows the same naming pattern as other dropdowns in the app :
AdvancedFilterFieldSelectDrodownButton, together with
AdvancedFilterFieldSelectDrodownContent.
- The field selection search in the filter dropdown is now a standalone
component : AdvancedFilterFieldSelectSearchInput
- The UI container of a row has been abstracted in a new
AdvancedFilterDropdownRow
Miscellaneous :
- Renamed a bunch of view filter old naming to record filter naming.
This PR fixes some minor bugs on advanced filters.
## Dropdown menu header in filter input
The chevron down icon in the operand dropdown menu header was missing
due to a recent refactor of the DropdownMenuHeader component.
I just removed the unused EndIcon and replaced its usage by
EndComponent.
## Advanced filter dropdown staying open with 0 filters
The behavior we have for non-advanced filters is that the chip should
disappear if the filter gets empty, which is logical, an empty filter is
equivalent to not having filters, so don't want empty chips.
For advanced filters, the principle is the same, except that it's a bit
more complex to handle due to the recursive filter group hierarchy.
Here we create a useRemoveRootRecordFilterGroupIfEmpty hook, that we can
call everywhere a synchronous action should end up removing advanced
filters completely. (instead of using an effect)
This hook is distinct from removeRecordFilterGroup because we want
removeRecordFilterGroup to do only one job and we don't want it to hide
any side effect. It's better to have the side effect in a separate hook
that we call sequentially afterwards, in a self-explanatory manner.
## Miscellaneous
In this PR we add a new component selector to get the root level record
filter group, which is handy in a lot of cases.
The return type of the useChildRecordFiltersAndRecordFilterGroups hook
when it's empty has been fixed, though as discussed with Charles, it
would be better to turn it into selectors, which will certainly be done
in future PRs.
A recent change made
contextStoreCurrentObjectMetadataItemIdComponentState not initialized,
while it was being used for intializing currentRecordFilters,
currentRecordSorts and currentRecordFilterGroups states.
In this PR we use objectMetadataItem in RecordIndexContext to initialize
record filters, sorts and filter groups instead.
This PR fixes minor bugs on advanced filters :
- We couldn't close the advanced filter dropdown after removing a rule,
because the rule options dropdown wasn't closed, so focus dropdown id
was in a corrupted state.
- The text filter input in filter dropdown and the search input were the
same component, which was causing conflicts with state management but
this conflict didn't happen with the simple filter dropdown
implementation, the advanced filter dropdown brought this bug to light.
- The chevron down icon disappeared from the filter update button group,
this PR fixes it.
Fixes https://github.com/twentyhq/core-team-issues/issues/557
Fixes https://github.com/twentyhq/core-team-issues/issues/558
This PR fixes many bugs on advanced filters, the goal here was to have
CRUD working with other simple filters and sorts.
In order to test this PR you'll have to run a sync metadata.
Fixes https://github.com/twentyhq/core-team-issues/issues/560
## Changed positionInViewFilterGroup field metadata type
This PR changes the type of positionInViewFilterGroup to NUMERIC instead
of POSITION, there certainly was a confusion during the initial
development, where POSITION type seemed relevant but it is not for this
particular feature because the position in a view filter group is not
the position of a record, which is used for displaying and re-ordering
purpose in table and kanban views.
Here the positionInViewFilterGroup is a specific position concept tied
to a custom feature, and it is handled by the specific logic of this
advanced filter dropdown layout.
## Create new ids when duplicating a view
When we use create view from an existing view, the logic in
useCreateViewFromCurrentView will copy over filters, filter groups and
sorts. The problem is that it copies it with the same ids, and that if
the backend manages somehow to create new ids, the ids that are put in
parentViewFilterGroupId are corresponding to the old filter groups not
the duplicated new ones.
So we had to create a map of old id => new id so that everything that
has to be sent to the backend for creation already has the same mapping
of parent id but with new ids generated by the frontend.
## Bug with creating a simple filter
We couldn't create a simple filter when advanced filters were set, this
was because of findDuplicateRecordFilterInNonAdvancedRecordFilters which
wasn't doing what it's naming tells, it wasn't filtering on simple
filters only before looking for duplicates.
## Clean code
- Use lastChildPosition directly from
useChildRecordFiltersAndRecordFilterGroups instead of drilling it down
- Refactored AdvancedFilterDropdownButton to extract the code lower
where it is really needed in AdvancedFilterChip
- Renamed a few View to Record naming where relevant
This PR improves advanced filter code and fixes the bug that prevented
the creation of a filter group.
On the debugging side :
- Adding an advanced filter rule to create a group now works
On the refactoring side :
- We now use AdvancedFilterRecordFilterGroupChildOptionsDropdown to
clarify the code that show the option dropdown of a group.
- Refacatored useCurrentViewViewFilterGroup to
useChildRecordFiltersAndRecordFilterGroups. It is now using only
RecordFilter and RecordFilterGroup type instead of view types. It also
exports recordFilters and recordFilterGroups alone, when they are
children of a group, so we don't have to extract them from the merged
array that is typed RecordFilter | RecordFilterGroup, which is necessary
for displaying a group.
- Two typeguards have been introduced to help discern RecordFilter from
RecordFilterGroup : isRecordFilterGroupChildARecordFilterGroup and
isRecordFilterGroupChildARecordFilter, this allows to remove any typing
on child processing.
- Renaming from view to record (but there are still some left)
This PR partially fixes advanced filters that were not working even with
feature flag activated.
Bugs fixed here :
- Advanced filters are not applied
- Root advanced filters cannot be created
- Cannot close advanced filters dropdown
- Can create multiple times the same non-advanced filter (reserved for
advanced filters)
upsertRecordFilter and removeRecordFilter have been refactored to take
record filter id instead of field metadata id, because the user should
be allowed to apply multiple filters for the same field.
We now base view filter CRUD directly on id, otherwise it could lead to
inconsistencies between advanced filters and simple filters.
This PR also refactors an important hook :
computeRecordGqlOperationFilter, so that it takes an object instead of
multiple params.
There are still bugs left, they will be taken in other PRs.
This PR implements CRUD for view filter groups with the new logic as
already done for view filters and view sorts.
It also completely removes the old combined view filter group states and
usage.
This PR is quite big but the impact is limited since it only changes
advanced filters module, which is under feature flag at the moment, and
it is already in a broken state so unusable, even if someone activates
the feature flag.
This PR implements hooks and utils logic for handling CRUD and view
filter group comparison.
The main hook is useAreViewFilterGroupsDifferentFromRecordFilterGroups,
like view filters and view sorts.
Inside this hook we implement getViewFilterGroupsToCreate,
getViewFilterGroupsToDelete and getViewFilterGroupsToUpdate.
All of those come with their unit tests.
In this PR we also introduce a new util to prevent nasty bugs happening
when we compare undefined === null,
This util is called compareStrictlyExceptForNullAndUndefined and it
should replace every strict equality comparison between values that can
be null or undefined (which we have a lot)
This could be enforced by a custom ESLint rule, the autofix may also be
implemented (maybe the util should be put in twenty-shared ?)