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 000000000..74d77a3a3
--- /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 39253f821..4ca9a2244 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 0d9aa2edd..44e52b08e 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 bb126ae2e..ae9984749 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 000000000..4f80772da
--- /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 10f388514..4f5573d21 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) => (
-
-
- )}
-
- 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 ff708c87d..0205c1ab8 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 000000000..384f9c2c5
--- /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 4f2279091..34d820bd9 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 8f3101729..37512bddf 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 32dbf9003..a2a054d47 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 9c82c9b95..6a54b03b6 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 000000000..0c4a179be
--- /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 a9c4d826e..fa8dd5336 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 2a80c0a3e..f41aae84d 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 000000000..a1c4a66f4
--- /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 6dd452c4b..86b5de3bb 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 3b01c0414..e1c985e48 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 29c83f674..7b9de59bc 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,
});