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 is a minor rework of PR #10738.
I noticed an inconsistency with how Select options are passed as props.
Many files use constants stored in external files to pass options props
to Select objects. This allows for code reusability. Some files are not
passing options in this format.
I modified more files so that they use this method of passing options
props. I made changes to:
- WorkerQueueMetricsSection.tsx
- SettingsDataModelFieldBooleanForm.tsx
- SettingsDataModelFieldTextForm.tsx
- SettingsDataModelFieldNumberForm.tsx
- PlaygroundSetupForm.tsx
- ViewPickerContentCreateMode.tsx
I also noticed that some of these files were incorrectly using
useLingui(), so I fixed the import and usage where needed.
---------
Co-authored-by: Beau Smith <bsmith26@iastate.edu>
Co-authored-by: Charles Bochet <charles@twenty.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>
Adding the possibility to change the view name and incon from the
Options menu dropdown
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@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 mainly fixes advanced filters on kanban view.
It also fixes various bugs and cleans some old states.
## Advanced filters on kanban views
Kanban views use a different hook to retrieve data from the backend :
useLoadRecordIndexBoardColumn, this hook wasn't using the new state
currentRecordFilterGroupsComponentState.
## Removal of confusing duplicate states
A few different states were used for filters and states, where we only
need one for filters and one for sorts for all indexes. So we remove
here the different states that can lead to confusion about what state
should be used in what case.
States removed :
- recordIndexFilterState
- recordIndexSortState
- recordIndexViewFilterGroupsState
- tableFiltersComponentState
- tableSortsComponentState
We also remove the logic that was used to manage those states.
## Abstracted non composite field type check into a util
We abstract the check made in mapFieldMetadataToGraphQLQuery into a util
isNonCompositeField, because those kinds of checks should be stored into
a separate unique file that acts as a source of truth.
## Bug with advanced filter rule position not saved
The position of an advanced filter rule wasn't correctly saved in the
backend, here we remove the WorkspaceIsSystem decorator on the
positionInViewFilterGroup fields.
The function that saved view filters was also ignoring the field
positionInViewFilterGroup, we add it back.
## Bug with view picker option dropdown closing weirdly
The view picker option dropdown was closing as soon as we hovered
outside of the option dropdown, which was annoying for the user, here we
apply the same behavior as every dropdown in the app : closing on click
outside.
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 removes the legacy useGetCurrentView hook that still returned
view with combined filters and sorts, which we don't use anymore.
This allows to remove a bug where we couldn't select the "open in"
settings of a view.
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 ?)
This PR fixed ViewBar chips that were using margin instead of padding
and gaps.
This SortOrFilter chip was using margin left to space itself where it
was the role of the view bar to handle gap between chips and
padding-left at the beginning.
This PR implements the initialization of current record filter groups
state from view.
It also implements mapRecordFilterGroupToViewFilterGroup,
mapRecordFilterGroupLogicalOperatorToViewFilterGroupLogicalOperator and
mapViewFilterGroupLogicalOperatorToRecordFilterGroupLogicalOperator with
their corresponding unit tests.
Some unused states not caught by ESLint are also removed.
This PR implements a parallel code path to upsert and remove record
filter groups.
Those record filter groups aren't keeping track of the view id but since
they are in a view context, it's implicit that the advanced filter
feature can keep track of view for record filter groups.
We'll need record filter group for an upcoming feature without views, so
we need to abstract record filter group from view.
We have viewFilterGroup.id === recordFilterGroup.id, so it's easy to map
each other.
This PR removes what's left from record filter and record sort previous
logic to handle CRUD and state management with view.
So everything that is named combinedFilter and combinedSort is removed
here.
We implement currentRecordFilters and currentRecordSorts everywhere.
We also remove the event in a state onSortSelectComponentState. (a
pattern we want to avoid)
Workspace Member will get their own record page in the future.
This PR lays backend changes to prepare for this:
- Settings most fields on WorkspaceMember as system fields
- Renaming workspaceMember/workspaceMemberId to
forWorkspaceMember/forWorkspaceMemberId as it conflicts with the morph
relationship, if we want to be able to add a workspace member as
favorite
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
This PR implements new record sorts CRUD as already done on record
filters, which is based on record sorts state instead of combined view
sorts.
It implements a new useSaveRecordSortsToViewSorts with its underlying
utils, to compute diff between two view sorts array.
The associated unit tests have also been written.
This PR also fixes the bug where the view bar disappeared when deleting
the already saved record sort of a view.
As per title, add ~200 missing translations in different places of app.
Most places are now available for translation with AI but still some
aren't available - some enums (like in MenuItemSelectColor.tsx) or
values in complex types (like in
SettingsNonCompositeFieldTypeConfigs.ts) or values where are injected
some variables (like in SettingsDataModelFieldNumberForm.tsx)
---------
Co-authored-by: Félix Malfait <felix@twenty.com>
Closes https://github.com/twentyhq/core-team-issues/issues/410
- Added `openRecordIn` column in the `view` entity, which is set to
`SIDE_PANEL` by default
- Created a new option inside the view option dropdown to be able to set
`openRecordIn`
- Updated all record show page openings to reflect the setting behavior
- For `workflow`, `workflowVersion` and `workflowRun` (what I call
workflow objects), we want the default view `openRecordIn` to be set to
`RECORD_PAGE`. When seeding the views for the new workspaces, we set
`openRecordIn` to `RECORD_PAGE` for workflow objects. Since the workflow
objects views `openRecordIn` will be set to the default value
`SIDE_PANEL` for the existing workspaces when the sync metadata runs, I
created a script to run in the 0.43 update to update this value.
- Updated `closeCommandMenu` because of problems introduced by the
animate presence wrapper around the command menu. We now reset the
states at the end of the animation.
Note: We want to be able to open all workflow objects pages in the side
panel, but this requires some refactoring of the workflow module. For
now @Bonapara wanted to allow the possibility to change the
`openRecordIn` setting to `SIDE_PANEL` even for the workflows even if
it's buggy and not ready for the moment. Since this is an experimental
feature, it shouldn't cause too many problems.
This PR adds the same synchronization utils and hooks from view to
record sorts, as we did with view and record filters.
The goal is to apply what's in the view sorts only when needed.
Also added tests for those utils and hooks.
We also add useRemoveRecordSorts.
This PR implements a parallel code path to set record sorts without
impacting the actual sort, like we did on record filter.
We add a ViewBarRecordSortEffect which mirrors
ViewBarRecordFilterEffect.
It also adds availableFieldMetadataItemsForSortFamilySelector to replace
sortDefinitions progressively.
This PR is simple, it creates states for record sort, mirroring record
filter states.
It also implements RecordSortsComponentInstanceContext everywhere
RecordFiltersComponentInstanceContext is used.
This could be later merged into a common RecordContext concept but we
first need to decide how to handle the existing ContextStore and
RecordIndexContext and ideally end up with a unique context (or a
context provider component that wraps in all those contexts at once).
Some bugs are already present on main when trying to delete a sort, they
will be fixed in the next PRs.