From e53e09dfd384dd5f4aa141b87078e957f0c72d6a Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Fri, 11 Jul 2025 16:47:52 +0200 Subject: [PATCH] Improved dropdown menu headers for filter and sorts (#13177) This PR improves dropdown menu headers for filter and sort dropdown in view bar and editable filter chips. It adds what's necessary to navigate back or close the dropdown, so that we don't rely solely on click outside to exit the dropdown. This PR also refactors the components so that we clearly identify the two code paths that can use filter dropdowns : view bar and filter chip, everything that can be DRY stays in the object-filter-dropdown module but we try to have our wrapping components in each distinct module instead of blending everything with ternaries inside object-filter-dropdown module. The vector search input value wasn't correctly handled across the different dropdowns, due to a wrong component instance management, since the dropdown menu header improvement put this into light, I also refactored the state management of the vector search input. @Bonapara please check the QA video and tell me if it's ok, I didn't add dropdown menu header on the advanced filter field list dropdown because it's a select more than a standalone dropdown, what do you think ? QA : https://github.com/user-attachments/assets/17080f32-f302-436c-937b-3577715b7e84 QA Vector search fix : https://github.com/user-attachments/assets/6367bbf6-8a98-4b53-86cf-6ba92be130eb Fixes https://github.com/twentyhq/core-team-issues/issues/640 Fixes https://github.com/twentyhq/core-team-issues/issues/1206 --- .../ObjectFilterDropdownContentWrapper.tsx | 38 +++++ .../ObjectFilterDropdownFilterInput.tsx | 28 ++-- .../ObjectFilterDropdownFilterInputHeader.tsx | 52 ++++++- ...lterDropdownInnerSelectOperandDropdown.tsx | 19 ++- .../ObjectFilterDropdownVectorSearchInput.tsx | 38 +++++ .../components/ObjectSortDropdownButton.tsx | 134 ++++++------------ .../components/DropdownMenuInnerSelect.tsx | 4 +- .../EditableFilterChipDropdownContent.tsx | 21 +++ .../EditableFilterChipDropdownMenuHeader.tsx | 45 ++++++ .../EditableFilterDropdownButton.tsx | 11 +- .../components/ViewBarFilterDropdown.tsx | 4 + .../ViewBarFilterDropdownContent.tsx | 21 ++- .../ViewBarFilterDropdownFieldSelectMenu.tsx | 16 +++ .../ViewBarFilterDropdownFilterInput.tsx | 22 +++ ...BarFilterDropdownFilterInputMenuHeader.tsx | 49 +++++++ ...iewBarFilterDropdownVectorSearchButton.tsx | 21 ++- ...ViewBarFilterDropdownVectorSearchInput.tsx | 44 +----- .../views/hooks/useClearVectorSearchInput.ts | 16 +++ .../useSetEditableFilterChipDropdownStates.ts | 26 ++-- ...ectorSearchInputValueFromExistingFilter.ts | 6 +- .../states/vectorSearchInputComponentState.ts | 4 +- 21 files changed, 422 insertions(+), 197 deletions(-) create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx create mode 100644 packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput.tsx create mode 100644 packages/twenty-front/src/modules/views/components/EditableFilterChipDropdownContent.tsx create mode 100644 packages/twenty-front/src/modules/views/components/EditableFilterChipDropdownMenuHeader.tsx create mode 100644 packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInput.tsx create mode 100644 packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx create mode 100644 packages/twenty-front/src/modules/views/hooks/useClearVectorSearchInput.ts diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx new file mode 100644 index 0000000000..74d77a3a3f --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper.tsx @@ -0,0 +1,38 @@ +import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes'; +import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth'; +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; +import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; +import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { isDefined } from 'twenty-shared/utils'; + +export const ObjectFilterDropdownContentWrapper = ({ + children, +}: React.PropsWithChildren) => { + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + + if (!isDefined(fieldMetadataItemUsedInDropdown)) { + return null; + } + + const filterType = getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ); + + const isDateFilter = DATE_FILTER_TYPES.includes(filterType); + + return ( + + {children} + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx index 39253f8219..4ca9a22445 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput.tsx @@ -5,22 +5,19 @@ import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-d import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect'; import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; -import { ViewBarFilterDropdownVectorSearchInput } from '@/views/components/ViewBarFilterDropdownVectorSearchInput'; + import { ViewFilterOperand } from 'twenty-shared/src/types/ViewFilterOperand'; import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect'; -import { ObjectFilterDropdownFilterInputHeader } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader'; import { ObjectFilterDropdownInnerSelectOperandDropdown } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown'; import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput'; +import { ObjectFilterDropdownVectorSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput'; import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes'; -import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth'; import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes'; import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; -import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; -import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; @@ -62,11 +59,7 @@ export const ObjectFilterDropdownFilterInput = ({ selectedOperandInDropdown === ViewFilterOperand.VectorSearch; if (isVectorSearchFilter && isDefined(filterDropdownId)) { - return ( - - ); + return ; } if (!isDefined(fieldMetadataItemUsedInDropdown)) { @@ -82,24 +75,21 @@ export const ObjectFilterDropdownFilterInput = ({ if (isOnlyOperand) { return ( - - + <> - + ); } else if (isDateFilter) { return ( - - + <> - + ); } else { return ( - - + <> {TEXT_FILTER_TYPES.includes(filterType) && ( @@ -130,7 +120,7 @@ export const ObjectFilterDropdownFilterInput = ({ )} {filterType === 'BOOLEAN' && } - + ); } }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx index 0d9aa2edd5..44e52b08e8 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInputHeader.tsx @@ -1,16 +1,56 @@ -import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; - import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; +import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; +import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; +import { DropdownComponentInstanceContext } from '@/ui/layout/dropdown/contexts/DropdownComponentInstanceContext'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader'; +import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; +import { useLingui } from '@lingui/react/macro'; +import { useContext } from 'react'; +import { ViewFilterOperand } from 'twenty-shared/types'; +import { IconX } from 'twenty-ui/display'; export const ObjectFilterDropdownFilterInputHeader = () => { + const { t } = useLingui(); + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( fieldMetadataItemUsedInDropdownComponentSelector, ); - return ( - - {fieldMetadataItemUsedInDropdown?.label} - + const selectedOperandInDropdown = useRecoilComponentValueV2( + selectedOperandInDropdownComponentState, ); + + const { closeDropdown } = useCloseDropdown(); + + const dropdownInstanceId = useContext( + DropdownComponentInstanceContext, + )?.instanceId; + + const isInViewBarFilterDropdown = + dropdownInstanceId === VIEW_BAR_FILTER_DROPDOWN_ID; + + const isVectorSearchFilter = + selectedOperandInDropdown === ViewFilterOperand.VectorSearch; + + if (isInViewBarFilterDropdown) { + return ; + } else { + return ( + closeDropdown(dropdownInstanceId)} + Icon={IconX} + /> + } + > + {isVectorSearchFilter + ? t`Search` + : fieldMetadataItemUsedInDropdown?.label} + + ); + } }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx index bb126ae2e3..ae9984749f 100644 --- a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown.tsx @@ -1,4 +1,6 @@ import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions'; +import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes'; +import { DATE_PICKER_DROPDOWN_CONTENT_WIDTH } from '@/object-record/object-filter-dropdown/constants/DatePickerDropdownContentWidth'; import { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand'; import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; @@ -7,6 +9,7 @@ import { getOperandLabel } from '@/object-record/object-filter-dropdown/utils/ge import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand'; import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands'; import { DropdownMenuInnerSelect } from '@/ui/layout/dropdown/components/DropdownMenuInnerSelect'; +import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { isDefined } from 'twenty-shared/utils'; import { SelectOption } from 'twenty-ui/input'; @@ -54,16 +57,30 @@ export const ObjectFilterDropdownInnerSelectOperandDropdown = () => { ); }; - if (!isDefined(selectedOperandInDropdown)) { + if ( + !isDefined(selectedOperandInDropdown) || + !isDefined(fieldMetadataItemUsedInDropdown) + ) { return null; } + const filterType = getFilterTypeFromFieldType( + fieldMetadataItemUsedInDropdown.type, + ); + + const isDateFilter = DATE_FILTER_TYPES.includes(filterType); + + const widthInPixels = isDateFilter + ? DATE_PICKER_DROPDOWN_CONTENT_WIDTH + : GenericDropdownContentWidth.ExtraLarge; + return ( ); }; diff --git a/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput.tsx b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput.tsx new file mode 100644 index 0000000000..4f80772da5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput.tsx @@ -0,0 +1,38 @@ +import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; +import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions'; +import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState'; +import { useLingui } from '@lingui/react/macro'; +import { useDebouncedCallback } from 'use-debounce'; + +export const ObjectFilterDropdownVectorSearchInput = () => { + const { t } = useLingui(); + + const [vectorSearchInputValue, setVectorSearchInputValue] = + useRecoilComponentStateV2(vectorSearchInputComponentState); + + const { applyVectorSearchFilter } = useVectorSearchFilterActions(); + + const debouncedApplyVectorSearchFilter = useDebouncedCallback( + (value: string) => { + applyVectorSearchFilter(value); + }, + 500, + ); + + const handleSearchChange = (e: React.ChangeEvent) => { + const inputValue = e.target.value; + setVectorSearchInputValue(inputValue); + debouncedApplyVectorSearchFilter(inputValue); + }; + + return ( + + ); +}; diff --git a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx index 10f3885145..4f5573d21a 100644 --- a/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx +++ b/packages/twenty-front/src/modules/object-record/object-sort-dropdown/components/ObjectSortDropdownButton.tsx @@ -1,5 +1,3 @@ -import styled from '@emotion/styled'; - import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector'; import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem'; import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId'; @@ -20,7 +18,10 @@ import { visibleTableColumnsComponentSelector } from '@/object-record/record-tab import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; +import { DropdownMenuInnerSelect } from '@/ui/layout/dropdown/components/DropdownMenuInnerSelect'; import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer'; +import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel'; import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator'; import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton'; @@ -32,54 +33,12 @@ import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; -import { useTheme } from '@emotion/react'; import { Trans, useLingui } from '@lingui/react/macro'; import { useRecoilValue } from 'recoil'; -import { IconChevronDown, useIcons } from 'twenty-ui/display'; +import { IconX, useIcons } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; import { v4 } from 'uuid'; -export const StyledInput = styled.input` - background: transparent; - border: none; - border-top: none; - border-bottom: 1px solid ${({ theme }) => theme.border.color.light}; - border-radius: 0; - color: ${({ theme }) => theme.font.color.primary}; - margin: 0; - outline: none; - padding: ${({ theme }) => theme.spacing(2)}; - 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}; - } -`; - -const StyledSelectedSortDirectionContainer = styled.div` - background: ${({ theme }) => theme.background.secondary}; - box-shadow: ${({ theme }) => theme.boxShadow.light}; - border-radius: ${({ theme }) => theme.border.radius.md}; - - position: absolute; - top: 32px; - width: 100%; - z-index: 1000; -`; - -const StyledDropdownMenuHeaderEndComponent = styled.div` - padding: ${({ theme }) => theme.spacing(1)}; - display: flex; - align-items: center; -`; - export const ObjectSortDropdownButton = () => { const { resetRecordSortDropdownSearchInput } = useResetRecordSortDropdownSearchInput(); @@ -88,10 +47,6 @@ export const ObjectSortDropdownButton = () => { objectSortDropdownSearchInputComponentState, ); - const isRecordSortDirectionMenuUnfolded = useRecoilComponentValueV2( - isRecordSortDirectionDropdownMenuUnfoldedComponentState, - ); - const { resetSortDropdown } = useResetSortDropdown(); const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow(); @@ -195,8 +150,6 @@ export const ObjectSortDropdownButton = () => { const { t } = useLingui(); - const theme = useTheme(); - const selectableItemIdArray = [ ...visibleFieldMetadataItems.map((item) => item.id), ...hiddenFieldMetadataItems.map((item) => item.id), @@ -227,51 +180,50 @@ export const ObjectSortDropdownButton = () => { } dropdownComponents={ + closeSortDropdown()} + Icon={IconX} + /> + } + > + {t`Sort`} + + ({ + value: sortDirection, + label: sortDirection === 'asc' ? t`Ascending` : t`Descending`, + }))} + selectedOption={{ + value: selectedRecordSortDirection, + label: + selectedRecordSortDirection === 'asc' + ? t`Ascending` + : t`Descending`, + }} + onChange={(sortDirection) => + handleSortDirectionClick( + sortDirection.value as RecordSortDirection, + ) + } + widthInPixels={GenericDropdownContentWidth.ExtraLarge} + /> + + + setObjectSortDropdownSearchInput(event.target.value) + } + /> - {isRecordSortDirectionMenuUnfolded && ( - - - {RECORD_SORT_DIRECTIONS.map((sortDirection, index) => ( - handleSortDirectionClick(sortDirection)} - text={ - sortDirection === 'asc' ? t`Ascending` : t`Descending` - } - /> - ))} - - - )} - - setIsRecordSortDirectionMenuUnfolded( - !isRecordSortDirectionMenuUnfolded, - ) - } - EndComponent={ - - - - } - > - {selectedRecordSortDirection === 'asc' - ? t`Ascending` - : t`Descending`} - - - setObjectSortDropdownSearchInput(event.target.value) - } - /> {shouldShowVisibleFields && ( <> diff --git a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx index ff708c87dc..0205c1ab8c 100644 --- a/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx +++ b/packages/twenty-front/src/modules/ui/layout/dropdown/components/DropdownMenuInnerSelect.tsx @@ -33,6 +33,7 @@ export type DropdownMenuInnerSelectProps = { onChange: (value: SelectOption) => void; options: SelectOption[]; dropdownId: string; + widthInPixels?: number; }; export const DropdownMenuInnerSelect = ({ @@ -40,6 +41,7 @@ export const DropdownMenuInnerSelect = ({ onChange, options, dropdownId, + widthInPixels, }: DropdownMenuInnerSelectProps) => { const theme = useTheme(); @@ -54,7 +56,7 @@ export const DropdownMenuInnerSelect = ({ } dropdownComponents={ - + {options.map((selectOption) => ( { + return ( + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterChipDropdownMenuHeader.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterChipDropdownMenuHeader.tsx new file mode 100644 index 0000000000..384f9c2c52 --- /dev/null +++ b/packages/twenty-front/src/modules/views/components/EditableFilterChipDropdownMenuHeader.tsx @@ -0,0 +1,45 @@ +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; +import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; +import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useLingui } from '@lingui/react/macro'; +import { ViewFilterOperand } from 'twenty-shared/types'; +import { IconX } from 'twenty-ui/display'; + +export const EditableFilterChipDropdownMenuHeader = () => { + const { t } = useLingui(); + + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + + const selectedOperandInDropdown = useRecoilComponentValueV2( + selectedOperandInDropdownComponentState, + ); + + const isVectorSearchFilter = + selectedOperandInDropdown === ViewFilterOperand.VectorSearch; + + const { closeDropdown } = useCloseDropdown(); + + const handleBackButtonClick = () => { + closeDropdown(); + }; + + return ( + + } + > + {isVectorSearchFilter + ? t`Search` + : fieldMetadataItemUsedInDropdown?.label} + + ); +}; diff --git a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx index 4f2279091e..34d820bd97 100644 --- a/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx +++ b/packages/twenty-front/src/modules/views/components/EditableFilterDropdownButton.tsx @@ -4,10 +4,11 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter'; import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown'; import { EditableFilterChip } from '@/views/components/EditableFilterChip'; -import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput'; import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter'; import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty'; import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; +import { EditableFilterChipDropdownContent } from '@/views/components/EditableFilterChipDropdownContent'; +import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput'; import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates'; type EditableFilterDropdownButtonProps = { @@ -29,13 +30,17 @@ export const EditableFilterDropdownButton = ({ removeRecordFilter({ recordFilterId: recordFilter.id }); }; + const { clearVectorSearchInput } = useClearVectorSearchInput(); + const onFilterDropdownClose = useCallback(() => { const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter); if (recordFilterIsEmpty) { removeRecordFilter({ recordFilterId: recordFilter.id }); } - }, [recordFilter, removeRecordFilter]); + + clearVectorSearchInput(); + }, [recordFilter, removeRecordFilter, clearVectorSearchInput]); const { setEditableFilterChipDropdownStates } = useSetEditableFilterChipDropdownStates(); @@ -56,7 +61,7 @@ export const EditableFilterDropdownButton = ({ /> } dropdownComponents={ - + } dropdownOffset={{ y: 8, x: 0 }} dropdownPlacement="bottom-start" diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx index 8f3101729a..37512bddfe 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdown.tsx @@ -8,6 +8,7 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty'; import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent'; +import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput'; import { isDefined } from 'twenty-shared/utils'; import { ViewBarFilterButton } from './ViewBarFilterButton'; @@ -20,6 +21,8 @@ export const ViewBarFilterDropdown = () => { objectFilterDropdownCurrentRecordFilterComponentState, ); + const { clearVectorSearchInput } = useClearVectorSearchInput(); + const handleDropdownClickOutside = () => { const recordFilterIsEmpty = isDefined(objectFilterDropdownCurrentRecordFilter) && @@ -37,6 +40,7 @@ export const ViewBarFilterDropdown = () => { const handleDropdownClose = () => { resetFilterDropdown(); removeEmptyVectorSearchFilter(); + clearVectorSearchInput(); }; const handleDropdownOpen = () => { diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx index 32dbf90032..a2a054d475 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownContent.tsx @@ -1,8 +1,12 @@ -import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput'; import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState'; +import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; import { ViewBarFilterDropdownFieldSelectMenu } from '@/views/components/ViewBarFilterDropdownFieldSelectMenu'; +import { ViewBarFilterDropdownFilterInput } from '@/views/components/ViewBarFilterDropdownFilterInput'; +import { ViewBarFilterDropdownVectorSearchInput } from '@/views/components/ViewBarFilterDropdownVectorSearchInput'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; +import { ViewFilterOperand } from 'twenty-shared/types'; export const ViewBarFilterDropdownContent = () => { const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2( @@ -10,14 +14,23 @@ export const ViewBarFilterDropdownContent = () => { VIEW_BAR_FILTER_DROPDOWN_ID, ); + const selectedOperandInDropdown = useRecoilComponentValueV2( + selectedOperandInDropdownComponentState, + ); + + const isVectorSearchFilter = + selectedOperandInDropdown === ViewFilterOperand.VectorSearch; + + if (isVectorSearchFilter) { + return ; + } + const shouldShowFilterInput = objectFilterDropdownFilterIsSelected; return ( <> {shouldShowFilterInput ? ( - + ) : ( )} diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx index 9c82c9b951..6a54b03b62 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFieldSelectMenu.tsx @@ -16,10 +16,14 @@ import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/ import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu'; import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem'; +import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; +import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown'; import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds'; import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; import { useLingui } from '@lingui/react/macro'; +import { IconX } from 'twenty-ui/display'; export const StyledInput = styled.input` background: transparent; @@ -56,6 +60,8 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => { selectableVisibleFieldMetadataItems, } = useFilterDropdownSelectableFieldMetadataItems(); + const { closeDropdown } = useCloseDropdown(); + const selectableFieldMetadataItemIds = [ ...selectableVisibleFieldMetadataItems.map( (fieldMetadataItem) => fieldMetadataItem.id, @@ -83,6 +89,16 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => { return ( + closeDropdown()} + Icon={IconX} + /> + } + > + {t`Filter`} + { + return ( + + + + + ); +}; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx new file mode 100644 index 0000000000..0c4a179be1 --- /dev/null +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownFilterInputMenuHeader.tsx @@ -0,0 +1,49 @@ +import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown'; +import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector'; +import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState'; +import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader'; +import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent'; +import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2'; +import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput'; +import { useLingui } from '@lingui/react/macro'; +import { ViewFilterOperand } from 'twenty-shared/types'; +import { IconChevronLeft } from 'twenty-ui/display'; + +export const ViewBarFilterDropdownFilterInputMenuHeader = () => { + const { t } = useLingui(); + + const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2( + fieldMetadataItemUsedInDropdownComponentSelector, + ); + + const selectedOperandInDropdown = useRecoilComponentValueV2( + selectedOperandInDropdownComponentState, + ); + + const isVectorSearchFilter = + selectedOperandInDropdown === ViewFilterOperand.VectorSearch; + + const { clearVectorSearchInput } = useClearVectorSearchInput(); + + const { resetFilterDropdown } = useResetFilterDropdown(); + + const handleBackButtonClick = () => { + resetFilterDropdown(); + clearVectorSearchInput(); + }; + + return ( + + } + > + {isVectorSearchFilter + ? t`Search` + : fieldMetadataItemUsedInDropdown?.label} + + ); +}; diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchButton.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchButton.tsx index a9c4d826ef..fa8dd5336d 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchButton.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchButton.tsx @@ -9,7 +9,6 @@ import { IconSearch } from 'twenty-ui/display'; import { MenuItem } from 'twenty-ui/navigation'; import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds'; -import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId'; import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState'; import { useOpenVectorSearchFilter } from '@/views/hooks/useOpenVectorSearchFilter'; @@ -26,20 +25,16 @@ export const ViewBarFilterDropdownVectorSearchButton = () => { const { t } = useLingui(); const [, setVectorSearchInputValue] = useRecoilComponentStateV2( vectorSearchInputComponentState, - VIEW_BAR_FILTER_DROPDOWN_ID, ); const { setVectorSearchInputValueFromExistingFilter } = - useSetVectorSearchInputValueFromExistingFilter(VIEW_BAR_FILTER_DROPDOWN_ID); + useSetVectorSearchInputValueFromExistingFilter(); - const fieldSearchInputValue = useRecoilComponentValueV2( + const objectFilterDropdownSearchInput = useRecoilComponentValueV2( objectFilterDropdownSearchInputComponentState, - VIEW_BAR_FILTER_DROPDOWN_ID, ); const { applyVectorSearchFilter } = useVectorSearchFilterActions(); - const { openVectorSearchFilter } = useOpenVectorSearchFilter( - VIEW_BAR_FILTER_DROPDOWN_ID, - ); + const { openVectorSearchFilter } = useOpenVectorSearchFilter(); const isSelected = useRecoilComponentFamilyValueV2( isSelectedItemIdComponentFamilySelector, @@ -49,9 +44,9 @@ export const ViewBarFilterDropdownVectorSearchButton = () => { const handleSearchClick = () => { openVectorSearchFilter(); - if (fieldSearchInputValue.length > 0) { - setVectorSearchInputValue(fieldSearchInputValue); - applyVectorSearchFilter(fieldSearchInputValue); + if (objectFilterDropdownSearchInput.length > 0) { + setVectorSearchInputValue(objectFilterDropdownSearchInput); + applyVectorSearchFilter(objectFilterDropdownSearchInput); } else { setVectorSearchInputValueFromExistingFilter(); } @@ -69,8 +64,8 @@ export const ViewBarFilterDropdownVectorSearchButton = () => { text={ <> {t`Search`} - {fieldSearchInputValue && ( - {t`· ${fieldSearchInputValue}`} + {objectFilterDropdownSearchInput && ( + {t`· ${objectFilterDropdownSearchInput}`} )} } diff --git a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchInput.tsx b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchInput.tsx index 2a80c0a3e0..f41aae84d3 100644 --- a/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchInput.tsx +++ b/packages/twenty-front/src/modules/views/components/ViewBarFilterDropdownVectorSearchInput.tsx @@ -1,47 +1,13 @@ +import { ObjectFilterDropdownVectorSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput'; import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent'; -import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput'; import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth'; -import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2'; -import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions'; -import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState'; -import { useLingui } from '@lingui/react/macro'; -import { useDebouncedCallback } from 'use-debounce'; - -export const ViewBarFilterDropdownVectorSearchInput = ({ - filterDropdownId, -}: { - filterDropdownId: string; -}) => { - const { t } = useLingui(); - const [vectorSearchInputValue, setVectorSearchInputValue] = - useRecoilComponentStateV2( - vectorSearchInputComponentState, - filterDropdownId, - ); - const { applyVectorSearchFilter } = useVectorSearchFilterActions(); - - const debouncedApplyVectorSearchFilter = useDebouncedCallback( - (value: string) => { - applyVectorSearchFilter(value); - }, - 500, - ); - - const handleSearchChange = (e: React.ChangeEvent) => { - const inputValue = e.target.value; - setVectorSearchInputValue(inputValue); - debouncedApplyVectorSearchFilter(inputValue); - }; +import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader'; +export const ViewBarFilterDropdownVectorSearchInput = () => { return ( - + + ); }; diff --git a/packages/twenty-front/src/modules/views/hooks/useClearVectorSearchInput.ts b/packages/twenty-front/src/modules/views/hooks/useClearVectorSearchInput.ts new file mode 100644 index 0000000000..a1c4a66f41 --- /dev/null +++ b/packages/twenty-front/src/modules/views/hooks/useClearVectorSearchInput.ts @@ -0,0 +1,16 @@ +import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2'; +import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState'; + +export const useClearVectorSearchInput = () => { + const setVectorSearchInputValue = useSetRecoilComponentStateV2( + vectorSearchInputComponentState, + ); + + const clearVectorSearchInput = () => { + setVectorSearchInputValue(''); + }; + + return { + clearVectorSearchInput, + }; +}; diff --git a/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts b/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts index 6dd452c4ba..86b5de3bb0 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSetEditableFilterChipDropdownStates.ts @@ -24,15 +24,6 @@ export const useSetEditableFilterChipDropdownStates = () => { ? filterableFieldMetadataItems.concat(vectorSearchField) : filterableFieldMetadataItems; - const fieldMetadataItem = filterableFieldsWithVector.find( - (fieldMetadataItem) => - fieldMetadataItem.id === recordFilter.fieldMetadataId, - ); - - if (!isDefined(fieldMetadataItem)) { - return; - } - if (isVectorSearchFilter(recordFilter)) { set( vectorSearchInputComponentState.atomFamily({ @@ -42,13 +33,20 @@ export const useSetEditableFilterChipDropdownStates = () => { ); } - set( - fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ - instanceId: recordFilter.id, - }), - fieldMetadataItem.id, + const fieldMetadataItem = filterableFieldsWithVector.find( + (fieldMetadataItem) => + fieldMetadataItem.id === recordFilter.fieldMetadataId, ); + if (isDefined(fieldMetadataItem)) { + set( + fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({ + instanceId: recordFilter.id, + }), + fieldMetadataItem.id, + ); + } + set( selectedOperandInDropdownComponentState.atomFamily({ instanceId: recordFilter.id, diff --git a/packages/twenty-front/src/modules/views/hooks/useSetVectorSearchInputValueFromExistingFilter.ts b/packages/twenty-front/src/modules/views/hooks/useSetVectorSearchInputValueFromExistingFilter.ts index 3b01c04146..e1c985e483 100644 --- a/packages/twenty-front/src/modules/views/hooks/useSetVectorSearchInputValueFromExistingFilter.ts +++ b/packages/twenty-front/src/modules/views/hooks/useSetVectorSearchInputValueFromExistingFilter.ts @@ -3,17 +3,15 @@ import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInpu import { isDefined } from 'twenty-shared/utils'; import { useVectorSearchFilterState } from './useVectorSearchFilterState'; -export const useSetVectorSearchInputValueFromExistingFilter = ( - filterDropdownId: string, -) => { +export const useSetVectorSearchInputValueFromExistingFilter = () => { const [, setVectorSearchInputValue] = useRecoilComponentStateV2( vectorSearchInputComponentState, - filterDropdownId, ); const { getExistingVectorSearchFilter } = useVectorSearchFilterState(); const setVectorSearchInputValueFromExistingFilter = () => { const existingVectorSearchFilter = getExistingVectorSearchFilter(); + if (isDefined(existingVectorSearchFilter)) { setVectorSearchInputValue(existingVectorSearchFilter.value); } diff --git a/packages/twenty-front/src/modules/views/states/vectorSearchInputComponentState.ts b/packages/twenty-front/src/modules/views/states/vectorSearchInputComponentState.ts index 29c83f6740..7b9de59bc3 100644 --- a/packages/twenty-front/src/modules/views/states/vectorSearchInputComponentState.ts +++ b/packages/twenty-front/src/modules/views/states/vectorSearchInputComponentState.ts @@ -1,8 +1,8 @@ +import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext'; import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2'; -import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext'; export const vectorSearchInputComponentState = createComponentStateV2({ key: 'vectorSearchInputComponentState', defaultValue: '', - componentInstanceContext: ViewComponentInstanceContext, + componentInstanceContext: ObjectFilterDropdownComponentInstanceContext, });