Fix/close filter by enter (#16643)
Fixes #16636 Added useCloseDropdown() hook and set onEnter prop to onEnter={closeDropDown()} using dropdownID EDIT from @charlesBochet after refactoring: - ObjectDropdownFilters are used in 3 places: Main Filter menu, EditableChip, AdvancedFilters - deprecate vectorSearch in view filter area, we are not using them, we are doing a anyField filter now. While refactoring the points below, I did not want to maintain vectorSearch as it was not used anymore - stop confusing the dropdownId (which is an id to interact with a specific dropdown) and componentInstanceIds (which is used to scope component states) for EditableFilter case - I haven't fixed the confusion for MainFilter case - It was already handled for AdvancedFilter case --------- Co-authored-by: Charles Bochet <charles@twenty.com> Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
+3
-7
@@ -49,12 +49,8 @@ export const AdvancedFilterDropdownFilterInput = ({
|
||||
<AdvancedFilterDropdownTextInput recordFilter={recordFilter} />
|
||||
))}
|
||||
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||
{filterType === 'DATE_TIME' && (
|
||||
<ObjectFilterDropdownDateTimeInput instanceId={filterDropdownId} />
|
||||
)}
|
||||
{filterType === 'DATE' && (
|
||||
<ObjectFilterDropdownDateInput instanceId={filterDropdownId} />
|
||||
)}
|
||||
{filterType === 'DATE_TIME' && <ObjectFilterDropdownDateTimeInput />}
|
||||
{filterType === 'DATE' && <ObjectFilterDropdownDateInput />}
|
||||
{filterType === 'RELATION' && (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
@@ -69,7 +65,7 @@ export const AdvancedFilterDropdownFilterInput = ({
|
||||
(isActorSourceCompositeFilter ? (
|
||||
<ObjectFilterDropdownSourceSelect dropdownId={filterDropdownId} />
|
||||
) : (
|
||||
<ObjectFilterDropdownTextInput />
|
||||
<ObjectFilterDropdownTextInput filterDropdownId={filterDropdownId} />
|
||||
))}
|
||||
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
|
||||
+2
-8
@@ -21,13 +21,7 @@ import {
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { formatDateString } from '~/utils/string/formatDateString';
|
||||
|
||||
type ObjectFilterDropdownDateInputProps = {
|
||||
instanceId: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownDateInput = ({
|
||||
instanceId,
|
||||
}: ObjectFilterDropdownDateInputProps) => {
|
||||
export const ObjectFilterDropdownDateInput = () => {
|
||||
const { dateFormat, timeZone } = useContext(UserContext);
|
||||
const dateLocale = useRecoilValue(dateLocaleState);
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
@@ -112,7 +106,7 @@ export const ObjectFilterDropdownDateInput = ({
|
||||
|
||||
return (
|
||||
<DatePicker
|
||||
instanceId={instanceId}
|
||||
instanceId={`object-filter-dropdown-date-input`}
|
||||
relativeDate={relativeDate}
|
||||
isRelative={isRelativeOperand}
|
||||
date={plainDateValue ?? null}
|
||||
|
||||
+2
-8
@@ -21,13 +21,7 @@ import {
|
||||
import { dateLocaleState } from '~/localization/states/dateLocaleState';
|
||||
import { formatDateTimeString } from '~/utils/string/formatDateTimeString';
|
||||
|
||||
type ObjectFilterDropdownDateTimeInputProps = {
|
||||
instanceId: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownDateTimeInput = ({
|
||||
instanceId,
|
||||
}: ObjectFilterDropdownDateTimeInputProps) => {
|
||||
export const ObjectFilterDropdownDateTimeInput = () => {
|
||||
const { dateFormat, timeFormat, timeZone } = useContext(UserContext);
|
||||
const dateLocale = useRecoilValue(dateLocaleState);
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
@@ -115,7 +109,7 @@ export const ObjectFilterDropdownDateTimeInput = ({
|
||||
|
||||
return (
|
||||
<DateTimePicker
|
||||
instanceId={instanceId}
|
||||
instanceId={`object-filter-dropdown-date-time-input`}
|
||||
relativeDate={relativeDate}
|
||||
isRelative={isRelativeOperand}
|
||||
date={internalDate}
|
||||
|
||||
+17
-17
@@ -12,7 +12,6 @@ import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter
|
||||
import { ObjectFilterDropdownDateTimeInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateTimeInput';
|
||||
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 { 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';
|
||||
@@ -31,12 +30,10 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
}: ObjectFilterDropdownFilterInputProps) => {
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
filterDropdownId,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
selectedOperandInDropdownComponentState,
|
||||
filterDropdownId,
|
||||
);
|
||||
|
||||
const isOperandWithFilterValue =
|
||||
@@ -54,13 +51,6 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
ViewFilterOperand.IS_RELATIVE,
|
||||
].includes(selectedOperandInDropdown);
|
||||
|
||||
const isVectorSearchFilter =
|
||||
selectedOperandInDropdown === ViewFilterOperand.VECTOR_SEARCH;
|
||||
|
||||
if (isVectorSearchFilter && isDefined(filterDropdownId)) {
|
||||
return <ObjectFilterDropdownVectorSearchInput />;
|
||||
}
|
||||
|
||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||
return null;
|
||||
}
|
||||
@@ -82,7 +72,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
<>
|
||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownDateInput instanceId={filterDropdownId} />
|
||||
<ObjectFilterDropdownDateInput />
|
||||
</>
|
||||
);
|
||||
} else if (filterType === 'DATE_TIME') {
|
||||
@@ -90,7 +80,7 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
<>
|
||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||
<DropdownMenuSeparator />
|
||||
<ObjectFilterDropdownDateTimeInput instanceId={filterDropdownId} />
|
||||
<ObjectFilterDropdownDateTimeInput />
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
@@ -99,10 +89,12 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
<ObjectFilterDropdownInnerSelectOperandDropdown />
|
||||
<DropdownMenuSeparator />
|
||||
{TEXT_FILTER_TYPES.includes(filterType) && (
|
||||
<ObjectFilterDropdownTextInput />
|
||||
<ObjectFilterDropdownTextInput filterDropdownId={filterDropdownId} />
|
||||
)}
|
||||
{NUMBER_FILTER_TYPES.includes(filterType) && (
|
||||
<ObjectFilterDropdownNumberInput />
|
||||
<ObjectFilterDropdownNumberInput
|
||||
filterDropdownId={filterDropdownId}
|
||||
/>
|
||||
)}
|
||||
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||
{filterType === 'RELATION' && (
|
||||
@@ -115,9 +107,17 @@ export const ObjectFilterDropdownFilterInput = ({
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{filterType === 'ACTOR' && <ObjectFilterDropdownTextInput />}
|
||||
{filterType === 'ADDRESS' && <ObjectFilterDropdownTextInput />}
|
||||
{filterType === 'CURRENCY' && <ObjectFilterDropdownNumberInput />}
|
||||
{filterType === 'ACTOR' && (
|
||||
<ObjectFilterDropdownTextInput filterDropdownId={filterDropdownId} />
|
||||
)}
|
||||
{filterType === 'ADDRESS' && (
|
||||
<ObjectFilterDropdownTextInput filterDropdownId={filterDropdownId} />
|
||||
)}
|
||||
{filterType === 'CURRENCY' && (
|
||||
<ObjectFilterDropdownNumberInput
|
||||
filterDropdownId={filterDropdownId}
|
||||
/>
|
||||
)}
|
||||
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||
<>
|
||||
<ObjectFilterDropdownSearchInput />
|
||||
|
||||
+4
-17
@@ -1,28 +1,20 @@
|
||||
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 { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useContext } from 'react';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { IconX } from 'twenty-ui/display';
|
||||
|
||||
// TODO: we shouldn't guess in which parent we are, this should be splitted in two components, one for each case
|
||||
export const ObjectFilterDropdownFilterInputHeader = () => {
|
||||
const { t } = useLingui();
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const dropdownInstanceId = useContext(
|
||||
@@ -30,10 +22,7 @@ export const ObjectFilterDropdownFilterInputHeader = () => {
|
||||
)?.instanceId;
|
||||
|
||||
const isInViewBarFilterDropdown =
|
||||
dropdownInstanceId === VIEW_BAR_FILTER_DROPDOWN_ID;
|
||||
|
||||
const isVectorSearchFilter =
|
||||
selectedOperandInDropdown === ViewFilterOperand.VECTOR_SEARCH;
|
||||
dropdownInstanceId === ViewBarFilterDropdownIds.MAIN;
|
||||
|
||||
if (isInViewBarFilterDropdown) {
|
||||
return <ViewBarFilterDropdownFilterInputMenuHeader />;
|
||||
@@ -47,9 +36,7 @@ export const ObjectFilterDropdownFilterInputHeader = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
{isVectorSearchFilter
|
||||
? t`Search`
|
||||
: fieldMetadataItemUsedInDropdown?.label}
|
||||
{fieldMetadataItemUsedInDropdown?.label}
|
||||
</DropdownMenuHeader>
|
||||
);
|
||||
}
|
||||
|
||||
+12
-2
@@ -5,9 +5,16 @@ import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filte
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
|
||||
export const ObjectFilterDropdownNumberInput = () => {
|
||||
type ObjectFilterDropdownNumberInputProps = {
|
||||
filterDropdownId: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownNumberInput = ({
|
||||
filterDropdownId,
|
||||
}: ObjectFilterDropdownNumberInputProps) => {
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
@@ -18,6 +25,8 @@ export const ObjectFilterDropdownNumberInput = () => {
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const [hasFocused, setHasFocused] = useState(false);
|
||||
|
||||
const handleInputRef = useCallback(
|
||||
@@ -40,13 +49,14 @@ export const ObjectFilterDropdownNumberInput = () => {
|
||||
return (
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuInput
|
||||
instanceId="object-filter-dropdown-number-input"
|
||||
instanceId={filterDropdownId}
|
||||
ref={handleInputRef}
|
||||
value={objectFilterDropdownFilterValue}
|
||||
autoFocus
|
||||
type="number"
|
||||
placeholder={fieldMetadataItemUsedInDropdown?.label}
|
||||
onChange={handleInputChange}
|
||||
onEnter={() => closeDropdown(filterDropdownId)}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
);
|
||||
|
||||
+14
-2
@@ -5,9 +5,16 @@ import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filte
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
|
||||
export const ObjectFilterDropdownTextInput = () => {
|
||||
type ObjectFilterDropdownTextInputProps = {
|
||||
filterDropdownId: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownTextInput = ({
|
||||
filterDropdownId,
|
||||
}: ObjectFilterDropdownTextInputProps) => {
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
@@ -18,6 +25,8 @@ export const ObjectFilterDropdownTextInput = () => {
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const [hasFocused, setHasFocused] = useState(false);
|
||||
|
||||
const handleInputRef = useCallback(
|
||||
@@ -40,13 +49,16 @@ export const ObjectFilterDropdownTextInput = () => {
|
||||
return (
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuInput
|
||||
instanceId="object-filter-dropdown-text-input"
|
||||
instanceId={filterDropdownId}
|
||||
ref={handleInputRef}
|
||||
value={objectFilterDropdownFilterValue ?? ''}
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder={fieldMetadataItemUsedInDropdown?.label}
|
||||
onChange={handleInputChange}
|
||||
onEnter={() => {
|
||||
closeDropdown(filterDropdownId);
|
||||
}}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
);
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
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] =
|
||||
useRecoilComponentState(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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
+2
-2
@@ -17,7 +17,7 @@ import { RecordCalendarMonth } from '@/object-record/record-calendar/month/compo
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { ComponentDecorator, RouterDecorator } from 'twenty-ui/testing';
|
||||
@@ -101,7 +101,7 @@ const meta: Meta<typeof RecordCalendarMonth> = {
|
||||
componentInstanceId={instanceId}
|
||||
>
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
value={{ instanceId: ViewBarFilterDropdownIds.MAIN }}
|
||||
>
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{
|
||||
|
||||
+6
-10
@@ -5,19 +5,18 @@ import {
|
||||
MultiItemBaseInput,
|
||||
type MultiItemBaseInputProps,
|
||||
} from '@/object-record/record-field/ui/meta-types/input/components/MultiItemBaseInput';
|
||||
import { MULTI_ITEM_FIELD_INPUT_DROPDOWN_ID_PREFIX } from '@/object-record/record-field/ui/meta-types/input/constants/MultiItemFieldInputDropdownClickOutsideId';
|
||||
import { RecordFieldComponentInstanceContext } from '@/object-record/record-field/ui/states/contexts/RecordFieldComponentInstanceContext';
|
||||
import { type PhoneRecord } from '@/object-record/record-field/ui/types/FieldMetadata';
|
||||
import { PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID } from '@/ui/input/components/internal/phone/constants/PhoneCountryCodePickerDropdownId';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { activeDropdownFocusIdState } from '@/ui/layout/dropdown/states/activeDropdownFocusIdState';
|
||||
import { currentFocusedItemSelector } from '@/ui/utilities/focus/states/currentFocusedItemSelector';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useHotkeysOnFocusedElement } from '@/ui/utilities/hotkey/hooks/useHotkeysOnFocusedElement';
|
||||
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { CustomError, isDefined } from 'twenty-shared/utils';
|
||||
import { CustomError } from 'twenty-shared/utils';
|
||||
import { IconCheck, IconPlus } from 'twenty-ui/display';
|
||||
import { LightIconButton } from 'twenty-ui/input';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
@@ -73,17 +72,14 @@ export const MultiItemFieldInput = <T,>({
|
||||
RecordFieldComponentInstanceContext,
|
||||
);
|
||||
|
||||
const activeDropdownFocusId = useRecoilValue(activeDropdownFocusIdState);
|
||||
const currentFocusedItem = useRecoilValue(currentFocusedItemSelector);
|
||||
|
||||
useListenClickOutside({
|
||||
refs: [containerRef],
|
||||
callback: (event) => {
|
||||
if (
|
||||
(isDefined(activeDropdownFocusId) &&
|
||||
activeDropdownFocusId.startsWith(
|
||||
MULTI_ITEM_FIELD_INPUT_DROPDOWN_ID_PREFIX,
|
||||
)) ||
|
||||
activeDropdownFocusId === PHONE_COUNTRY_CODE_PICKER_DROPDOWN_ID
|
||||
currentFocusedItem?.componentInstance.componentType !==
|
||||
FocusComponentType.OPENED_FIELD_INPUT
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
-12
@@ -2,9 +2,6 @@ import { AdvancedFilterContext } from '@/object-record/advanced-filter/states/co
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { getSnapshotValue } from '@/ui/utilities/state/utils/getSnapshotValue';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState';
|
||||
import { isVectorSearchFilter } from '@/views/utils/isVectorSearchFilter';
|
||||
import { useContext } from 'react';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -32,15 +29,6 @@ export const useRemoveRecordFilter = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVectorSearchFilter(filterToRemove)) {
|
||||
set(
|
||||
vectorSearchInputComponentState.atomFamily({
|
||||
instanceId: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
}),
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
set(currentRecordFiltersCallbackState, (currentRecordFilters) => {
|
||||
const newCurrentRecordFilters = [...currentRecordFilters];
|
||||
|
||||
|
||||
+9
-3
@@ -4,6 +4,7 @@ import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUp
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { getEditableChipDropdownId } from '@/views/editable-chip/utils/getEditableChipDropdownId';
|
||||
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -46,8 +47,9 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
if (isDefined(existingNonAdvancedRecordFilter)) {
|
||||
setEditableFilterChipDropdownStates(existingNonAdvancedRecordFilter);
|
||||
openDropdown({
|
||||
dropdownComponentInstanceIdFromProps:
|
||||
existingNonAdvancedRecordFilter.id,
|
||||
dropdownComponentInstanceIdFromProps: getEditableChipDropdownId({
|
||||
recordFilterId: existingNonAdvancedRecordFilter.id,
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -59,7 +61,11 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
upsertRecordFilter(newRecordFilter);
|
||||
|
||||
setEditableFilterChipDropdownStates(newRecordFilter);
|
||||
openDropdown({ dropdownComponentInstanceIdFromProps: newRecordFilter.id });
|
||||
openDropdown({
|
||||
dropdownComponentInstanceIdFromProps: getEditableChipDropdownId({
|
||||
recordFilterId: newRecordFilter.id,
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
||||
return { openRecordFilterChipFromTableHeader };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SEARCH_VECTOR_FIELD_NAME } from '@/views/constants/ViewFieldConstants';
|
||||
import { SEARCH_VECTOR_FIELD_NAME } from '@/object-record/constants/SearchVectorFieldName';
|
||||
|
||||
export const isSystemSearchVectorField = (fieldName: string): boolean => {
|
||||
return fieldName === SEARCH_VECTOR_FIELD_NAME;
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ import { getAllRecordFilterDescendantsOfRecordFilterGroup } from '@/object-recor
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { plural } from '@lingui/core/macro';
|
||||
import { useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -49,7 +49,7 @@ export const AdvancedFilterChip = () => {
|
||||
});
|
||||
|
||||
const handleRemoveClick = () => {
|
||||
closeDropdown(ADVANCED_FILTER_DROPDOWN_ID);
|
||||
closeDropdown(ViewBarFilterDropdownIds.ADVANCED);
|
||||
|
||||
const viewFilterGroupIds = currentRecordFilterGroups.map(
|
||||
(recordFilterGroup) => recordFilterGroup.id,
|
||||
@@ -109,7 +109,7 @@ export const AdvancedFilterChip = () => {
|
||||
|
||||
return (
|
||||
<SortOrFilterChip
|
||||
testId={ADVANCED_FILTER_DROPDOWN_ID}
|
||||
testId={ViewBarFilterDropdownIds.ADVANCED}
|
||||
labelKey={chipLabel}
|
||||
labelValue=""
|
||||
Icon={IconFilter}
|
||||
+3
-3
@@ -4,8 +4,8 @@ import { AdvancedFilterRootRecordFilterGroup } from '@/object-record/advanced-fi
|
||||
import { useSetAdvancedFilterDropdownStates } from '@/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates';
|
||||
import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { AdvancedFilterChip } from '@/views/components/AdvancedFilterChip';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { AdvancedFilterChip } from '@/views/advanced-filter-chip/components/AdvancedFilterChip';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const AdvancedFilterDropdownButton = () => {
|
||||
@@ -26,7 +26,7 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={ADVANCED_FILTER_DROPDOWN_ID}
|
||||
dropdownId={ViewBarFilterDropdownIds.ADVANCED}
|
||||
clickableComponent={<AdvancedFilterChip />}
|
||||
dropdownComponents={<AdvancedFilterRootRecordFilterGroup />}
|
||||
dropdownOffset={{ y: 8, x: 0 }}
|
||||
@@ -2,7 +2,7 @@ import { anyFieldFilterValueComponentState } from '@/object-record/record-filter
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { IconFilter } from 'twenty-ui/display';
|
||||
|
||||
@@ -22,7 +22,7 @@ export const AnyFieldSearchChip = () => {
|
||||
|
||||
return (
|
||||
<SortOrFilterChip
|
||||
testId={ADVANCED_FILTER_DROPDOWN_ID}
|
||||
testId={ViewBarFilterDropdownIds.ADVANCED}
|
||||
labelKey={t`Any field`}
|
||||
labelValue={`: ${anyFieldFilterValue}`}
|
||||
Icon={IconFilter}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { ViewBarRecordFieldEffect } from '@/views/components/ViewBarRecordFieldE
|
||||
import { ViewBarRecordFilterEffect } from '@/views/components/ViewBarRecordFilterEffect';
|
||||
import { ViewBarRecordFilterGroupEffect } from '@/views/components/ViewBarRecordFilterGroupEffect';
|
||||
import { ViewBarRecordSortEffect } from '@/views/components/ViewBarRecordSortEffect';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { UpdateViewButtonGroup } from './UpdateViewButtonGroup';
|
||||
import { ViewBarDetails } from './ViewBarDetails';
|
||||
|
||||
@@ -63,7 +63,7 @@ export const ViewBar = ({
|
||||
rightComponent={
|
||||
<>
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
value={{ instanceId: ViewBarFilterDropdownIds.MAIN }}
|
||||
>
|
||||
<ViewBarFilterDropdown />
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
|
||||
@@ -5,10 +5,9 @@ import { useObjectNameSingularFromPlural } from '@/object-metadata/hooks/useObje
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { useHandleToggleTrashColumnFilter } from '@/object-record/record-index/hooks/useHandleToggleTrashColumnFilter';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { AdvancedFilterDropdownButton } from '@/views/components/AdvancedFilterDropdownButton';
|
||||
import { EditableFilterDropdownButton } from '@/views/components/EditableFilterDropdownButton';
|
||||
import { EditableSortChip } from '@/views/components/EditableSortChip';
|
||||
import { AdvancedFilterDropdownButton } from '@/views/advanced-filter-chip/components/AdvancedFilterDropdownButton';
|
||||
import { ViewBarDetailsAddFilterButton } from '@/views/components/ViewBarDetailsAddFilterButton';
|
||||
import { EditableSortChip } from '@/views/editable-chip/components/EditableSortChip';
|
||||
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { currentRecordSortsComponentState } from '@/object-record/record-sort/states/currentRecordSortsComponentState';
|
||||
@@ -25,6 +24,8 @@ import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDrop
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { AnyFieldSearchDropdownButton } from '@/views/components/AnyFieldSearchDropdownButton';
|
||||
import { ANY_FIELD_SEARCH_DROPDOWN_ID } from '@/views/constants/AnyFieldSearchDropdownId';
|
||||
import { EditableFilterDropdownButton } from '@/views/editable-chip/components/EditableFilterDropdownButton';
|
||||
import { getEditableChipObjectFilterDropdownComponentInstanceId } from '@/views/editable-chip/utils/getEditableChipObjectFilterDropdownComponentInstanceId';
|
||||
import { useHasFiltersInQueryParams } from '@/views/hooks/internal/useHasFiltersInQueryParams';
|
||||
import { useApplyCurrentViewAnyFieldFilterToAnyFieldFilter } from '@/views/hooks/useApplyCurrentViewAnyFieldFilterToAnyFieldFilter';
|
||||
import { useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups } from '@/views/hooks/useApplyCurrentViewFilterGroupsToCurrentRecordFilterGroups';
|
||||
@@ -253,7 +254,12 @@ export const ViewBarDetails = ({
|
||||
{recordFilters.map((recordFilter) => (
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
key={recordFilter.id}
|
||||
value={{ instanceId: recordFilter.id }}
|
||||
value={{
|
||||
instanceId:
|
||||
getEditableChipObjectFilterDropdownComponentInstanceId({
|
||||
recordFilterId: recordFilter.id,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<EditableFilterDropdownButton recordFilter={recordFilter} />
|
||||
</ObjectFilterDropdownComponentInstanceContext.Provider>
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
|
||||
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
|
||||
import { useToggleDropdown } from '@/ui/layout/dropdown/hooks/useToggleDropdown';
|
||||
@@ -10,13 +10,13 @@ export const ViewBarDetailsAddFilterButton = () => {
|
||||
const { toggleDropdown } = useToggleDropdown();
|
||||
|
||||
const { resetFilterDropdown } = useResetFilterDropdown(
|
||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
ViewBarFilterDropdownIds.MAIN,
|
||||
);
|
||||
|
||||
const handleClick = () => {
|
||||
resetFilterDropdown();
|
||||
toggleDropdown({
|
||||
dropdownComponentInstanceIdFromProps: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
dropdownComponentInstanceIdFromProps: ViewBarFilterDropdownIds.MAIN,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { StyledHeaderDropdownButton } from '@/ui/layout/dropdown/components/StyledHeaderDropdownButton';
|
||||
import { isDropdownOpenComponentState } from '@/ui/layout/dropdown/states/isDropdownOpenComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { Trans } from '@lingui/react/macro';
|
||||
|
||||
export const ViewBarFilterButton = () => {
|
||||
const isDropdownOpen = useRecoilComponentValue(
|
||||
isDropdownOpenComponentState,
|
||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
ViewBarFilterDropdownIds.MAIN,
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
import { useResetFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useResetFilterDropdown';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { ViewBarFilterDropdownContent } from '@/views/components/ViewBarFilterDropdownContent';
|
||||
import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { ViewBarFilterButton } from './ViewBarFilterButton';
|
||||
|
||||
export const ViewBarFilterDropdown = () => {
|
||||
const { resetFilterDropdown } = useResetFilterDropdown();
|
||||
const { removeEmptyVectorSearchFilter } = useVectorSearchFilterActions();
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValue(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const { clearVectorSearchInput } = useClearVectorSearchInput();
|
||||
|
||||
const handleDropdownClickOutside = () => {
|
||||
const recordFilterIsEmpty =
|
||||
isDefined(objectFilterDropdownCurrentRecordFilter) &&
|
||||
@@ -33,14 +28,10 @@ export const ViewBarFilterDropdown = () => {
|
||||
recordFilterId: objectFilterDropdownCurrentRecordFilter.id,
|
||||
});
|
||||
}
|
||||
|
||||
removeEmptyVectorSearchFilter();
|
||||
};
|
||||
|
||||
const handleDropdownClose = () => {
|
||||
resetFilterDropdown();
|
||||
removeEmptyVectorSearchFilter();
|
||||
clearVectorSearchInput();
|
||||
};
|
||||
|
||||
const handleDropdownOpen = () => {
|
||||
@@ -49,7 +40,7 @@ export const ViewBarFilterDropdown = () => {
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
dropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||
dropdownId={ViewBarFilterDropdownIds.MAIN}
|
||||
onClose={handleDropdownClose}
|
||||
onOpen={handleDropdownOpen}
|
||||
clickableComponent={<ViewBarFilterButton />}
|
||||
|
||||
+3
-4
@@ -7,14 +7,13 @@ import { SelectableListItem } from '@/ui/layout/selectable-list/components/Selec
|
||||
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
|
||||
import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue';
|
||||
import { VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS } from '@/views/constants/ViewBarFilterBottomMenuItemIds';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
|
||||
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
|
||||
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
|
||||
import { useCloseDropdown } from '@/ui/layout/dropdown/hooks/useCloseDropdown';
|
||||
import { useOpenDropdown } from '@/ui/layout/dropdown/hooks/useOpenDropdown';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
@@ -115,9 +114,9 @@ export const ViewBarFilterDropdownAdvancedFilterButton = () => {
|
||||
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
|
||||
}
|
||||
|
||||
closeObjectFilterDropdown(VIEW_BAR_FILTER_DROPDOWN_ID);
|
||||
closeObjectFilterDropdown(ViewBarFilterDropdownIds.MAIN);
|
||||
openAdvancedFilterDropdown({
|
||||
dropdownComponentInstanceIdFromProps: ADVANCED_FILTER_DROPDOWN_ID,
|
||||
dropdownComponentInstanceIdFromProps: ViewBarFilterDropdownIds.ADVANCED,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
+2
-16
@@ -1,42 +1,28 @@
|
||||
import { objectFilterDropdownAnyFieldSearchIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownAnyFieldSearchIsSelectedComponentState';
|
||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { ViewBarFilterDropdownAnyFieldSearchInput } from '@/views/components/ViewBarFilterDropdownAnyFieldSearchInput';
|
||||
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';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
|
||||
export const ViewBarFilterDropdownContent = () => {
|
||||
const [objectFilterDropdownFilterIsSelected] = useRecoilComponentState(
|
||||
objectFilterDropdownFilterIsSelectedComponentState,
|
||||
VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
ViewBarFilterDropdownIds.MAIN,
|
||||
);
|
||||
|
||||
const objectFilterDropdownAnyFieldSearchIsSelected = useRecoilComponentValue(
|
||||
objectFilterDropdownAnyFieldSearchIsSelectedComponentState,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const isVectorSearchFilter =
|
||||
selectedOperandInDropdown === ViewFilterOperand.VECTOR_SEARCH;
|
||||
|
||||
const isAnyFieldSearchFilter = objectFilterDropdownAnyFieldSearchIsSelected;
|
||||
|
||||
if (isAnyFieldSearchFilter) {
|
||||
return <ViewBarFilterDropdownAnyFieldSearchInput />;
|
||||
}
|
||||
|
||||
if (isVectorSearchFilter) {
|
||||
return <ViewBarFilterDropdownVectorSearchInput />;
|
||||
}
|
||||
|
||||
const shouldShowFilterInput = objectFilterDropdownFilterIsSelected;
|
||||
|
||||
return (
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components
|
||||
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 { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { IconX } from 'twenty-ui/display';
|
||||
|
||||
@@ -110,7 +110,7 @@ export const ViewBarFilterDropdownFieldSelectMenu = () => {
|
||||
<SelectableList
|
||||
selectableItemIdArray={selectableFieldMetadataItemIds}
|
||||
selectableListInstanceId={FILTER_FIELD_LIST_ID}
|
||||
focusId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||
focusId={ViewBarFilterDropdownIds.MAIN}
|
||||
>
|
||||
{shouldShowVisibleFields && (
|
||||
<>
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
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';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
|
||||
type ViewBarFilterDropdownFilterInputProps = {
|
||||
recordFilterId?: string;
|
||||
@@ -14,7 +14,7 @@ export const ViewBarFilterDropdownFilterInput = ({
|
||||
<ObjectFilterDropdownContentWrapper>
|
||||
<ViewBarFilterDropdownFilterInputMenuHeader />
|
||||
<ObjectFilterDropdownFilterInput
|
||||
filterDropdownId={VIEW_BAR_FILTER_DROPDOWN_ID}
|
||||
filterDropdownId={ViewBarFilterDropdownIds.MAIN}
|
||||
recordFilterId={recordFilterId}
|
||||
/>
|
||||
</ObjectFilterDropdownContentWrapper>
|
||||
|
||||
+1
-19
@@ -1,35 +1,19 @@
|
||||
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 { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
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 = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const isVectorSearchFilter =
|
||||
selectedOperandInDropdown === ViewFilterOperand.VECTOR_SEARCH;
|
||||
|
||||
const { clearVectorSearchInput } = useClearVectorSearchInput();
|
||||
|
||||
const { resetFilterDropdown } = useResetFilterDropdown();
|
||||
|
||||
const handleBackButtonClick = () => {
|
||||
resetFilterDropdown();
|
||||
clearVectorSearchInput();
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -41,9 +25,7 @@ export const ViewBarFilterDropdownFilterInputMenuHeader = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
{isVectorSearchFilter
|
||||
? t`Search`
|
||||
: fieldMetadataItemUsedInDropdown?.label}
|
||||
{fieldMetadataItemUsedInDropdown?.label}
|
||||
</DropdownMenuHeader>
|
||||
);
|
||||
};
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
import { SelectableListItem } from '@/ui/layout/selectable-list/components/SelectableListItem';
|
||||
import { isSelectedItemIdComponentFamilySelector } from '@/ui/layout/selectable-list/states/selectors/isSelectedItemIdComponentFamilySelector';
|
||||
import { useRecoilComponentFamilyValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentFamilyValue';
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import styled from '@emotion/styled';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
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 { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { useOpenVectorSearchFilter } from '@/views/hooks/useOpenVectorSearchFilter';
|
||||
import { useSetVectorSearchInputValueFromExistingFilter } from '@/views/hooks/useSetVectorSearchInputValueFromExistingFilter';
|
||||
import { useVectorSearchFilterActions } from '@/views/hooks/useVectorSearchFilterActions';
|
||||
import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState';
|
||||
|
||||
const StyledSearchText = styled.span`
|
||||
color: ${({ theme }) => theme.font.color.light};
|
||||
margin-left: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
export const ViewBarFilterDropdownVectorSearchButton = () => {
|
||||
const { t } = useLingui();
|
||||
const [, setVectorSearchInputValue] = useRecoilComponentState(
|
||||
vectorSearchInputComponentState,
|
||||
);
|
||||
const { setVectorSearchInputValueFromExistingFilter } =
|
||||
useSetVectorSearchInputValueFromExistingFilter();
|
||||
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValue(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const { applyVectorSearchFilter } = useVectorSearchFilterActions();
|
||||
const { openVectorSearchFilter } = useOpenVectorSearchFilter();
|
||||
|
||||
const isSelected = useRecoilComponentFamilyValue(
|
||||
isSelectedItemIdComponentFamilySelector,
|
||||
VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS.SEARCH,
|
||||
);
|
||||
|
||||
const handleSearchClick = () => {
|
||||
openVectorSearchFilter();
|
||||
|
||||
if (objectFilterDropdownSearchInput.length > 0) {
|
||||
setVectorSearchInputValue(objectFilterDropdownSearchInput);
|
||||
applyVectorSearchFilter(objectFilterDropdownSearchInput);
|
||||
} else {
|
||||
setVectorSearchInputValueFromExistingFilter();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<SelectableListItem
|
||||
itemId={VIEW_BAR_FILTER_BOTTOM_MENU_ITEM_IDS.SEARCH}
|
||||
onEnter={handleSearchClick}
|
||||
>
|
||||
<MenuItem
|
||||
focused={isSelected}
|
||||
onClick={handleSearchClick}
|
||||
LeftIcon={IconSearch}
|
||||
text={
|
||||
<>
|
||||
{t`Search`}
|
||||
{objectFilterDropdownSearchInput && (
|
||||
<StyledSearchText>{t`· ${objectFilterDropdownSearchInput}`}</StyledSearchText>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</SelectableListItem>
|
||||
);
|
||||
};
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { ObjectFilterDropdownVectorSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownVectorSearchInput';
|
||||
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
|
||||
import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/GenericDropdownContentWidth';
|
||||
import { ViewBarFilterDropdownFilterInputMenuHeader } from '@/views/components/ViewBarFilterDropdownFilterInputMenuHeader';
|
||||
|
||||
export const ViewBarFilterDropdownVectorSearchInput = () => {
|
||||
return (
|
||||
<DropdownContent widthInPixels={GenericDropdownContentWidth.ExtraLarge}>
|
||||
<ViewBarFilterDropdownFilterInputMenuHeader />
|
||||
<ObjectFilterDropdownVectorSearchInput />
|
||||
</DropdownContent>
|
||||
);
|
||||
};
|
||||
+2
-2
@@ -16,7 +16,7 @@ import { RecordComponentInstanceContextsWrapper } from '@/object-record/componen
|
||||
import { currentRecordFieldsComponentState } from '@/object-record/record-field/states/currentRecordFieldsComponentState';
|
||||
import { type RecordField } from '@/object-record/record-field/types/RecordField';
|
||||
import { useRecordIndexFieldMetadataDerivedStates } from '@/object-record/record-index/hooks/useRecordIndexFieldMetadataDerivedStates';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { coreViewsState } from '@/views/states/coreViewState';
|
||||
import { within } from '@storybook/test';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
@@ -104,7 +104,7 @@ const meta: Meta<typeof ViewBarFilterDropdown> = {
|
||||
componentInstanceId={instanceId}
|
||||
>
|
||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||
value={{ instanceId: VIEW_BAR_FILTER_DROPDOWN_ID }}
|
||||
value={{ instanceId: ViewBarFilterDropdownIds.MAIN }}
|
||||
>
|
||||
<RecordTableComponentInstanceContext.Provider
|
||||
value={{
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const ADVANCED_FILTER_DROPDOWN_ID = 'advanced-filter';
|
||||
@@ -1 +0,0 @@
|
||||
export const VIEW_BAR_FILTER_DROPDOWN_ID = 'view-bar-filter-dropdown';
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum ViewBarFilterDropdownIds {
|
||||
MAIN = 'view-bar-main-filter-dropdown-id',
|
||||
ADVANCED = 'view-bar-advanced-filter-dropdown-id',
|
||||
// We also have editable chip dropdown, in this case use the getEditableChipDropdownId
|
||||
}
|
||||
+3
-2
@@ -1,6 +1,7 @@
|
||||
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';
|
||||
import { EditableFilterChipDropdownMenuHeader } from '@/views/editable-chip/components/EditableFilterChipDropdownMenuHeader';
|
||||
import { getEditableChipDropdownId } from '@/views/editable-chip/utils/getEditableChipDropdownId';
|
||||
|
||||
type EditableFilterChipDropdownContentProps = {
|
||||
recordFilterId: string;
|
||||
@@ -13,7 +14,7 @@ export const EditableFilterChipDropdownContent = ({
|
||||
<ObjectFilterDropdownContentWrapper>
|
||||
<EditableFilterChipDropdownMenuHeader />
|
||||
<ObjectFilterDropdownFilterInput
|
||||
filterDropdownId={recordFilterId}
|
||||
filterDropdownId={getEditableChipDropdownId({ recordFilterId })}
|
||||
recordFilterId={recordFilterId}
|
||||
/>
|
||||
</ObjectFilterDropdownContentWrapper>
|
||||
+1
-15
@@ -1,27 +1,15 @@
|
||||
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 { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
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 = useRecoilComponentValue(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValue(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const isVectorSearchFilter =
|
||||
selectedOperandInDropdown === ViewFilterOperand.VECTOR_SEARCH;
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const handleBackButtonClick = () => {
|
||||
@@ -37,9 +25,7 @@ export const EditableFilterChipDropdownMenuHeader = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
{isVectorSearchFilter
|
||||
? t`Search`
|
||||
: fieldMetadataItemUsedInDropdown?.label}
|
||||
{fieldMetadataItemUsedInDropdown?.label}
|
||||
</DropdownMenuHeader>
|
||||
);
|
||||
};
|
||||
+11
-13
@@ -2,14 +2,14 @@ import { useCallback } from 'react';
|
||||
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { EditableFilterChip } from '@/views/components/EditableFilterChip';
|
||||
import { EditableFilterChip } from '@/views/editable-chip/components/EditableFilterChip';
|
||||
|
||||
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 { EditableRelationFilterChip } from '@/views/components/EditableRelationFilterChip';
|
||||
import { useClearVectorSearchInput } from '@/views/hooks/useClearVectorSearchInput';
|
||||
import { EditableFilterChipDropdownContent } from '@/views/editable-chip/components/EditableFilterChipDropdownContent';
|
||||
import { EditableRelationFilterChip } from '@/views/editable-chip/components/EditableRelationFilterChip';
|
||||
import { getEditableChipDropdownId } from '@/views/editable-chip/utils/getEditableChipDropdownId';
|
||||
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
|
||||
|
||||
type EditableFilterDropdownButtonProps = {
|
||||
@@ -19,29 +19,25 @@ type EditableFilterDropdownButtonProps = {
|
||||
export const EditableFilterDropdownButton = ({
|
||||
recordFilter,
|
||||
}: EditableFilterDropdownButtonProps) => {
|
||||
const dropdownId = recordFilter.id;
|
||||
|
||||
const { closeDropdown } = useCloseDropdown();
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const handleRemove = () => {
|
||||
closeDropdown(dropdownId);
|
||||
closeDropdown(
|
||||
getEditableChipDropdownId({ recordFilterId: recordFilter.id }),
|
||||
);
|
||||
|
||||
removeRecordFilter({ recordFilterId: recordFilter.id });
|
||||
};
|
||||
|
||||
const { clearVectorSearchInput } = useClearVectorSearchInput();
|
||||
|
||||
const onFilterDropdownClose = useCallback(() => {
|
||||
const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter);
|
||||
|
||||
if (recordFilterIsEmpty) {
|
||||
removeRecordFilter({ recordFilterId: recordFilter.id });
|
||||
}
|
||||
|
||||
clearVectorSearchInput();
|
||||
}, [recordFilter, removeRecordFilter, clearVectorSearchInput]);
|
||||
}, [recordFilter, removeRecordFilter]);
|
||||
|
||||
const { setEditableFilterChipDropdownStates } =
|
||||
useSetEditableFilterChipDropdownStates();
|
||||
@@ -53,7 +49,9 @@ export const EditableFilterDropdownButton = ({
|
||||
return (
|
||||
<>
|
||||
<Dropdown
|
||||
dropdownId={recordFilter.id}
|
||||
dropdownId={getEditableChipDropdownId({
|
||||
recordFilterId: recordFilter.id,
|
||||
})}
|
||||
clickableComponent={
|
||||
recordFilter.type === 'RELATION' ? (
|
||||
<EditableRelationFilterChip
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
type GetEditableChipDropdownIdProps = {
|
||||
recordFilterId: string;
|
||||
};
|
||||
|
||||
export const getEditableChipDropdownId = ({
|
||||
recordFilterId,
|
||||
}: GetEditableChipDropdownIdProps) => {
|
||||
return `editable-chip-dropdown-${recordFilterId}`;
|
||||
};
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
type GetEditableChipObjectFilterDropdownComponentInstanceIdProps = {
|
||||
recordFilterId: string;
|
||||
};
|
||||
|
||||
export const getEditableChipObjectFilterDropdownComponentInstanceId = ({
|
||||
recordFilterId,
|
||||
}: GetEditableChipObjectFilterDropdownComponentInstanceIdProps) => {
|
||||
return `editable-filter-${recordFilterId}`;
|
||||
};
|
||||
+2
-2
@@ -17,7 +17,7 @@ import { getRecordFilterOperands } from '@/object-record/record-filter/utils/get
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
import { getFilterTypeFromFieldType } from 'twenty-shared/utils';
|
||||
import { getMockPersonObjectMetadataItem } from '~/testing/mock-data/people';
|
||||
import { generatedMockObjectMetadataItems } from '~/testing/utils/generatedMockObjectMetadataItems';
|
||||
@@ -165,7 +165,7 @@ describe('useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown', () =
|
||||
expect(result.current.objectFilterDropdownFilterIsSelected).toBe(true);
|
||||
expect(result.current.selectedOperandInDropdown).toBe(defaultOperand);
|
||||
expect(mockPushFocusItemToFocusStack).toHaveBeenCalledWith({
|
||||
focusId: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
focusId: ViewBarFilterDropdownIds.MAIN,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: personCompanyFieldMetadataItemMock.id,
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState';
|
||||
|
||||
export const useClearVectorSearchInput = () => {
|
||||
const setVectorSearchInputValue = useSetRecoilComponentState(
|
||||
vectorSearchInputComponentState,
|
||||
);
|
||||
|
||||
const clearVectorSearchInput = () => {
|
||||
setVectorSearchInputValue('');
|
||||
};
|
||||
|
||||
return {
|
||||
clearVectorSearchInput,
|
||||
};
|
||||
};
|
||||
+2
-2
@@ -13,7 +13,7 @@ import { getRecordFilterOperands } from '@/object-record/record-filter/utils/get
|
||||
import { usePushFocusItemToFocusStack } from '@/ui/utilities/focus/hooks/usePushFocusItemToFocusStack';
|
||||
import { FocusComponentType } from '@/ui/utilities/focus/types/FocusComponentType';
|
||||
import { useRecoilComponentCallbackState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackState';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
import { ViewBarFilterDropdownIds } from '@/views/constants/ViewBarFilterDropdownIds';
|
||||
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
@@ -68,7 +68,7 @@ export const useInitializeFilterOnFieldMetadataItemFromViewBarFilterDropdown =
|
||||
|
||||
if (filterType === 'RELATION' || filterType === 'SELECT') {
|
||||
pushFocusItemToFocusStack({
|
||||
focusId: VIEW_BAR_FILTER_DROPDOWN_ID,
|
||||
focusId: ViewBarFilterDropdownIds.MAIN,
|
||||
component: {
|
||||
type: FocusComponentType.DROPDOWN,
|
||||
instanceId: fieldMetadataItem.id,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { type CoreViewFilter } from '~/generated/graphql';
|
||||
import { type ViewFilter } from '../types/ViewFilter';
|
||||
import { getFilterableFieldsWithVectorSearch } from '../utils/getFilterableFieldsWithVectorSearch';
|
||||
import { getFilterableFields } from '../utils/getFilterableFields';
|
||||
import { mapViewFiltersToFilters } from '../utils/mapViewFiltersToFilters';
|
||||
|
||||
export const useMapViewFiltersToFilters = () => {
|
||||
@@ -11,7 +11,7 @@ export const useMapViewFiltersToFilters = () => {
|
||||
viewFilters: ViewFilter[] | CoreViewFilter[],
|
||||
) => {
|
||||
const filterableFieldMetadataItems =
|
||||
getFilterableFieldsWithVectorSearch(objectMetadataItem);
|
||||
getFilterableFields(objectMetadataItem);
|
||||
return mapViewFiltersToFilters(viewFilters, filterableFieldMetadataItems);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useSetRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentState';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
|
||||
export const useOpenVectorSearchFilter = (filterDropdownId?: string) => {
|
||||
const setSelectedOperandInDropdown = useSetRecoilComponentState(
|
||||
selectedOperandInDropdownComponentState,
|
||||
filterDropdownId,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownFilterIsSelected = useSetRecoilComponentState(
|
||||
objectFilterDropdownFilterIsSelectedComponentState,
|
||||
filterDropdownId,
|
||||
);
|
||||
|
||||
const openVectorSearchFilter = () => {
|
||||
setObjectFilterDropdownFilterIsSelected(true);
|
||||
setSelectedOperandInDropdown(ViewFilterOperand.VECTOR_SEARCH);
|
||||
};
|
||||
|
||||
return {
|
||||
openVectorSearchFilter,
|
||||
};
|
||||
};
|
||||
+2
-2
@@ -6,7 +6,7 @@ import { currentRecordSortsComponentState } from '@/object-record/record-sort/st
|
||||
import { getRecordIndexIdFromObjectNamePluralAndViewId } from '@/object-record/utils/getRecordIndexIdFromObjectNamePluralAndViewId';
|
||||
import { coreViewsByObjectMetadataIdFamilySelector } from '@/views/states/selectors/coreViewsByObjectMetadataIdFamilySelector';
|
||||
import { convertCoreViewToView } from '@/views/utils/convertCoreViewToView';
|
||||
import { getFilterableFieldsWithVectorSearch } from '@/views/utils/getFilterableFieldsWithVectorSearch';
|
||||
import { getFilterableFields } from '@/views/utils/getFilterableFields';
|
||||
|
||||
import { mapViewFieldToRecordField } from '@/views/utils/mapViewFieldToRecordField';
|
||||
import { mapViewFiltersToFilters } from '@/views/utils/mapViewFiltersToFilters';
|
||||
@@ -117,7 +117,7 @@ export const useRefreshCoreViewsByObjectMetadataId = () => {
|
||||
}),
|
||||
mapViewFiltersToFilters(
|
||||
view.viewFilters,
|
||||
getFilterableFieldsWithVectorSearch(objectMetadataItem),
|
||||
getFilterableFields(objectMetadataItem),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
+16
-25
@@ -4,9 +4,7 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object-
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useVectorSearchFieldInRecordIndexContextOrThrow } from '@/views/hooks/useVectorSearchFieldInRecordIndexContextOrThrow';
|
||||
import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState';
|
||||
import { isVectorSearchFilter } from '@/views/utils/isVectorSearchFilter';
|
||||
import { getEditableChipObjectFilterDropdownComponentInstanceId } from '@/views/editable-chip/utils/getEditableChipObjectFilterDropdownComponentInstanceId';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -14,26 +12,10 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
||||
const { filterableFieldMetadataItems } =
|
||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
||||
|
||||
const { vectorSearchField } =
|
||||
useVectorSearchFieldInRecordIndexContextOrThrow();
|
||||
|
||||
const setEditableFilterChipDropdownStates = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(recordFilter: RecordFilter) => {
|
||||
const filterableFieldsWithVector = vectorSearchField
|
||||
? filterableFieldMetadataItems.concat(vectorSearchField)
|
||||
: filterableFieldMetadataItems;
|
||||
|
||||
if (isVectorSearchFilter(recordFilter)) {
|
||||
set(
|
||||
vectorSearchInputComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
}),
|
||||
recordFilter.value,
|
||||
);
|
||||
}
|
||||
|
||||
const fieldMetadataItem = filterableFieldsWithVector.find(
|
||||
const fieldMetadataItem = filterableFieldMetadataItems.find(
|
||||
(fieldMetadataItem) =>
|
||||
fieldMetadataItem.id === recordFilter.fieldMetadataId,
|
||||
);
|
||||
@@ -41,7 +23,10 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
||||
if (isDefined(fieldMetadataItem)) {
|
||||
set(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
instanceId:
|
||||
getEditableChipObjectFilterDropdownComponentInstanceId({
|
||||
recordFilterId: recordFilter.id,
|
||||
}),
|
||||
}),
|
||||
fieldMetadataItem.id,
|
||||
);
|
||||
@@ -49,26 +34,32 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
||||
|
||||
set(
|
||||
selectedOperandInDropdownComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({
|
||||
recordFilterId: recordFilter.id,
|
||||
}),
|
||||
}),
|
||||
recordFilter.operand,
|
||||
);
|
||||
|
||||
set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({
|
||||
recordFilterId: recordFilter.id,
|
||||
}),
|
||||
}),
|
||||
recordFilter,
|
||||
);
|
||||
|
||||
set(
|
||||
subFieldNameUsedInDropdownComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
instanceId: getEditableChipObjectFilterDropdownComponentInstanceId({
|
||||
recordFilterId: recordFilter.id,
|
||||
}),
|
||||
}),
|
||||
recordFilter.subFieldName,
|
||||
);
|
||||
},
|
||||
[filterableFieldMetadataItems, vectorSearchField],
|
||||
[filterableFieldMetadataItems],
|
||||
);
|
||||
|
||||
return {
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import { useRecoilComponentState } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentState';
|
||||
import { vectorSearchInputComponentState } from '@/views/states/vectorSearchInputComponentState';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { useVectorSearchFilterState } from './useVectorSearchFilterState';
|
||||
|
||||
export const useSetVectorSearchInputValueFromExistingFilter = () => {
|
||||
const [, setVectorSearchInputValue] = useRecoilComponentState(
|
||||
vectorSearchInputComponentState,
|
||||
);
|
||||
const { getExistingVectorSearchFilter } = useVectorSearchFilterState();
|
||||
|
||||
const setVectorSearchInputValueFromExistingFilter = () => {
|
||||
const existingVectorSearchFilter = getExistingVectorSearchFilter();
|
||||
|
||||
if (isDefined(existingVectorSearchFilter)) {
|
||||
setVectorSearchInputValue(existingVectorSearchFilter.value);
|
||||
}
|
||||
};
|
||||
|
||||
return { setVectorSearchInputValueFromExistingFilter };
|
||||
};
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { SEARCH_VECTOR_FIELD_NAME } from '../constants/ViewFieldConstants';
|
||||
|
||||
export const useVectorSearchFieldInRecordIndexContextOrThrow = () => {
|
||||
const { objectMetadataItem } = useRecordIndexContextOrThrow();
|
||||
|
||||
const vectorSearchField = objectMetadataItem.fields.find(
|
||||
(field) =>
|
||||
field.type === 'TS_VECTOR' && field.name === SEARCH_VECTOR_FIELD_NAME,
|
||||
);
|
||||
|
||||
return { vectorSearchField };
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
import { useRemoveRecordFilter } from '@/object-record/record-filter/hooks/useRemoveRecordFilter';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
||||
import { useVectorSearchFieldInRecordIndexContextOrThrow } from '@/views/hooks/useVectorSearchFieldInRecordIndexContextOrThrow';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
import { getFilterTypeFromFieldType, isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
import { useVectorSearchFilterState } from './useVectorSearchFilterState';
|
||||
|
||||
export const useVectorSearchFilterActions = () => {
|
||||
const { vectorSearchField } =
|
||||
useVectorSearchFieldInRecordIndexContextOrThrow();
|
||||
const { getExistingVectorSearchFilter } = useVectorSearchFilterState();
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const applyVectorSearchFilter = (value: string) => {
|
||||
if (!vectorSearchField) {
|
||||
return;
|
||||
}
|
||||
|
||||
const existingVectorSearchFilter = getExistingVectorSearchFilter();
|
||||
|
||||
const vectorSearchRecordFilter = {
|
||||
id: existingVectorSearchFilter?.id ?? v4(),
|
||||
fieldMetadataId: vectorSearchField.id,
|
||||
value: value,
|
||||
displayValue: value,
|
||||
operand: ViewFilterOperand.VECTOR_SEARCH,
|
||||
type: getFilterTypeFromFieldType(vectorSearchField.type),
|
||||
label: t`Search`,
|
||||
};
|
||||
|
||||
upsertRecordFilter(vectorSearchRecordFilter);
|
||||
};
|
||||
|
||||
const removeEmptyVectorSearchFilter = () => {
|
||||
const vectorSearchFilter = getExistingVectorSearchFilter();
|
||||
|
||||
if (
|
||||
isDefined(vectorSearchFilter) &&
|
||||
isRecordFilterConsideredEmpty(vectorSearchFilter)
|
||||
) {
|
||||
removeRecordFilter({
|
||||
recordFilterId: vectorSearchFilter.id,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
applyVectorSearchFilter,
|
||||
removeEmptyVectorSearchFilter,
|
||||
};
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue';
|
||||
import { isVectorSearchFilter } from '@/views/utils/isVectorSearchFilter';
|
||||
|
||||
export const useVectorSearchFilterState = () => {
|
||||
const currentRecordFilters = useRecoilComponentValue(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const getExistingVectorSearchFilter = () => {
|
||||
return currentRecordFilters.find(isVectorSearchFilter);
|
||||
};
|
||||
|
||||
return {
|
||||
getExistingVectorSearchFilter,
|
||||
};
|
||||
};
|
||||
@@ -1,8 +0,0 @@
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { createComponentState } from '@/ui/utilities/state/component-state/utils/createComponentState';
|
||||
|
||||
export const vectorSearchInputComponentState = createComponentState<string>({
|
||||
key: 'vectorSearchInputComponentState',
|
||||
defaultValue: '',
|
||||
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getFilterFilterableFieldMetadataItems } from '@/object-metadata/utils/getFilterFilterableFieldMetadataItems';
|
||||
|
||||
export const getFilterableFields = (objectMetadataItem: ObjectMetadataItem) => {
|
||||
return [
|
||||
...objectMetadataItem.fields.filter(
|
||||
getFilterFilterableFieldMetadataItems({ isJsonFilterEnabled: true }),
|
||||
),
|
||||
];
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
import { type ObjectMetadataItem } from '@/object-metadata/types/ObjectMetadataItem';
|
||||
import { getFilterFilterableFieldMetadataItems } from '@/object-metadata/utils/getFilterFilterableFieldMetadataItems';
|
||||
import { SEARCH_VECTOR_FIELD_NAME } from '../constants/ViewFieldConstants';
|
||||
|
||||
export const getFilterableFieldsWithVectorSearch = (
|
||||
objectMetadataItem: ObjectMetadataItem,
|
||||
) => {
|
||||
const vectorSearchField = objectMetadataItem.fields.find(
|
||||
(field) =>
|
||||
field.type === 'TS_VECTOR' && field.name === SEARCH_VECTOR_FIELD_NAME,
|
||||
);
|
||||
|
||||
return [
|
||||
...objectMetadataItem.fields.filter(
|
||||
getFilterFilterableFieldMetadataItems({ isJsonFilterEnabled: true }),
|
||||
),
|
||||
...(vectorSearchField ? [vectorSearchField] : []),
|
||||
];
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
import { type RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { ViewFilterOperand } from 'twenty-shared/types';
|
||||
|
||||
export const isVectorSearchFilter = (filter: RecordFilter) => {
|
||||
return filter.operand === ViewFilterOperand.VECTOR_SEARCH;
|
||||
};
|
||||
@@ -14,5 +14,4 @@ export enum ViewFilterOperandDeprecated {
|
||||
IsInPast = 'isInPast',
|
||||
IsInFuture = 'isInFuture',
|
||||
IsToday = 'isToday',
|
||||
VectorSearch = 'search',
|
||||
}
|
||||
|
||||
-1
@@ -19,7 +19,6 @@ const operandMapping: Record<string, ViewFilterOperand> = {
|
||||
[ViewFilterOperandDeprecated.IsInPast]: ViewFilterOperand.IS_IN_PAST,
|
||||
[ViewFilterOperandDeprecated.IsInFuture]: ViewFilterOperand.IS_IN_FUTURE,
|
||||
[ViewFilterOperandDeprecated.IsToday]: ViewFilterOperand.IS_TODAY,
|
||||
[ViewFilterOperandDeprecated.VectorSearch]: ViewFilterOperand.VECTOR_SEARCH,
|
||||
[ViewFilterOperand.IS]: ViewFilterOperand.IS,
|
||||
[ViewFilterOperand.IS_NOT_NULL]: ViewFilterOperand.IS_NOT_NULL,
|
||||
[ViewFilterOperand.IS_NOT]: ViewFilterOperand.IS_NOT,
|
||||
|
||||
Reference in New Issue
Block a user