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
This commit is contained in:
@ -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 (
|
||||||
|
<DropdownContent
|
||||||
|
widthInPixels={
|
||||||
|
isDateFilter
|
||||||
|
? DATE_PICKER_DROPDOWN_CONTENT_WIDTH
|
||||||
|
: GenericDropdownContentWidth.ExtraLarge
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</DropdownContent>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -5,22 +5,19 @@ import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-d
|
|||||||
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
|
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
|
||||||
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { ViewBarFilterDropdownVectorSearchInput } from '@/views/components/ViewBarFilterDropdownVectorSearchInput';
|
|
||||||
import { ViewFilterOperand } from 'twenty-shared/src/types/ViewFilterOperand';
|
import { ViewFilterOperand } from 'twenty-shared/src/types/ViewFilterOperand';
|
||||||
|
|
||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
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 { ObjectFilterDropdownInnerSelectOperandDropdown } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownInnerSelectOperandDropdown';
|
||||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
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_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 { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
||||||
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
@ -62,11 +59,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
selectedOperandInDropdown === ViewFilterOperand.VectorSearch;
|
selectedOperandInDropdown === ViewFilterOperand.VectorSearch;
|
||||||
|
|
||||||
if (isVectorSearchFilter && isDefined(filterDropdownId)) {
|
if (isVectorSearchFilter && isDefined(filterDropdownId)) {
|
||||||
return (
|
return <ObjectFilterDropdownVectorSearchInput />;
|
||||||
<ViewBarFilterDropdownVectorSearchInput
|
|
||||||
filterDropdownId={filterDropdownId}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||||
@ -82,24 +75,21 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
|
|
||||||
if (isOnlyOperand) {
|
if (isOnlyOperand) {
|
||||||
return (
|
return (
|
||||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
<>
|
||||||
<ObjectFilterDropdownFilterInputHeader />
|
|
||||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||||
</DropdownContent>
|
</>
|
||||||
);
|
);
|
||||||
} else if (isDateFilter) {
|
} else if (isDateFilter) {
|
||||||
return (
|
return (
|
||||||
<DropdownContent widthInPixels={DATE_PICKER_DROPDOWN_CONTENT_WIDTH}>
|
<>
|
||||||
<ObjectFilterDropdownFilterInputHeader />
|
|
||||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<ObjectFilterDropdownDateInput />
|
<ObjectFilterDropdownDateInput />
|
||||||
</DropdownContent>
|
</>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
<>
|
||||||
<ObjectFilterDropdownFilterInputHeader />
|
|
||||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
{TEXT_FILTER_TYPES.includes(filterType) && (
|
{TEXT_FILTER_TYPES.includes(filterType) && (
|
||||||
@ -130,7 +120,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||||
</DropdownContent>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,16 +1,56 @@
|
|||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
|
||||||
|
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
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 { 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 = () => {
|
export const ObjectFilterDropdownFilterInputHeader = () => {
|
||||||
|
const { t } = useLingui();
|
||||||
|
|
||||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||||
<DropdownMenuHeader>
|
selectedOperandInDropdownComponentState,
|
||||||
{fieldMetadataItemUsedInDropdown?.label}
|
|
||||||
</DropdownMenuHeader>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { closeDropdown } = useCloseDropdown();
|
||||||
|
|
||||||
|
const dropdownInstanceId = useContext(
|
||||||
|
DropdownComponentInstanceContext,
|
||||||
|
)?.instanceId;
|
||||||
|
|
||||||
|
const isInViewBarFilterDropdown =
|
||||||
|
dropdownInstanceId === VIEW_BAR_FILTER_DROPDOWN_ID;
|
||||||
|
|
||||||
|
const isVectorSearchFilter =
|
||||||
|
selectedOperandInDropdown === ViewFilterOperand.VectorSearch;
|
||||||
|
|
||||||
|
if (isInViewBarFilterDropdown) {
|
||||||
|
return <ViewBarFilterDropdownFilterInputMenuHeader />;
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<DropdownMenuHeader
|
||||||
|
StartComponent={
|
||||||
|
<DropdownMenuHeaderLeftComponent
|
||||||
|
onClick={() => closeDropdown(dropdownInstanceId)}
|
||||||
|
Icon={IconX}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{isVectorSearchFilter
|
||||||
|
? t`Search`
|
||||||
|
: fieldMetadataItemUsedInDropdown?.label}
|
||||||
|
</DropdownMenuHeader>
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
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 { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand';
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
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 { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { DropdownMenuInnerSelect } from '@/ui/layout/dropdown/components/DropdownMenuInnerSelect';
|
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { SelectOption } from 'twenty-ui/input';
|
import { SelectOption } from 'twenty-ui/input';
|
||||||
@ -54,16 +57,30 @@ export const ObjectFilterDropdownInnerSelectOperandDropdown = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isDefined(selectedOperandInDropdown)) {
|
if (
|
||||||
|
!isDefined(selectedOperandInDropdown) ||
|
||||||
|
!isDefined(fieldMetadataItemUsedInDropdown)
|
||||||
|
) {
|
||||||
return null;
|
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 (
|
return (
|
||||||
<DropdownMenuInnerSelect
|
<DropdownMenuInnerSelect
|
||||||
dropdownId={OBJECT_FILTER_DROPDOWN_INNER_SELECT_OPERAND_DROPDOWN_ID}
|
dropdownId={OBJECT_FILTER_DROPDOWN_INNER_SELECT_OPERAND_DROPDOWN_ID}
|
||||||
selectedOption={selectedOption}
|
selectedOption={selectedOption}
|
||||||
onChange={handleOperandChange}
|
onChange={handleOperandChange}
|
||||||
options={options}
|
options={options}
|
||||||
|
widthInPixels={widthInPixels}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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<HTMLInputElement>) => {
|
||||||
|
const inputValue = e.target.value;
|
||||||
|
setVectorSearchInputValue(inputValue);
|
||||||
|
debouncedApplyVectorSearchFilter(inputValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DropdownMenuSearchInput
|
||||||
|
autoFocus
|
||||||
|
type="text"
|
||||||
|
value={vectorSearchInputValue}
|
||||||
|
placeholder={t`Search`}
|
||||||
|
onChange={handleSearchChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -1,5 +1,3 @@
|
|||||||
import styled from '@emotion/styled';
|
|
||||||
|
|
||||||
import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector';
|
import { availableFieldMetadataItemsForSortFamilySelector } from '@/object-metadata/states/availableFieldMetadataItemsForSortFamilySelector';
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { OBJECT_SORT_DROPDOWN_ID } from '@/object-record/object-sort-dropdown/constants/ObjectSortDropdownId';
|
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 { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||||
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
|
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 { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||||
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
import { DropdownMenuSectionLabel } from '@/ui/layout/dropdown/components/DropdownMenuSectionLabel';
|
||||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
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 { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
import { useTheme } from '@emotion/react';
|
|
||||||
import { Trans, useLingui } from '@lingui/react/macro';
|
import { Trans, useLingui } from '@lingui/react/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
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 { MenuItem } from 'twenty-ui/navigation';
|
||||||
import { v4 } from 'uuid';
|
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 = () => {
|
export const ObjectSortDropdownButton = () => {
|
||||||
const { resetRecordSortDropdownSearchInput } =
|
const { resetRecordSortDropdownSearchInput } =
|
||||||
useResetRecordSortDropdownSearchInput();
|
useResetRecordSortDropdownSearchInput();
|
||||||
@ -88,10 +47,6 @@ export const ObjectSortDropdownButton = () => {
|
|||||||
objectSortDropdownSearchInputComponentState,
|
objectSortDropdownSearchInputComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isRecordSortDirectionMenuUnfolded = useRecoilComponentValueV2(
|
|
||||||
isRecordSortDirectionDropdownMenuUnfoldedComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { resetSortDropdown } = useResetSortDropdown();
|
const { resetSortDropdown } = useResetSortDropdown();
|
||||||
|
|
||||||
const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow();
|
const { recordIndexId, objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||||
@ -195,8 +150,6 @@ export const ObjectSortDropdownButton = () => {
|
|||||||
|
|
||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const selectableItemIdArray = [
|
const selectableItemIdArray = [
|
||||||
...visibleFieldMetadataItems.map((item) => item.id),
|
...visibleFieldMetadataItems.map((item) => item.id),
|
||||||
...hiddenFieldMetadataItems.map((item) => item.id),
|
...hiddenFieldMetadataItems.map((item) => item.id),
|
||||||
@ -227,51 +180,50 @@ export const ObjectSortDropdownButton = () => {
|
|||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||||
|
<DropdownMenuHeader
|
||||||
|
StartComponent={
|
||||||
|
<DropdownMenuHeaderLeftComponent
|
||||||
|
onClick={() => closeSortDropdown()}
|
||||||
|
Icon={IconX}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t`Sort`}
|
||||||
|
</DropdownMenuHeader>
|
||||||
|
<DropdownMenuInnerSelect
|
||||||
|
dropdownId="record-sort-direction-dropdown"
|
||||||
|
options={RECORD_SORT_DIRECTIONS.map((sortDirection) => ({
|
||||||
|
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}
|
||||||
|
/>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuSearchInput
|
||||||
|
autoFocus
|
||||||
|
value={objectSortDropdownSearchInput}
|
||||||
|
placeholder={t`Search fields`}
|
||||||
|
onChange={(event) =>
|
||||||
|
setObjectSortDropdownSearchInput(event.target.value)
|
||||||
|
}
|
||||||
|
/>
|
||||||
<SelectableList
|
<SelectableList
|
||||||
selectableListInstanceId={OBJECT_SORT_DROPDOWN_ID}
|
selectableListInstanceId={OBJECT_SORT_DROPDOWN_ID}
|
||||||
selectableItemIdArray={selectableItemIdArray}
|
selectableItemIdArray={selectableItemIdArray}
|
||||||
focusId={OBJECT_SORT_DROPDOWN_ID}
|
focusId={OBJECT_SORT_DROPDOWN_ID}
|
||||||
>
|
>
|
||||||
{isRecordSortDirectionMenuUnfolded && (
|
|
||||||
<StyledSelectedSortDirectionContainer>
|
|
||||||
<DropdownMenuItemsContainer>
|
|
||||||
{RECORD_SORT_DIRECTIONS.map((sortDirection, index) => (
|
|
||||||
<MenuItem
|
|
||||||
key={index}
|
|
||||||
focused={selectedItemId === sortDirection}
|
|
||||||
onClick={() => handleSortDirectionClick(sortDirection)}
|
|
||||||
text={
|
|
||||||
sortDirection === 'asc' ? t`Ascending` : t`Descending`
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</DropdownMenuItemsContainer>
|
|
||||||
</StyledSelectedSortDirectionContainer>
|
|
||||||
)}
|
|
||||||
<DropdownMenuHeader
|
|
||||||
onClick={() =>
|
|
||||||
setIsRecordSortDirectionMenuUnfolded(
|
|
||||||
!isRecordSortDirectionMenuUnfolded,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
EndComponent={
|
|
||||||
<StyledDropdownMenuHeaderEndComponent>
|
|
||||||
<IconChevronDown size={theme.icon.size.md} />
|
|
||||||
</StyledDropdownMenuHeaderEndComponent>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{selectedRecordSortDirection === 'asc'
|
|
||||||
? t`Ascending`
|
|
||||||
: t`Descending`}
|
|
||||||
</DropdownMenuHeader>
|
|
||||||
<StyledInput
|
|
||||||
autoFocus
|
|
||||||
value={objectSortDropdownSearchInput}
|
|
||||||
placeholder={t`Search fields`}
|
|
||||||
onChange={(event) =>
|
|
||||||
setObjectSortDropdownSearchInput(event.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
{shouldShowVisibleFields && (
|
{shouldShowVisibleFields && (
|
||||||
<>
|
<>
|
||||||
<DropdownMenuSectionLabel label={t`Visible fields`} />
|
<DropdownMenuSectionLabel label={t`Visible fields`} />
|
||||||
|
|||||||
@ -33,6 +33,7 @@ export type DropdownMenuInnerSelectProps = {
|
|||||||
onChange: (value: SelectOption) => void;
|
onChange: (value: SelectOption) => void;
|
||||||
options: SelectOption[];
|
options: SelectOption[];
|
||||||
dropdownId: string;
|
dropdownId: string;
|
||||||
|
widthInPixels?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DropdownMenuInnerSelect = ({
|
export const DropdownMenuInnerSelect = ({
|
||||||
@ -40,6 +41,7 @@ export const DropdownMenuInnerSelect = ({
|
|||||||
onChange,
|
onChange,
|
||||||
options,
|
options,
|
||||||
dropdownId,
|
dropdownId,
|
||||||
|
widthInPixels,
|
||||||
}: DropdownMenuInnerSelectProps) => {
|
}: DropdownMenuInnerSelectProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ export const DropdownMenuInnerSelect = ({
|
|||||||
</StyledDropdownMenuInnerSelectDropdownButton>
|
</StyledDropdownMenuInnerSelectDropdownButton>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<DropdownContent>
|
<DropdownContent widthInPixels={widthInPixels}>
|
||||||
<DropdownMenuItemsContainer>
|
<DropdownMenuItemsContainer>
|
||||||
{options.map((selectOption) => (
|
{options.map((selectOption) => (
|
||||||
<MenuItemSelect
|
<MenuItemSelect
|
||||||
|
|||||||
@ -0,0 +1,21 @@
|
|||||||
|
import { ObjectFilterDropdownContentWrapper } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper';
|
||||||
|
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
||||||
|
import { EditableFilterChipDropdownMenuHeader } from '@/views/components/EditableFilterChipDropdownMenuHeader';
|
||||||
|
|
||||||
|
type EditableFilterChipDropdownContentProps = {
|
||||||
|
recordFilterId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditableFilterChipDropdownContent = ({
|
||||||
|
recordFilterId,
|
||||||
|
}: EditableFilterChipDropdownContentProps) => {
|
||||||
|
return (
|
||||||
|
<ObjectFilterDropdownContentWrapper>
|
||||||
|
<EditableFilterChipDropdownMenuHeader />
|
||||||
|
<ObjectFilterDropdownFilterInput
|
||||||
|
filterDropdownId={recordFilterId}
|
||||||
|
recordFilterId={recordFilterId}
|
||||||
|
/>
|
||||||
|
</ObjectFilterDropdownContentWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -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 (
|
||||||
|
<DropdownMenuHeader
|
||||||
|
StartComponent={
|
||||||
|
<DropdownMenuHeaderLeftComponent
|
||||||
|
onClick={handleBackButtonClick}
|
||||||
|
Icon={IconX}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{isVectorSearchFilter
|
||||||
|
? t`Search`
|
||||||
|
: fieldMetadataItemUsedInDropdown?.label}
|
||||||
|
</DropdownMenuHeader>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -4,10 +4,11 @@ import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
|||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
|
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 { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||||
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
||||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
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';
|
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
|
||||||
|
|
||||||
type EditableFilterDropdownButtonProps = {
|
type EditableFilterDropdownButtonProps = {
|
||||||
@ -29,13 +30,17 @@ export const EditableFilterDropdownButton = ({
|
|||||||
removeRecordFilter({ recordFilterId: recordFilter.id });
|
removeRecordFilter({ recordFilterId: recordFilter.id });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { clearVectorSearchInput } = useClearVectorSearchInput();
|
||||||
|
|
||||||
const onFilterDropdownClose = useCallback(() => {
|
const onFilterDropdownClose = useCallback(() => {
|
||||||
const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter);
|
const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter);
|
||||||
|
|
||||||
if (recordFilterIsEmpty) {
|
if (recordFilterIsEmpty) {
|
||||||
removeRecordFilter({ recordFilterId: recordFilter.id });
|
removeRecordFilter({ recordFilterId: recordFilter.id });
|
||||||
}
|
}
|
||||||
}, [recordFilter, removeRecordFilter]);
|
|
||||||
|
clearVectorSearchInput();
|
||||||
|
}, [recordFilter, removeRecordFilter, clearVectorSearchInput]);
|
||||||
|
|
||||||
const { setEditableFilterChipDropdownStates } =
|
const { setEditableFilterChipDropdownStates } =
|
||||||
useSetEditableFilterChipDropdownStates();
|
useSetEditableFilterChipDropdownStates();
|
||||||
@ -56,7 +61,7 @@ export const EditableFilterDropdownButton = ({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<ObjectFilterDropdownFilterInput filterDropdownId={recordFilter.id} />
|
<EditableFilterChipDropdownContent recordFilterId={recordFilter.id} />
|
||||||
}
|
}
|
||||||
dropdownOffset={{ y: 8, x: 0 }}
|
dropdownOffset={{ y: 8, x: 0 }}
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRe
|
|||||||
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent';
|
import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent';
|
||||||
|
import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput';
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { ViewBarFilterButton } from './ViewBarFilterButton';
|
import { ViewBarFilterButton } from './ViewBarFilterButton';
|
||||||
|
|
||||||
@ -20,6 +21,8 @@ export const ViewBarFilterDropdown = () => {
|
|||||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { clearVectorSearchInput } = useClearVectorSearchInput();
|
||||||
|
|
||||||
const handleDropdownClickOutside = () => {
|
const handleDropdownClickOutside = () => {
|
||||||
const recordFilterIsEmpty =
|
const recordFilterIsEmpty =
|
||||||
isDefined(objectFilterDropdownCurrentRecordFilter) &&
|
isDefined(objectFilterDropdownCurrentRecordFilter) &&
|
||||||
@ -37,6 +40,7 @@ export const ViewBarFilterDropdown = () => {
|
|||||||
const handleDropdownClose = () => {
|
const handleDropdownClose = () => {
|
||||||
resetFilterDropdown();
|
resetFilterDropdown();
|
||||||
removeEmptyVectorSearchFilter();
|
removeEmptyVectorSearchFilter();
|
||||||
|
clearVectorSearchInput();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDropdownOpen = () => {
|
const handleDropdownOpen = () => {
|
||||||
|
|||||||
@ -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 { 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 { 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 { 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 { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||||
|
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||||
|
|
||||||
export const ViewBarFilterDropdownContent = () => {
|
export const ViewBarFilterDropdownContent = () => {
|
||||||
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
||||||
@ -10,14 +14,23 @@ export const ViewBarFilterDropdownContent = () => {
|
|||||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||||
|
selectedOperandInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isVectorSearchFilter =
|
||||||
|
selectedOperandInDropdown === ViewFilterOperand.VectorSearch;
|
||||||
|
|
||||||
|
if (isVectorSearchFilter) {
|
||||||
|
return <ViewBarFilterDropdownVectorSearchInput />;
|
||||||
|
}
|
||||||
|
|
||||||
const shouldShowFilterInput = objectFilterDropdownFilterIsSelected;
|
const shouldShowFilterInput = objectFilterDropdownFilterIsSelected;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{shouldShowFilterInput ? (
|
{shouldShowFilterInput ? (
|
||||||
<ObjectFilterDropdownFilterInput
|
<ViewBarFilterDropdownFilterInput />
|
||||||
filterDropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<ViewBarFilterDropdownFieldSelectMenu />
|
<ViewBarFilterDropdownFieldSelectMenu />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -16,10 +16,14 @@ import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/
|
|||||||
import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu';
|
import { ViewBarFilterDropdownBottomMenu } from '@/views/components/ViewBarFilterDropdownBottomMenu';
|
||||||
import { ViewBarFilterDropdownFieldSelectMenuItem } from '@/views/components/ViewBarFilterDropdownFieldSelectMenuItem';
|
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 { 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_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds';
|
||||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
|
import { IconX } from 'twenty-ui/display';
|
||||||
|
|
||||||
export const StyledInput = styled.input`
|
export const StyledInput = styled.input`
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -56,6 +60,8 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
|||||||
selectableVisibleFieldMetadataItems,
|
selectableVisibleFieldMetadataItems,
|
||||||
} = useFilterDropdownSelectableFieldMetadataItems();
|
} = useFilterDropdownSelectableFieldMetadataItems();
|
||||||
|
|
||||||
|
const { closeDropdown } = useCloseDropdown();
|
||||||
|
|
||||||
const selectableFieldMetadataItemIds = [
|
const selectableFieldMetadataItemIds = [
|
||||||
...selectableVisibleFieldMetadataItems.map(
|
...selectableVisibleFieldMetadataItems.map(
|
||||||
(fieldMetadataItem) => fieldMetadataItem.id,
|
(fieldMetadataItem) => fieldMetadataItem.id,
|
||||||
@ -83,6 +89,16 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||||
|
<DropdownMenuHeader
|
||||||
|
StartComponent={
|
||||||
|
<DropdownMenuHeaderLeftComponent
|
||||||
|
onClick={() => closeDropdown()}
|
||||||
|
Icon={IconX}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t`Filter`}
|
||||||
|
</DropdownMenuHeader>
|
||||||
<StyledInput
|
<StyledInput
|
||||||
value={objectFilterDropdownSearchInput}
|
value={objectFilterDropdownSearchInput}
|
||||||
autoFocus
|
autoFocus
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { ObjectFilterDropdownContentWrapper } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownContentWrapper';
|
||||||
|
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
||||||
|
import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader';
|
||||||
|
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||||
|
|
||||||
|
type ViewBarFilterDropdownFilterInputProps = {
|
||||||
|
recordFilterId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ViewBarFilterDropdownFilterInput = ({
|
||||||
|
recordFilterId,
|
||||||
|
}: ViewBarFilterDropdownFilterInputProps) => {
|
||||||
|
return (
|
||||||
|
<ObjectFilterDropdownContentWrapper>
|
||||||
|
<ViewBarFilterDropdownFilterInputMenuHeader />
|
||||||
|
<ObjectFilterDropdownFilterInput
|
||||||
|
filterDropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||||
|
recordFilterId={recordFilterId}
|
||||||
|
/>
|
||||||
|
</ObjectFilterDropdownContentWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -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 (
|
||||||
|
<DropdownMenuHeader
|
||||||
|
StartComponent={
|
||||||
|
<DropdownMenuHeaderLeftComponent
|
||||||
|
onClick={handleBackButtonClick}
|
||||||
|
Icon={IconChevronLeft}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{isVectorSearchFilter
|
||||||
|
? t`Search`
|
||||||
|
: fieldMetadataItemUsedInDropdown?.label}
|
||||||
|
</DropdownMenuHeader>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -9,7 +9,6 @@ import { IconSearch } from 'twenty-ui/display';
|
|||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
|
||||||
import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds';
|
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 { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||||
import { useOpenVectorSearchFilter } from '@/views/hooks/useOpenVectorSearchFilter';
|
import { useOpenVectorSearchFilter } from '@/views/hooks/useOpenVectorSearchFilter';
|
||||||
@ -26,20 +25,16 @@ export const ViewBarFilterDropdownVectorSearchButton = () => {
|
|||||||
const { t } = useLingui();
|
const { t } = useLingui();
|
||||||
const [, setVectorSearchInputValue] = useRecoilComponentStateV2(
|
const [, setVectorSearchInputValue] = useRecoilComponentStateV2(
|
||||||
vectorSearchInputComponentState,
|
vectorSearchInputComponentState,
|
||||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
|
||||||
);
|
);
|
||||||
const { setVectorSearchInputValueFromExistingFilter } =
|
const { setVectorSearchInputValueFromExistingFilter } =
|
||||||
useSetVectorSearchInputValueFromExistingFilter(VIEW_BAR_FILTER_DROPDOWN_ID);
|
useSetVectorSearchInputValueFromExistingFilter();
|
||||||
|
|
||||||
const fieldSearchInputValue = useRecoilComponentValueV2(
|
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||||
objectFilterDropdownSearchInputComponentState,
|
objectFilterDropdownSearchInputComponentState,
|
||||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const { applyVectorSearchFilter } = useVectorSearchFilterActions();
|
const { applyVectorSearchFilter } = useVectorSearchFilterActions();
|
||||||
const { openVectorSearchFilter } = useOpenVectorSearchFilter(
|
const { openVectorSearchFilter } = useOpenVectorSearchFilter();
|
||||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
|
||||||
);
|
|
||||||
|
|
||||||
const isSelected = useRecoilComponentFamilyValueV2(
|
const isSelected = useRecoilComponentFamilyValueV2(
|
||||||
isSelectedItemIdComponentFamilySelector,
|
isSelectedItemIdComponentFamilySelector,
|
||||||
@ -49,9 +44,9 @@ export const ViewBarFilterDropdownVectorSearchButton = () => {
|
|||||||
const handleSearchClick = () => {
|
const handleSearchClick = () => {
|
||||||
openVectorSearchFilter();
|
openVectorSearchFilter();
|
||||||
|
|
||||||
if (fieldSearchInputValue.length > 0) {
|
if (objectFilterDropdownSearchInput.length > 0) {
|
||||||
setVectorSearchInputValue(fieldSearchInputValue);
|
setVectorSearchInputValue(objectFilterDropdownSearchInput);
|
||||||
applyVectorSearchFilter(fieldSearchInputValue);
|
applyVectorSearchFilter(objectFilterDropdownSearchInput);
|
||||||
} else {
|
} else {
|
||||||
setVectorSearchInputValueFromExistingFilter();
|
setVectorSearchInputValueFromExistingFilter();
|
||||||
}
|
}
|
||||||
@ -69,8 +64,8 @@ export const ViewBarFilterDropdownVectorSearchButton = () => {
|
|||||||
text={
|
text={
|
||||||
<>
|
<>
|
||||||
{t`Search`}
|
{t`Search`}
|
||||||
{fieldSearchInputValue && (
|
{objectFilterDropdownSearchInput && (
|
||||||
<StyledSearchText>{t`· ${fieldSearchInputValue}`}</StyledSearchText>
|
<StyledSearchText>{t`· ${objectFilterDropdownSearchInput}`}</StyledSearchText>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,47 +1,13 @@
|
|||||||
|
import { ObjectFilterDropdownVectorSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput';
|
||||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
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 { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||||
import { useRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentStateV2';
|
import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader';
|
||||||
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<HTMLInputElement>) => {
|
|
||||||
const inputValue = e.target.value;
|
|
||||||
setVectorSearchInputValue(inputValue);
|
|
||||||
debouncedApplyVectorSearchFilter(inputValue);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
export const ViewBarFilterDropdownVectorSearchInput = () => {
|
||||||
return (
|
return (
|
||||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||||
<DropdownMenuSearchInput
|
<ViewBarFilterDropdownFilterInputMenuHeader />
|
||||||
autoFocus
|
<ObjectFilterDropdownVectorSearchInput />
|
||||||
type="text"
|
|
||||||
value={vectorSearchInputValue}
|
|
||||||
placeholder={t`Search`}
|
|
||||||
onChange={handleSearchChange}
|
|
||||||
/>
|
|
||||||
</DropdownContent>
|
</DropdownContent>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -24,15 +24,6 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
|||||||
? filterableFieldMetadataItems.concat(vectorSearchField)
|
? filterableFieldMetadataItems.concat(vectorSearchField)
|
||||||
: filterableFieldMetadataItems;
|
: filterableFieldMetadataItems;
|
||||||
|
|
||||||
const fieldMetadataItem = filterableFieldsWithVector.find(
|
|
||||||
(fieldMetadataItem) =>
|
|
||||||
fieldMetadataItem.id === recordFilter.fieldMetadataId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!isDefined(fieldMetadataItem)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isVectorSearchFilter(recordFilter)) {
|
if (isVectorSearchFilter(recordFilter)) {
|
||||||
set(
|
set(
|
||||||
vectorSearchInputComponentState.atomFamily({
|
vectorSearchInputComponentState.atomFamily({
|
||||||
@ -42,13 +33,20 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(
|
const fieldMetadataItem = filterableFieldsWithVector.find(
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
(fieldMetadataItem) =>
|
||||||
instanceId: recordFilter.id,
|
fieldMetadataItem.id === recordFilter.fieldMetadataId,
|
||||||
}),
|
|
||||||
fieldMetadataItem.id,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isDefined(fieldMetadataItem)) {
|
||||||
|
set(
|
||||||
|
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||||
|
instanceId: recordFilter.id,
|
||||||
|
}),
|
||||||
|
fieldMetadataItem.id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
set(
|
set(
|
||||||
selectedOperandInDropdownComponentState.atomFamily({
|
selectedOperandInDropdownComponentState.atomFamily({
|
||||||
instanceId: recordFilter.id,
|
instanceId: recordFilter.id,
|
||||||
|
|||||||
@ -3,17 +3,15 @@ import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInpu
|
|||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { useVectorSearchFilterState } from './useVectorSearchFilterState';
|
import { useVectorSearchFilterState } from './useVectorSearchFilterState';
|
||||||
|
|
||||||
export const useSetVectorSearchInputValueFromExistingFilter = (
|
export const useSetVectorSearchInputValueFromExistingFilter = () => {
|
||||||
filterDropdownId: string,
|
|
||||||
) => {
|
|
||||||
const [, setVectorSearchInputValue] = useRecoilComponentStateV2(
|
const [, setVectorSearchInputValue] = useRecoilComponentStateV2(
|
||||||
vectorSearchInputComponentState,
|
vectorSearchInputComponentState,
|
||||||
filterDropdownId,
|
|
||||||
);
|
);
|
||||||
const { getExistingVectorSearchFilter } = useVectorSearchFilterState();
|
const { getExistingVectorSearchFilter } = useVectorSearchFilterState();
|
||||||
|
|
||||||
const setVectorSearchInputValueFromExistingFilter = () => {
|
const setVectorSearchInputValueFromExistingFilter = () => {
|
||||||
const existingVectorSearchFilter = getExistingVectorSearchFilter();
|
const existingVectorSearchFilter = getExistingVectorSearchFilter();
|
||||||
|
|
||||||
if (isDefined(existingVectorSearchFilter)) {
|
if (isDefined(existingVectorSearchFilter)) {
|
||||||
setVectorSearchInputValue(existingVectorSearchFilter.value);
|
setVectorSearchInputValue(existingVectorSearchFilter.value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||||
import { ViewComponentInstanceContext } from '@/views/states/contexts/ViewComponentInstanceContext';
|
|
||||||
|
|
||||||
export const vectorSearchInputComponentState = createComponentStateV2<string>({
|
export const vectorSearchInputComponentState = createComponentStateV2<string>({
|
||||||
key: 'vectorSearchInputComponentState',
|
key: 'vectorSearchInputComponentState',
|
||||||
defaultValue: '',
|
defaultValue: '',
|
||||||
componentInstanceContext: ViewComponentInstanceContext,
|
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user