From c961d3a60dabb7213fb27a3e463f5eb0fea5757a Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Fri, 21 Mar 2025 16:19:19 +0100 Subject: [PATCH] Reorganized components in advanced filter dropdown (#11089) 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. --- .../components/AdvancedFilterDropdownRow.tsx | 9 ++ ...AdvancedFilterFieldSelectDrodownButton.tsx | 53 ++++++++++++ ...dvancedFilterFieldSelectDrodownContent.tsx | 20 +++++ .../AdvancedFilterFieldSelectSearchInput.tsx | 46 ++++++++++ ...rRecordFilterGroupChildOptionsDropdown.tsx | 27 ------ ...vancedFilterRecordFilterGroupChildren.tsx} | 36 +++----- .../AdvancedFilterRecordFilterGroupRow.tsx | 30 +++++++ ...vancedFilterRecordFilterOperandSelect.tsx} | 14 +-- .../AdvancedFilterRecordFilterRow.tsx | 44 ++++++++++ ...AdvancedFilterRootLevelViewFilterGroup.tsx | 85 ------------------ .../AdvancedFilterRootRecordFilterGroup.tsx | 65 ++++++++++++++ ...dvancedFilterValueInputDropdownButton.tsx} | 86 +++++++++++-------- .../components/AdvancedFilterViewFilter.tsx | 60 ------------- ...pdownFilterSelectCompositeFieldSubMenu.tsx | 3 +- .../AdvancedFilterDropdownButton.tsx | 4 +- 15 files changed, 339 insertions(+), 243 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownRow.tsx create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownButton.tsx create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownContent.tsx create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx delete mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown.tsx rename packages/twenty-front/src/modules/object-record/advanced-filter/components/{AdvancedFilterRecordFilterGroup.tsx => AdvancedFilterRecordFilterGroupChildren.tsx} (54%) create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow.tsx rename packages/twenty-front/src/modules/object-record/advanced-filter/components/{AdvancedFilterViewFilterOperandSelect.tsx => AdvancedFilterRecordFilterOperandSelect.tsx} (91%) create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow.tsx delete mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup.tsx create mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx rename packages/twenty-front/src/modules/object-record/advanced-filter/components/{AdvancedFilterViewFilterValueInput.tsx => AdvancedFilterValueInputDropdownButton.tsx} (54%) delete mode 100644 packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilter.tsx diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownRow.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownRow.tsx new file mode 100644 index 000000000..5bfc09163 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterDropdownRow.tsx @@ -0,0 +1,9 @@ +import styled from '@emotion/styled'; + +const StyledRow = styled.div` + display: flex; + width: 100%; + gap: ${({ theme }) => theme.spacing(2)}; +`; + +export const AdvancedFilterDropdownRow = StyledRow; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownButton.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownButton.tsx new file mode 100644 index 000000000..319e492fe --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownButton.tsx @@ -0,0 +1,53 @@ +import { AdvancedFilterFieldSelectDrodownContent } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownContent'; +import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown'; + +import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; +import { SelectControl } from '@/ui/input/components/SelectControl'; +import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import styled from '@emotion/styled'; + +const StyledContainer = styled.div` + flex: 2; +`; + +type AdvancedFilterFieldSelectDrodownButtonProps = { + recordFilterId: string; +}; + +export const AdvancedFilterFieldSelectDrodownButton = ({ + recordFilterId, +}: AdvancedFilterFieldSelectDrodownButtonProps) => { + const { advancedFilterDropdownId } = + useAdvancedFilterDropdown(recordFilterId); + + const currentRecordFilters = useRecoilComponentValueV2( + currentRecordFiltersComponentState, + ); + + const recordFilter = currentRecordFilters.find( + (recordFilter) => recordFilter.id === recordFilterId, + ); + + const selectedFieldLabel = recordFilter?.label ?? ''; + + return ( + + + } + dropdownComponents={} + dropdownHotkeyScope={{ scope: advancedFilterDropdownId }} + dropdownOffset={{ y: 8, x: 0 }} + dropdownPlacement="bottom-start" + /> + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownContent.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownContent.tsx new file mode 100644 index 000000000..5372872d1 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownContent.tsx @@ -0,0 +1,20 @@ +import { ObjectFilterDropdownFilterSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelect'; +import { ObjectFilterDropdownFilterSelectCompositeFieldSubMenu } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu'; +import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; + +export const AdvancedFilterFieldSelectDrodownContent = () => { + const [objectFilterDropdownIsSelectingCompositeField] = + useRecoilComponentStateV2( + objectFilterDropdownIsSelectingCompositeFieldComponentState, + ); + + const shouldShowCompositeSelectionSubMenu = + objectFilterDropdownIsSelectingCompositeField; + + return shouldShowCompositeSelectionSubMenu ? ( + + ) : ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx new file mode 100644 index 000000000..4a57b0734 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterFieldSelectSearchInput.tsx @@ -0,0 +1,46 @@ +import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import styled from '@emotion/styled'; +import { t } from '@lingui/core/macro'; + +export const StyledInput = styled.input` + background: transparent; + border: none; + border-top: none; + border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; + border-radius: 0; + border-top-left-radius: ${({ theme }) => theme.border.radius.md}; + border-top-right-radius: ${({ theme }) => theme.border.radius.md}; + color: ${({ theme }) => theme.font.color.primary}; + margin: 0; + outline: none; + padding: ${({ theme }) => theme.spacing(2)}; + min-height: 19px; + font-family: inherit; + font-size: ${({ theme }) => theme.font.size.sm}; + + font-weight: inherit; + max-width: 100%; + overflow: hidden; + text-decoration: none; + + &::placeholder { + color: ${({ theme }) => theme.font.color.light}; + } +`; + +export const AdvancedFilterFieldSelectSearchInput = () => { + const [objectFilterDropdownSearchInput, setObjectFilterDropdownSearchInput] = + useRecoilComponentStateV2(objectFilterDropdownSearchInputComponentState); + + return ( + ) => + setObjectFilterDropdownSearchInput(event.target.value) + } + /> + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown.tsx deleted file mode 100644 index 034f96b71..000000000 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { AdvancedFilterRecordFilterGroupOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupOptionsDropdown'; -import { AdvancedFilterRecordFilterOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown'; -import { isRecordFilterGroupChildARecordFilter } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilter'; -import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; -import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; - -type AdvancedFilterRecordFilterGroupChildOptionsDropdownProps = { - recordFilterGroupChild: RecordFilter | RecordFilterGroup; -}; - -export const AdvancedFilterRecordFilterGroupChildOptionsDropdown = ({ - recordFilterGroupChild, -}: AdvancedFilterRecordFilterGroupChildOptionsDropdownProps) => { - const isRecordFilter = isRecordFilterGroupChildARecordFilter( - recordFilterGroupChild, - ); - - return isRecordFilter ? ( - - ) : ( - - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx similarity index 54% rename from packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx rename to packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx index bc90f61c2..0889a8603 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildren.tsx @@ -1,18 +1,10 @@ import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect'; -import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell'; -import { AdvancedFilterRecordFilterGroupChildOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown'; +import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow'; -import { AdvancedFilterViewFilter } from '@/object-record/advanced-filter/components/AdvancedFilterViewFilter'; import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups'; import styled from '@emotion/styled'; import { isDefined } from 'twenty-shared'; -const StyledRow = styled.div` - display: flex; - width: 100%; - gap: ${({ theme }) => theme.spacing(2)}; -`; - const StyledContainer = styled.div<{ isGrayBackground?: boolean }>` align-items: start; background-color: ${({ theme, isGrayBackground }) => @@ -27,14 +19,14 @@ const StyledContainer = styled.div<{ isGrayBackground?: boolean }>` overflow: hidden; `; -type AdvancedFilterRecordFilterGroupProps = { +type AdvancedFilterRecordFilterGroupChildrenProps = { recordFilterGroupId: string; }; -export const AdvancedFilterRecordFilterGroup = ({ +export const AdvancedFilterRecordFilterGroupChildren = ({ recordFilterGroupId, -}: AdvancedFilterRecordFilterGroupProps) => { - const { currentRecordFilterGroup, childRecordFiltersAndRecordFilterGroups } = +}: AdvancedFilterRecordFilterGroupChildrenProps) => { + const { currentRecordFilterGroup, childRecordFilters } = useChildRecordFiltersAndRecordFilterGroups({ recordFilterGroupId, }); @@ -49,17 +41,13 @@ export const AdvancedFilterRecordFilterGroup = ({ return ( - {childRecordFiltersAndRecordFilterGroups.map((child, i) => ( - - - - - + {childRecordFilters.map((childRecordFilter, childRecordFilterIndex) => ( + ))} { + return ( + + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx similarity index 91% rename from packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx rename to packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx index fbe53fed9..3ea5d486f 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect.tsx @@ -20,21 +20,21 @@ const StyledContainer = styled.div` flex: 1; `; -type AdvancedFilterViewFilterOperandSelectProps = { - viewFilterId: string; +type AdvancedFilterRecordFilterOperandSelectProps = { + recordFilterId: string; }; -export const AdvancedFilterViewFilterOperandSelect = ({ - viewFilterId, -}: AdvancedFilterViewFilterOperandSelectProps) => { - const dropdownId = `advanced-filter-view-filter-operand-${viewFilterId}`; +export const AdvancedFilterRecordFilterOperandSelect = ({ + recordFilterId, +}: AdvancedFilterRecordFilterOperandSelectProps) => { + const dropdownId = `advanced-filter-view-filter-operand-${recordFilterId}`; const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); const filter = currentRecordFilters.find( - (recordFilter) => recordFilter.id === viewFilterId, + (recordFilter) => recordFilter.id === recordFilterId, ); const { getFieldMetadataItemById } = useGetFieldMetadataItemById(); diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow.tsx new file mode 100644 index 000000000..7540fdeb9 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow.tsx @@ -0,0 +1,44 @@ +import { AdvancedFilterDropdownRow } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownRow'; +import { AdvancedFilterFieldSelectDrodownButton } from '@/object-record/advanced-filter/components/AdvancedFilterFieldSelectDrodownButton'; +import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell'; +import { AdvancedFilterRecordFilterOperandSelect } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect'; +import { AdvancedFilterRecordFilterOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown'; +import { AdvancedFilterValueInputDropdownButton } from '@/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton'; +import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; +import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup'; +import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; + +export const AdvancedFilterRecordFilterRow = ({ + recordFilterGroup, + recordFilter, + recordFilterIndex, +}: { + recordFilterGroup: RecordFilterGroup; + recordFilter: RecordFilter; + recordFilterIndex: number; +}) => { + return ( + + + + + + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup.tsx deleted file mode 100644 index 8c694ea7c..000000000 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect'; -import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell'; -import { AdvancedFilterRecordFilterGroupChildOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupChildOptionsDropdown'; - -import { AdvancedFilterRecordFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroup'; -import { AdvancedFilterViewFilter } from '@/object-record/advanced-filter/components/AdvancedFilterViewFilter'; -import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups'; -import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; -import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import styled from '@emotion/styled'; -import { isDefined } from 'twenty-shared'; - -const StyledRow = styled.div` - display: flex; - width: 100%; - gap: ${({ theme }) => theme.spacing(2)}; -`; - -const StyledContainer = styled.div<{ isGrayBackground?: boolean }>` - align-items: start; - background-color: ${({ theme, isGrayBackground }) => - isGrayBackground ? theme.background.transparent.lighter : 'transparent'}; - border: ${({ theme }) => `1px solid ${theme.border.color.medium}`}; - border-radius: ${({ theme }) => theme.border.radius.md}; - display: flex; - flex: 1; - flex-direction: column; - gap: ${({ theme }) => theme.spacing(2)}; - padding: ${({ theme }) => theme.spacing(2)}; - overflow: hidden; -`; - -export const AdvancedFilterRootLevelViewFilterGroup = () => { - const rootLevelRecordFilterGroup = useRecoilComponentValueV2( - rootLevelRecordFilterGroupComponentSelector, - ); - - const { childRecordFiltersAndRecordFilterGroups } = - useChildRecordFiltersAndRecordFilterGroups({ - recordFilterGroupId: rootLevelRecordFilterGroup?.id, - }); - - if (!isDefined(rootLevelRecordFilterGroup)) { - return null; - } - - return ( - - {childRecordFiltersAndRecordFilterGroups.map( - (recordFilterGroupChild, recordFilterGroupChildIndex) => - isRecordFilterGroupChildARecordFilterGroup(recordFilterGroupChild) ? ( - - - - - - ) : ( - - - - - - ), - )} - - - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx new file mode 100644 index 000000000..89a8150b5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup.tsx @@ -0,0 +1,65 @@ +import { AdvancedFilterAddFilterRuleSelect } from '@/object-record/advanced-filter/components/AdvancedFilterAddFilterRuleSelect'; + +import { AdvancedFilterRecordFilterGroupRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterGroupRow'; +import { AdvancedFilterRecordFilterRow } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterRow'; +import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups'; +import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; +import { isRecordFilterGroupChildARecordFilterGroup } from '@/object-record/advanced-filter/utils/isRecordFilterGroupChildARecordFilterGroup'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import styled from '@emotion/styled'; +import { isDefined } from 'twenty-shared'; + +const StyledContainer = styled.div<{ isGrayBackground?: boolean }>` + align-items: start; + background-color: ${({ theme, isGrayBackground }) => + isGrayBackground ? theme.background.transparent.lighter : 'transparent'}; + border: ${({ theme }) => `1px solid ${theme.border.color.medium}`}; + border-radius: ${({ theme }) => theme.border.radius.md}; + display: flex; + flex: 1; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(2)}; + padding: ${({ theme }) => theme.spacing(2)}; + overflow: hidden; +`; + +export const AdvancedFilterRootRecordFilterGroup = () => { + const rootRecordFilterGroup = useRecoilComponentValueV2( + rootLevelRecordFilterGroupComponentSelector, + ); + + const { childRecordFiltersAndRecordFilterGroups } = + useChildRecordFiltersAndRecordFilterGroups({ + recordFilterGroupId: rootRecordFilterGroup?.id, + }); + + if (!isDefined(rootRecordFilterGroup)) { + return null; + } + + return ( + + {childRecordFiltersAndRecordFilterGroups.map( + (recordFilterGroupChild, recordFilterGroupChildIndex) => + isRecordFilterGroupChildARecordFilterGroup(recordFilterGroupChild) ? ( + + ) : ( + + ), + )} + + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterValueInput.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx similarity index 54% rename from packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterValueInput.tsx rename to packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx index b6c76448c..446e22fcf 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilterValueInput.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton.tsx @@ -2,6 +2,7 @@ import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-d import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; +import { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands'; import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; import { SelectControl } from '@/ui/input/components/SelectControl'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; @@ -9,21 +10,27 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; -type AdvancedFilterViewFilterValueInputProps = { - viewFilterId: string; +import styled from '@emotion/styled'; + +const StyledValueDropdownContainer = styled.div` + flex: 3; +`; + +type AdvancedFilterValueInputDropdownButtonProps = { + recordFilterId: string; }; -export const AdvancedFilterViewFilterValueInput = ({ - viewFilterId, -}: AdvancedFilterViewFilterValueInputProps) => { - const dropdownId = `advanced-filter-view-filter-value-input-${viewFilterId}`; +export const AdvancedFilterValueInputDropdownButton = ({ + recordFilterId, +}: AdvancedFilterValueInputDropdownButtonProps) => { + const dropdownId = `advanced-filter-view-filter-value-input-${recordFilterId}`; const currentRecordFilters = useRecoilComponentValueV2( currentRecordFiltersComponentState, ); const filter = currentRecordFilters.find( - (recordFilter) => recordFilter.id === viewFilterId, + (recordFilter) => recordFilter.id === recordFilterId, ); const isDisabled = !filter?.fieldMetadataId || !filter.operand; @@ -40,43 +47,48 @@ export const AdvancedFilterViewFilterValueInput = ({ selectedFilterComponentState, ); - if (isDisabled) { - return ( - - ); - } + const operandHasNoInput = + filter && !configurableViewFilterOperands.has(filter.operand); return ( - + {operandHasNoInput ? ( + <> + ) : isDisabled ? ( - } - onOpen={() => { - setFieldMetadataItemIdUsedInDropdown(filter.fieldMetadataId); - setSelectedOperandInDropdown(filter.operand); - setSelectedFilter(filter); - }} - dropdownComponents={ - - - - } - dropdownHotkeyScope={{ scope: dropdownId }} - dropdownOffset={{ y: 8, x: 0 }} - dropdownPlacement="bottom-start" - dropdownMenuWidth={280} - /> + ) : ( + + } + onOpen={() => { + setFieldMetadataItemIdUsedInDropdown(filter.fieldMetadataId); + setSelectedOperandInDropdown(filter.operand); + setSelectedFilter(filter); + }} + dropdownComponents={ + + + + } + dropdownHotkeyScope={{ scope: dropdownId }} + dropdownOffset={{ y: 8, x: 0 }} + dropdownPlacement="bottom-start" + dropdownMenuWidth={280} + /> + )} + ); }; diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilter.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilter.tsx deleted file mode 100644 index 69a0632f6..000000000 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterViewFilter.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { AdvancedFilterViewFilterFieldSelect } from '@/object-record/advanced-filter/components/AdvancedFilterViewFilterFieldSelect'; -import { AdvancedFilterViewFilterOperandSelect } from '@/object-record/advanced-filter/components/AdvancedFilterViewFilterOperandSelect'; -import { AdvancedFilterViewFilterValueInput } from '@/object-record/advanced-filter/components/AdvancedFilterViewFilterValueInput'; - -import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; -import { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands'; -import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState'; -import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; -import styled from '@emotion/styled'; -import { isDefined } from 'twenty-shared'; - -const StyledValueDropdownContainer = styled.div` - flex: 3; -`; - -const StyledRow = styled.div` - flex: 1; - display: flex; - gap: ${({ theme }) => theme.spacing(2)}; - white-space: nowrap; - overflow: hidden; -`; - -type AdvancedFilterViewFilterProps = { - viewFilterId: string; -}; - -export const AdvancedFilterViewFilter = ({ - viewFilterId, -}: AdvancedFilterViewFilterProps) => { - const currentRecordFilters = useRecoilComponentValueV2( - currentRecordFiltersComponentState, - ); - - const recordFilter = currentRecordFilters.find( - (recordFilter) => recordFilter.id === viewFilterId, - ); - - if (!isDefined(recordFilter)) { - return null; - } - - return ( - - - - - - {configurableViewFilterOperands.has(recordFilter.operand) && ( - - )} - - - - ); -}; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx index cc4456e4a..63f870467 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterSelectCompositeFieldSubMenu.tsx @@ -1,6 +1,7 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { useAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterDropdown'; + import { advancedFilterViewFilterGroupIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterGroupIdComponentState'; import { advancedFilterViewFilterIdComponentState } from '@/object-record/object-filter-dropdown/states/advancedFilterViewFilterIdComponentState'; import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState'; @@ -21,6 +22,7 @@ import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-re import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; @@ -28,7 +30,6 @@ import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-sta import { useState } from 'react'; import { isDefined } from 'twenty-shared'; import { IconApps, IconChevronLeft, MenuItem, useIcons } from 'twenty-ui'; -import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; export const ObjectFilterDropdownFilterSelectCompositeFieldSubMenu = () => { const [searchText] = useState(''); diff --git a/packages/twenty-front/src/modules/views/components/AdvancedFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/components/AdvancedFilterDropdownButton.tsx index 8ecb837cc..2aea58913 100644 --- a/packages/twenty-front/src/modules/views/components/AdvancedFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/components/AdvancedFilterDropdownButton.tsx @@ -1,6 +1,6 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; -import { AdvancedFilterRootLevelViewFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRootLevelViewFilterGroup'; +import { AdvancedFilterRootRecordFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup'; import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { AdvancedFilterChip } from '@/views/components/AdvancedFilterChip'; @@ -20,7 +20,7 @@ export const AdvancedFilterDropdownButton = () => { } - dropdownComponents={} + dropdownComponents={} dropdownHotkeyScope={{ scope: ADVANCED_FILTER_DROPDOWN_ID }} dropdownOffset={{ y: 8, x: 0 }} dropdownPlacement="bottom-start"