Refactored object filter dropdown input state management (#11838)
This PR refactors the generic module object dropdown filter input. We have multiple components for each filter type and each one was using selectedFilterState and the applyRecordFilter hook to read and set its value. The main issue was that each component was forced to pass every property of a RecordFilter to applyRecordFilter to only modify the value property, thus creating a lot of unnecessary dependencies and tight coupling between every component and hook that used the record filters. Now we have each component only reading from a new objectFilterDropdownCurrentRecordFilterComponentState, scoped to a ObjectFilterDropdownComponentInstanceContext, thus whether we're in a view bar dropdown, an editable filter chip dropdown or an advanced filter dropdown, we know where to read the filter value from. This component state might even be simplified by only storing the record filter id, thus avoiding having to synchronize this state with its counterpart in currentRecordFilterComponentState, but we should try after the main refactor effort, as those two states aren't in the same instance context. We implement a new applyObjectFilterDropdownFilterValue hook to handle the value setting from an object filter dropdown input component. There's also a new useApplyObjectFilterDropdownOperand for doing the same but for operand. Another important thing that had to be done to keep a synchronous code path was to set the states of each advanced filter row at the advanced filter dropdown onOpen event, using useSetAdvancedFilterDropdownStates. Finally we remove : useApplyRecordFilter, useSelectFilterUsedInDropdown and selectedFilterComponentState which were making all of this zone difficult to work with. Closes https://github.com/twentyhq/core-team-issues/issues/718 Closes https://github.com/twentyhq/core-team-issues/issues/720
This commit is contained in:
@ -1,122 +0,0 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { DateTimePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { computeVariableDateViewFilterValue } from '@/views/view-filter-value/utils/computeVariableDateViewFilterValue';
|
||||
import {
|
||||
resolveDateViewFilterValue,
|
||||
VariableDateViewFilterValueDirection,
|
||||
VariableDateViewFilterValueUnit,
|
||||
} from '@/views/view-filter-value/utils/resolveDateViewFilterValue';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const AdvancedFilterDropdownDateInput = () => {
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
|
||||
const initialFilterValue = selectedFilter
|
||||
? resolveDateViewFilterValue(selectedFilter)
|
||||
: null;
|
||||
const [internalDate, setInternalDate] = useState<Date | null>(
|
||||
initialFilterValue instanceof Date ? initialFilterValue : null,
|
||||
);
|
||||
|
||||
const isDateTimeInput =
|
||||
fieldMetadataItemUsedInDropdown?.type === FieldMetadataType.DATE_TIME;
|
||||
|
||||
const handleAbsoluteDateChange = (newDate: Date | null) => {
|
||||
setInternalDate(newDate);
|
||||
|
||||
if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
const newDisplayValue = isDefined(newDate)
|
||||
? newDate.toLocaleDateString()
|
||||
: '';
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: newDate?.toISOString() ?? '',
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: newDisplayValue,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
};
|
||||
|
||||
const handleRelativeDateChange = (
|
||||
relativeDate: {
|
||||
direction: VariableDateViewFilterValueDirection;
|
||||
amount?: number;
|
||||
unit: VariableDateViewFilterValueUnit;
|
||||
} | null,
|
||||
) => {
|
||||
if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
const value = relativeDate
|
||||
? computeVariableDateViewFilterValue(
|
||||
relativeDate.direction,
|
||||
relativeDate.amount,
|
||||
relativeDate.unit,
|
||||
)
|
||||
: '';
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: getRelativeDateDisplayValue(relativeDate),
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
};
|
||||
|
||||
const isRelativeOperand =
|
||||
selectedOperandInDropdown === ViewFilterOperand.IsRelative;
|
||||
|
||||
const resolvedValue = selectedFilter
|
||||
? resolveDateViewFilterValue(selectedFilter)
|
||||
: null;
|
||||
|
||||
const relativeDate =
|
||||
resolvedValue && !(resolvedValue instanceof Date)
|
||||
? resolvedValue
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<DateTimePicker
|
||||
relativeDate={relativeDate}
|
||||
highlightedDateRange={relativeDate}
|
||||
isRelative={isRelativeOperand}
|
||||
date={internalDate}
|
||||
onChange={handleAbsoluteDateChange}
|
||||
onRelativeDateChange={handleRelativeDateChange}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@ -5,9 +5,9 @@ import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-d
|
||||
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
|
||||
import { AdvancedFilterDropdownDateInput } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownDateInput';
|
||||
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||
import { ObjectFilterDropdownCurrencySelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownCurrencySelect';
|
||||
import { ObjectFilterDropdownDateInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownDateInput';
|
||||
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
@ -41,7 +41,7 @@ export const AdvancedFilterDropdownFilterInput = ({
|
||||
<>
|
||||
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||
{DATE_FILTER_TYPES.includes(filterType) && (
|
||||
<AdvancedFilterDropdownDateInput />
|
||||
<ObjectFilterDropdownDateInput />
|
||||
)}
|
||||
{filterType === 'RELATION' && (
|
||||
<>
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const AdvancedFilterDropdownNumberInput = () => {
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
@ -18,34 +14,14 @@ export const AdvancedFilterDropdownNumberInput = () => {
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
const { objectFilterDropdownFilterValue } =
|
||||
useObjectFilterDropdownFilterValue();
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
|
||||
const [inputValue, setInputValue] = useState(
|
||||
() => selectedFilter?.value || '',
|
||||
);
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const handleChange = (newValue: string) => {
|
||||
if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInputValue(newValue);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '',
|
||||
value: newValue,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: newValue,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
});
|
||||
applyObjectFilterDropdownFilterValue(newValue);
|
||||
};
|
||||
|
||||
if (!selectedOperandInDropdown || !fieldMetadataItemUsedInDropdown) {
|
||||
@ -54,7 +30,7 @@ export const AdvancedFilterDropdownNumberInput = () => {
|
||||
|
||||
return (
|
||||
<TextInputV2
|
||||
value={inputValue}
|
||||
value={objectFilterDropdownFilterValue}
|
||||
onChange={handleChange}
|
||||
placeholder="Enter value"
|
||||
fullWidth
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||
|
||||
@ -9,21 +9,11 @@ type AdvancedFilterDropdownTextInputProps = {
|
||||
export const AdvancedFilterDropdownTextInput = ({
|
||||
recordFilter,
|
||||
}: AdvancedFilterDropdownTextInputProps) => {
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const handleChange = (newValue: string) => {
|
||||
applyRecordFilter({
|
||||
id: recordFilter.id,
|
||||
fieldMetadataId: recordFilter.fieldMetadataId,
|
||||
value: newValue,
|
||||
operand: recordFilter.operand,
|
||||
displayValue: newValue,
|
||||
type: recordFilter.type,
|
||||
label: recordFilter.label,
|
||||
recordFilterGroupId: recordFilter.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: recordFilter.positionInRecordFilterGroup,
|
||||
subFieldName: recordFilter.subFieldName,
|
||||
});
|
||||
applyObjectFilterDropdownFilterValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -4,6 +4,8 @@ import { AdvancedFilterValueInputDropdownButtonClickableSelect } from '@/object-
|
||||
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
||||
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 { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands';
|
||||
import { isExpectedSubFieldName } from '@/object-record/object-filter-dropdown/utils/isExpectedSubFieldName';
|
||||
@ -44,6 +46,15 @@ export const AdvancedFilterValueInput = ({
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownCurrentRecordFilter =
|
||||
useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const operandHasNoInput =
|
||||
recordFilter && !configurableViewFilterOperands.has(recordFilter.operand);
|
||||
|
||||
@ -55,6 +66,11 @@ export const AdvancedFilterValueInput = ({
|
||||
setObjectFilterDropdownSearchInput('');
|
||||
};
|
||||
|
||||
const handleFilterValueDropdownOpen = () => {
|
||||
setObjectFilterDropdownCurrentRecordFilter(recordFilter);
|
||||
setFieldMetadataItemIdUsedInDropdown(recordFilter.fieldMetadataId);
|
||||
};
|
||||
|
||||
const filterType = recordFilter.type;
|
||||
|
||||
const dropdownContentOffset =
|
||||
@ -98,6 +114,7 @@ export const AdvancedFilterValueInput = ({
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownWidth={280}
|
||||
onClose={handleFilterValueDropdownClose}
|
||||
onOpen={handleFilterValueDropdownOpen}
|
||||
/>
|
||||
)}
|
||||
</StyledValueDropdownContainer>
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
|
||||
@ -40,14 +42,19 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
|
||||
const { getFieldMetadataItemById } = useGetFieldMetadataItemById();
|
||||
|
||||
const setSubFieldNameUsedInDropdown = useSetRecoilComponentStateV2(
|
||||
subFieldNameUsedInDropdownComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownCurrentRecordFilter =
|
||||
useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const selectFieldUsedInAdvancedFilterDropdown = ({
|
||||
fieldMetadataItemId,
|
||||
recordFilterId,
|
||||
@ -86,7 +93,7 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
(recordFilter) => recordFilter.id === recordFilterId,
|
||||
);
|
||||
|
||||
applyRecordFilter({
|
||||
const newAdvancedFilter = {
|
||||
id: recordFilterId,
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
displayValue,
|
||||
@ -97,12 +104,15 @@ export const useSelectFieldUsedInAdvancedFilterDropdown = () => {
|
||||
existingRecordFilter?.positionInRecordFilterGroup,
|
||||
type: filterType,
|
||||
label: fieldMetadataItem.label,
|
||||
subFieldName: subFieldName ?? null,
|
||||
});
|
||||
subFieldName,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
setSubFieldNameUsedInDropdown(subFieldName);
|
||||
|
||||
setObjectFilterDropdownSearchInput('');
|
||||
|
||||
setObjectFilterDropdownCurrentRecordFilter(newAdvancedFilter);
|
||||
upsertRecordFilter(newAdvancedFilter);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -0,0 +1,98 @@
|
||||
import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector';
|
||||
import { getAdvancedFilterObjectFilterDropdownComponentInstanceId } from '@/object-record/advanced-filter/utils/getAdvancedFilterObjectFilterDropdownComponentInstanceId';
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { currentRecordFilterGroupsComponentState } from '@/object-record/record-filter-group/states/currentRecordFilterGroupsComponentState';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
export const useSetAdvancedFilterDropdownStates = () => {
|
||||
const rootLevelRecordFilterGroup = useRecoilComponentValueV2(
|
||||
rootLevelRecordFilterGroupComponentSelector,
|
||||
);
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const currentRecordFilterGroups = useRecoilComponentValueV2(
|
||||
currentRecordFilterGroupsComponentState,
|
||||
);
|
||||
|
||||
const setAdvancedFilterDropdownStates = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
const rootLevelRecordFilters = currentRecordFilters.filter(
|
||||
(recordFilter) =>
|
||||
recordFilter.recordFilterGroupId === rootLevelRecordFilterGroup?.id,
|
||||
);
|
||||
|
||||
for (const rootLevelRecordFilter of rootLevelRecordFilters) {
|
||||
set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId:
|
||||
getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||
rootLevelRecordFilter.id,
|
||||
),
|
||||
}),
|
||||
rootLevelRecordFilter,
|
||||
);
|
||||
|
||||
set(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||
instanceId:
|
||||
getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||
rootLevelRecordFilter.id,
|
||||
),
|
||||
}),
|
||||
rootLevelRecordFilter.fieldMetadataId,
|
||||
);
|
||||
}
|
||||
|
||||
const childRecordFilterGroups = currentRecordFilterGroups.filter(
|
||||
(currentRecordGroupToFilter) =>
|
||||
currentRecordGroupToFilter.parentRecordFilterGroupId ===
|
||||
rootLevelRecordFilterGroup?.id,
|
||||
);
|
||||
|
||||
for (const childRecordFilterGroup of childRecordFilterGroups) {
|
||||
const recordFiltersInThisGroup = currentRecordFilters.filter(
|
||||
(recordFilter) =>
|
||||
recordFilter.recordFilterGroupId === childRecordFilterGroup.id,
|
||||
);
|
||||
|
||||
for (const recordFilterInThisGroup of recordFiltersInThisGroup) {
|
||||
set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId:
|
||||
getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||
recordFilterInThisGroup.id,
|
||||
),
|
||||
}),
|
||||
recordFilterInThisGroup,
|
||||
);
|
||||
|
||||
set(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||
instanceId:
|
||||
getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||
recordFilterInThisGroup.id,
|
||||
),
|
||||
}),
|
||||
recordFilterInThisGroup.fieldMetadataId,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
[
|
||||
currentRecordFilterGroups,
|
||||
currentRecordFilters,
|
||||
rootLevelRecordFilterGroup,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
setAdvancedFilterDropdownStates,
|
||||
};
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { getAdvancedFilterObjectFilterDropdownComponentInstanceId } from '@/object-record/advanced-filter/utils/getAdvancedFilterObjectFilterDropdownComponentInstanceId';
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
@ -31,7 +31,7 @@ export const useSetRecordFilterUsedInAdvancedFilterDropdownRow = () => {
|
||||
);
|
||||
|
||||
set(
|
||||
selectedFilterComponentState.atomFamily({
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId:
|
||||
advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||
}),
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { BooleanDisplay } from '@/ui/field/display/components/BooleanDisplay';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconCheck } from 'twenty-ui/display';
|
||||
|
||||
const StyledBooleanSelectContainer = styled.div<{ selected?: boolean }>`
|
||||
@ -40,52 +33,20 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
||||
const theme = useTheme();
|
||||
const options = [true, false];
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
const { objectFilterDropdownFilterValue } =
|
||||
useObjectFilterDropdownFilterValue();
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const { closeDropdown } = useDropdown();
|
||||
|
||||
const [selectedValue, setSelectedValue] = useState<boolean | undefined>(
|
||||
selectedFilter?.value === 'true',
|
||||
);
|
||||
const handleOptionSelect = (newValue: boolean) => {
|
||||
applyObjectFilterDropdownFilterValue(
|
||||
newValue.toString(),
|
||||
newValue ? 'True' : 'False',
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedValue(selectedFilter?.value === 'true');
|
||||
}, [selectedFilter?.value]);
|
||||
|
||||
const handleOptionSelect = (value: boolean) => {
|
||||
if (
|
||||
!isDefined(fieldMetadataItemUsedInDropdown) ||
|
||||
!isDefined(selectedOperandInDropdown)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ?? v4(),
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: value ? 'True' : 'False',
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: value.toString(),
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
|
||||
setSelectedValue(value);
|
||||
closeDropdown();
|
||||
};
|
||||
|
||||
@ -100,10 +61,10 @@ export const ObjectFilterDropdownBooleanSelect = () => {
|
||||
<StyledBooleanSelectContainer
|
||||
key={String(option)}
|
||||
onClick={() => handleOptionSelect(option)}
|
||||
selected={selectedValue === option}
|
||||
selected={objectFilterDropdownFilterValue === option.toString()}
|
||||
>
|
||||
<BooleanDisplay value={option} />
|
||||
{selectedFilter?.value === option.toString() && (
|
||||
{objectFilterDropdownFilterValue === option.toString() && (
|
||||
<StyledIconCheckContainer>
|
||||
<IconCheck color={theme.grayScale.gray50} size={16} />
|
||||
</StyledIconCheckContainer>
|
||||
|
||||
@ -1,12 +1,7 @@
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { turnCurrencyIntoSelectableItem } from '@/object-record/object-filter-dropdown/utils/turnCurrencyIntoSelectableItem';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
||||
import { StyledMultipleSelectDropdownAvatarChip } from '@/object-record/select/components/StyledMultipleSelectDropdownAvatarChip';
|
||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||
import { CURRENCIES } from '@/settings/data-model/constants/Currencies';
|
||||
@ -14,70 +9,55 @@ import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/Drop
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { ChangeEvent, useState } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { MenuItem, MenuItemMultiSelectAvatar } from 'twenty-ui/navigation';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const EMPTY_FILTER_VALUE = '[]';
|
||||
export const MAX_ITEMS_TO_DISPLAY = 3;
|
||||
|
||||
type ObjectFilterDropdownCurrencySelectProps = {
|
||||
viewComponentId?: string;
|
||||
dropdownWidth?: number;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownCurrencySelect = ({
|
||||
viewComponentId,
|
||||
dropdownWidth,
|
||||
}: ObjectFilterDropdownCurrencySelectProps) => {
|
||||
const [searchText, setSearchText] = useState('');
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownSelectedRecordIds = useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownSelectedRecordIdsComponentState,
|
||||
selectedFilter?.id,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSelectedRecordIds = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSelectedRecordIdsComponentState,
|
||||
selectedFilter?.id,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter(viewComponentId);
|
||||
|
||||
const currenciesAsSelectableItems = CURRENCIES.map(
|
||||
turnCurrencyIntoSelectableItem,
|
||||
);
|
||||
|
||||
const selectedCurrencies = isNonEmptyString(
|
||||
objectFilterDropdownCurrentRecordFilter?.value,
|
||||
)
|
||||
? (JSON.parse(objectFilterDropdownCurrentRecordFilter.value) as string[]) // TODO: replace by a safe parse
|
||||
: [];
|
||||
|
||||
const filteredSelectableItems = currenciesAsSelectableItems.filter(
|
||||
(selectableItem) =>
|
||||
selectableItem.name.toLowerCase().includes(searchText.toLowerCase()) &&
|
||||
!objectFilterDropdownSelectedRecordIds.includes(selectableItem.id),
|
||||
!selectedCurrencies.includes(selectableItem.id),
|
||||
);
|
||||
|
||||
const filteredSelectedItems = currenciesAsSelectableItems.filter(
|
||||
(selectableItem) =>
|
||||
selectableItem.name.toLowerCase().includes(searchText.toLowerCase()) &&
|
||||
objectFilterDropdownSelectedRecordIds.includes(selectableItem.id),
|
||||
);
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
selectedCurrencies.includes(selectableItem.id),
|
||||
);
|
||||
|
||||
const handleMultipleItemSelectChange = (
|
||||
@ -85,10 +65,8 @@ export const ObjectFilterDropdownCurrencySelect = ({
|
||||
newSelectedValue: boolean,
|
||||
) => {
|
||||
const newSelectedItemIds = newSelectedValue
|
||||
? [...objectFilterDropdownSelectedRecordIds, itemToSelect.id]
|
||||
: objectFilterDropdownSelectedRecordIds.filter(
|
||||
(id) => id !== itemToSelect.id,
|
||||
);
|
||||
? [...selectedCurrencies, itemToSelect.id]
|
||||
: selectedCurrencies.filter((id) => id !== itemToSelect.id);
|
||||
|
||||
if (!isDefined(fieldMetadataItemUsedInFilterDropdown)) {
|
||||
throw new Error(
|
||||
@ -96,8 +74,6 @@ export const ObjectFilterDropdownCurrencySelect = ({
|
||||
);
|
||||
}
|
||||
|
||||
setObjectFilterDropdownSelectedRecordIds(newSelectedItemIds);
|
||||
|
||||
const selectedItemNames = currenciesAsSelectableItems
|
||||
.filter((option) => newSelectedItemIds.includes(option.id))
|
||||
.map((option) => option.name);
|
||||
@ -107,46 +83,12 @@ export const ObjectFilterDropdownCurrencySelect = ({
|
||||
? `${selectedItemNames.length} currencies`
|
||||
: selectedItemNames.join(', ');
|
||||
|
||||
if (
|
||||
isDefined(fieldMetadataItemUsedInFilterDropdown) &&
|
||||
isDefined(selectedOperandInDropdown)
|
||||
) {
|
||||
const newFilterValue =
|
||||
newSelectedItemIds.length > 0
|
||||
? JSON.stringify(newSelectedItemIds)
|
||||
: EMPTY_FILTER_VALUE;
|
||||
const newFilterValue =
|
||||
newSelectedItemIds.length > 0
|
||||
? JSON.stringify(newSelectedItemIds)
|
||||
: EMPTY_FILTER_VALUE;
|
||||
|
||||
const duplicateFilterInCurrentRecordFilters =
|
||||
findDuplicateRecordFilterInNonAdvancedRecordFilters({
|
||||
recordFilters: currentRecordFilters,
|
||||
fieldMetadataItemId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
subFieldName: 'currencyCode',
|
||||
});
|
||||
|
||||
const filterIsAlreadyInCurrentRecordFilters = isDefined(
|
||||
duplicateFilterInCurrentRecordFilters,
|
||||
);
|
||||
|
||||
const filterId = filterIsAlreadyInCurrentRecordFilters
|
||||
? duplicateFilterInCurrentRecordFilters?.id
|
||||
: v4();
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : filterId,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInFilterDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInFilterDropdown.label,
|
||||
operand: selectedOperandInDropdown || ViewFilterOperand.Is,
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
subFieldName: 'currencyCode',
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
});
|
||||
}
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, filterDisplayValue);
|
||||
};
|
||||
|
||||
const showNoResult =
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { DateTimePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
@ -28,15 +25,17 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const initialFilterValue = selectedFilter
|
||||
? resolveDateViewFilterValue(selectedFilter)
|
||||
const initialFilterValue = isDefined(objectFilterDropdownCurrentRecordFilter)
|
||||
? resolveDateViewFilterValue(objectFilterDropdownCurrentRecordFilter)
|
||||
: null;
|
||||
|
||||
const [internalDate, setInternalDate] = useState<Date | null>(
|
||||
initialFilterValue instanceof Date ? initialFilterValue : null,
|
||||
);
|
||||
@ -47,24 +46,14 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
const handleAbsoluteDateChange = (newDate: Date | null) => {
|
||||
setInternalDate(newDate);
|
||||
|
||||
if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
const newFilterValue = newDate?.toISOString() ?? '';
|
||||
const newDisplayValue = isDefined(newDate)
|
||||
? isDateTimeInput
|
||||
? newDate.toLocaleString()
|
||||
: newDate.toLocaleDateString()
|
||||
: '';
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: newDate?.toISOString() ?? '',
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: isDefined(newDate)
|
||||
? isDateTimeInput
|
||||
? newDate.toLocaleString()
|
||||
: newDate.toLocaleDateString()
|
||||
: '',
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, newDisplayValue);
|
||||
};
|
||||
|
||||
const handleRelativeDateChange = (
|
||||
@ -74,9 +63,7 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
unit: VariableDateViewFilterValueUnit;
|
||||
} | null,
|
||||
) => {
|
||||
if (!fieldMetadataItemUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
const value = relativeDate
|
||||
const newFilterValue = relativeDate
|
||||
? computeVariableDateViewFilterValue(
|
||||
relativeDate.direction,
|
||||
relativeDate.amount,
|
||||
@ -84,24 +71,18 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
)
|
||||
: '';
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: getRelativeDateDisplayValue(relativeDate),
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup: selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
});
|
||||
const newDisplayValue = relativeDate
|
||||
? getRelativeDateDisplayValue(relativeDate)
|
||||
: '';
|
||||
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, newDisplayValue);
|
||||
};
|
||||
|
||||
const isRelativeOperand =
|
||||
selectedOperandInDropdown === ViewFilterOperand.IsRelative;
|
||||
|
||||
const resolvedValue = selectedFilter
|
||||
? resolveDateViewFilterValue(selectedFilter)
|
||||
const resolvedValue = objectFilterDropdownCurrentRecordFilter
|
||||
? resolveDateViewFilterValue(objectFilterDropdownCurrentRecordFilter)
|
||||
: null;
|
||||
|
||||
const relativeDate =
|
||||
|
||||
@ -9,7 +9,6 @@ import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { FILTER_FIELD_LIST_ID } from '@/object-record/object-filter-dropdown/constants/FilterFieldListId';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
||||
@ -68,10 +67,6 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const setSelectedFilter = useSetRecoilComponentStateV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownCurrentRecordFilter =
|
||||
useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
@ -103,8 +98,6 @@ export const ObjectFilterDropdownFilterSelectMenuItem = ({
|
||||
);
|
||||
|
||||
if (filterIsAlreadyInCurrentRecordFilters) {
|
||||
setSelectedFilter(duplicateFilterInCurrentRecordFilters);
|
||||
|
||||
setObjectFilterDropdownCurrentRecordFilter(
|
||||
duplicateFilterInCurrentRecordFilters,
|
||||
);
|
||||
|
||||
@ -1,41 +1,25 @@
|
||||
import { ChangeEvent, useCallback, useState } from 'react';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { DropdownMenuInput } from '@/ui/layout/dropdown/components/DropdownMenuInput';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
export const ObjectFilterDropdownNumberInput = () => {
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
const { objectFilterDropdownFilterValue } =
|
||||
useObjectFilterDropdownFilterValue();
|
||||
|
||||
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
|
||||
subFieldNameUsedInDropdownComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const [hasFocused, setHasFocused] = useState(false);
|
||||
|
||||
const [inputValue, setInputValue] = useState(
|
||||
() => selectedFilter?.value || '',
|
||||
);
|
||||
|
||||
const handleInputRef = useCallback(
|
||||
(node: HTMLInputElement | null) => {
|
||||
if (Boolean(node) && !hasFocused) {
|
||||
@ -47,39 +31,22 @@ export const ObjectFilterDropdownNumberInput = () => {
|
||||
[hasFocused],
|
||||
);
|
||||
|
||||
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
applyObjectFilterDropdownFilterValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
fieldMetadataItemUsedInDropdown &&
|
||||
selectedOperandInDropdown && (
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuInput
|
||||
ref={handleInputRef}
|
||||
value={inputValue}
|
||||
autoFocus
|
||||
type="number"
|
||||
placeholder={fieldMetadataItemUsedInDropdown.label}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
setInputValue(newValue);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown?.id ?? '',
|
||||
value: newValue,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: newValue,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
subFieldName: subFieldNameUsedInDropdown,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
)
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuInput
|
||||
ref={handleInputRef}
|
||||
value={objectFilterDropdownFilterValue}
|
||||
autoFocus
|
||||
type="number"
|
||||
placeholder={fieldMetadataItemUsedInDropdown?.label}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,22 +1,16 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownOperand } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownOperand';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import styled from '@emotion/styled';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { getOperandLabel } from '../utils/getOperandLabel';
|
||||
import { MenuItem } from 'twenty-ui/navigation';
|
||||
import { getOperandLabel } from '../utils/getOperandLabel';
|
||||
|
||||
const StyledDropdownMenuItemsContainer = styled(DropdownMenuItemsContainer)`
|
||||
background-color: ${({ theme }) => theme.background.primary};
|
||||
@ -28,19 +22,12 @@ export const ObjectFilterDropdownOperandSelect = () => {
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
|
||||
subFieldNameUsedInDropdownComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const { applyObjectFilterDropdownOperand } =
|
||||
useApplyObjectFilterDropdownOperand();
|
||||
|
||||
const { closeDropdown } = useDropdown();
|
||||
|
||||
@ -54,56 +41,7 @@ export const ObjectFilterDropdownOperandSelect = () => {
|
||||
: [];
|
||||
|
||||
const handleOperandChange = (newOperand: ViewFilterOperand) => {
|
||||
const isValuelessOperand = [
|
||||
ViewFilterOperand.IsEmpty,
|
||||
ViewFilterOperand.IsNotEmpty,
|
||||
ViewFilterOperand.IsInPast,
|
||||
ViewFilterOperand.IsInFuture,
|
||||
ViewFilterOperand.IsToday,
|
||||
].includes(newOperand);
|
||||
|
||||
setSelectedOperandInDropdown(newOperand);
|
||||
|
||||
if (isValuelessOperand && isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
displayValue: '',
|
||||
operand: newOperand,
|
||||
value: '',
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
subFieldName: subFieldNameUsedInDropdown,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
isDefined(fieldMetadataItemUsedInDropdown) &&
|
||||
isDefined(selectedFilter)
|
||||
) {
|
||||
const filterType = getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
);
|
||||
|
||||
const { value, displayValue } = getInitialFilterValue(
|
||||
filterType,
|
||||
newOperand,
|
||||
selectedFilter.value,
|
||||
selectedFilter.displayValue,
|
||||
);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: selectedFilter.fieldMetadataId,
|
||||
displayValue,
|
||||
operand: newOperand,
|
||||
value,
|
||||
type: filterType,
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
subFieldName: subFieldNameUsedInDropdown,
|
||||
});
|
||||
}
|
||||
applyObjectFilterDropdownOperand(newOperand);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { Key } from 'ts-key-enum';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { FieldMetadataItemOption } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { useOptionsForSelect } from '@/object-record/object-filter-dropdown/hooks/useOptionsForSelect';
|
||||
@ -10,19 +9,17 @@ import { SelectableList } from '@/ui/layout/selectable-list/components/Selectabl
|
||||
|
||||
import { useSelectableList } from '@/ui/layout/selectable-list/hooks/useSelectableList';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { selectedItemIdComponentState } from '@/ui/layout/selectable-list/states/selectedItemIdComponentState';
|
||||
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
|
||||
import { useAvailableComponentInstanceIdOrThrow } from '@/ui/utilities/state/component-state/hooks/useAvailableComponentInstanceIdOrThrow';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { MenuItem, MenuItemMultiSelect } from 'twenty-ui/navigation';
|
||||
|
||||
@ -38,27 +35,30 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSelectedOptionValues = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSelectedOptionValuesComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const componentInstanceId = useAvailableComponentInstanceIdOrThrow(
|
||||
ObjectFilterDropdownComponentInstanceContext,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const selectedOptions = useMemo(
|
||||
() =>
|
||||
isNonEmptyString(objectFilterDropdownCurrentRecordFilter?.value)
|
||||
? (JSON.parse(
|
||||
objectFilterDropdownCurrentRecordFilter.value,
|
||||
) as string[]) // TODO: replace by a safe parse
|
||||
: [],
|
||||
[objectFilterDropdownCurrentRecordFilter?.value],
|
||||
);
|
||||
|
||||
const { closeDropdown } = useDropdown();
|
||||
|
||||
@ -80,9 +80,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
useEffect(() => {
|
||||
if (isDefined(selectOptions)) {
|
||||
const options = selectOptions.map((option) => {
|
||||
const isSelected =
|
||||
objectFilterDropdownSelectedOptionValues?.includes(option.value) ??
|
||||
false;
|
||||
const isSelected = selectedOptions?.includes(option.value) ?? false;
|
||||
|
||||
return {
|
||||
...option,
|
||||
@ -92,7 +90,7 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
|
||||
setSelectableOptions(options);
|
||||
}
|
||||
}, [objectFilterDropdownSelectedOptionValues, selectOptions]);
|
||||
}, [selectedOptions, selectOptions]);
|
||||
|
||||
useScopedHotkeys(
|
||||
[Key.Escape],
|
||||
@ -127,29 +125,13 @@ export const ObjectFilterDropdownOptionSelect = () => {
|
||||
? `${selectedOptions.length} options`
|
||||
: selectedOptions.map((option) => option.label).join(', ');
|
||||
|
||||
if (
|
||||
isDefined(fieldMetadataItemUsedInDropdown) &&
|
||||
isDefined(selectedOperandInDropdown)
|
||||
) {
|
||||
const newFilterValue =
|
||||
selectedOptions.length > 0
|
||||
? JSON.stringify(selectedOptions.map((option) => option.value))
|
||||
: EMPTY_FILTER_VALUE;
|
||||
const newFilterValue =
|
||||
selectedOptions.length > 0
|
||||
? JSON.stringify(selectedOptions.map((option) => option.value))
|
||||
: EMPTY_FILTER_VALUE;
|
||||
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, filterDisplayValue);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
type: getFilterTypeFromFieldType(fieldMetadataItemUsedInDropdown.type),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: newFilterValue,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
}
|
||||
resetSelectedItem();
|
||||
};
|
||||
|
||||
|
||||
@ -1,15 +1,9 @@
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { RATING_VALUES } from '@/object-record/record-field/meta-types/constants/RatingValues';
|
||||
import { FieldRatingValue } from '@/object-record/record-field/types/FieldMetadata';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { RatingInput } from '@/ui/field/input/components/RatingInput';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledRatingInputContainer = styled.div`
|
||||
@ -35,53 +29,37 @@ export const convertLessThanRatingToArrayOfRatingValues = (
|
||||
};
|
||||
|
||||
export const convertRatingToRatingValue = (rating: number) => {
|
||||
return `RATING_${rating}`;
|
||||
return `RATING_${rating}` as FieldRatingValue;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownRatingInput = () => {
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
const { objectFilterDropdownFilterValue } =
|
||||
useObjectFilterDropdownFilterValue();
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
const handleInputChange = (newRatingValue: FieldRatingValue) => {
|
||||
if (!newRatingValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
const ratingValueConverted =
|
||||
convertFieldRatingValueToNumber(newRatingValue);
|
||||
|
||||
applyObjectFilterDropdownFilterValue(ratingValueConverted);
|
||||
};
|
||||
|
||||
const currentFilterValueConvertedToRatingValue = convertRatingToRatingValue(
|
||||
Number(objectFilterDropdownFilterValue),
|
||||
);
|
||||
|
||||
return (
|
||||
fieldMetadataItemUsedInDropdown &&
|
||||
selectedOperandInDropdown && (
|
||||
<StyledRatingInputContainer>
|
||||
<RatingInput
|
||||
value={selectedFilter?.value as FieldRatingValue}
|
||||
onChange={(newValue: FieldRatingValue) => {
|
||||
if (!newValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyRecordFilter?.({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: convertFieldRatingValueToNumber(newValue),
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: convertFieldRatingValueToNumber(newValue),
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</StyledRatingInputContainer>
|
||||
)
|
||||
<StyledRatingInputContainer>
|
||||
<RatingInput
|
||||
value={currentFilterValueConvertedToRatingValue}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</StyledRatingInputContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,17 +1,13 @@
|
||||
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
|
||||
import {
|
||||
getFilterTypeFromFieldType,
|
||||
getRelationObjectMetadataNameSingular,
|
||||
} from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { getRelationObjectMetadataNameSingular } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { ObjectFilterDropdownRecordPinnedItems } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordPinnedItems';
|
||||
import { CURRENT_WORKSPACE_MEMBER_SELECTABLE_ITEM_ID } from '@/object-record/object-filter-dropdown/constants/CurrentWorkspaceMemberSelectableItemId';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { useObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
||||
import { useRecordsForSelect } from '@/object-record/select/hooks/useRecordsForSelect';
|
||||
@ -23,7 +19,6 @@ import { jsonRelationFilterValueSchema } from '@/views/view-filter-value/validat
|
||||
import { simpleRelationFilterValueSchema } from '@/views/view-filter-value/validation-schemas/simpleRelationFilterValueSchema';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { IconUserCircle } from 'twenty-ui/display';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const EMPTY_FILTER_VALUE: string = JSON.stringify({
|
||||
isCurrentWorkspaceMemberSelected: false,
|
||||
@ -33,26 +28,26 @@ export const EMPTY_FILTER_VALUE: string = JSON.stringify({
|
||||
export const MAX_RECORDS_TO_DISPLAY = 3;
|
||||
|
||||
type ObjectFilterDropdownRecordSelectProps = {
|
||||
viewComponentId?: string;
|
||||
recordFilterId?: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownRecordSelect = ({
|
||||
viewComponentId,
|
||||
recordFilterId,
|
||||
}: ObjectFilterDropdownRecordSelectProps) => {
|
||||
const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const { objectFilterDropdownFilterValue } =
|
||||
useObjectFilterDropdownFilterValue();
|
||||
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
@ -61,16 +56,14 @@ export const ObjectFilterDropdownRecordSelect = ({
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter(viewComponentId);
|
||||
|
||||
const { isCurrentWorkspaceMemberSelected } = jsonRelationFilterValueSchema
|
||||
.catch({
|
||||
isCurrentWorkspaceMemberSelected: false,
|
||||
selectedRecordIds: simpleRelationFilterValueSchema.parse(
|
||||
selectedFilter?.value,
|
||||
objectFilterDropdownFilterValue,
|
||||
),
|
||||
})
|
||||
.parse(selectedFilter?.value);
|
||||
.parse(objectFilterDropdownFilterValue);
|
||||
|
||||
if (!isDefined(fieldMetadataItemUsedInFilterDropdown)) {
|
||||
throw new Error('fieldMetadataItemUsedInFilterDropdown is not defined');
|
||||
@ -210,50 +203,7 @@ export const ObjectFilterDropdownRecordSelect = ({
|
||||
} satisfies RelationFilterValue)
|
||||
: '';
|
||||
|
||||
const duplicateFilterInCurrentRecordFilters =
|
||||
findDuplicateRecordFilterInNonAdvancedRecordFilters({
|
||||
recordFilters: currentRecordFilters,
|
||||
fieldMetadataItemId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
});
|
||||
|
||||
const filterIsAlreadyInCurrentRecordFilters = isDefined(
|
||||
duplicateFilterInCurrentRecordFilters,
|
||||
);
|
||||
|
||||
if (filterIsAlreadyInCurrentRecordFilters && !isDefined(recordFilterId)) {
|
||||
applyRecordFilter({
|
||||
id: duplicateFilterInCurrentRecordFilters.id,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInFilterDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInFilterDropdown.label,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
recordFilterGroupId:
|
||||
duplicateFilterInCurrentRecordFilters.recordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
duplicateFilterInCurrentRecordFilters.positionInRecordFilterGroup,
|
||||
subFieldName: duplicateFilterInCurrentRecordFilters.subFieldName,
|
||||
});
|
||||
} else {
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInFilterDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInFilterDropdown.label,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
}
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, filterDisplayValue);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,68 +1,44 @@
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { useApplyObjectFilterDropdownFilterValue } from '@/object-record/object-filter-dropdown/hooks/useApplyObjectFilterDropdownFilterValue';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { getActorSourceMultiSelectOptions } from '@/object-record/object-filter-dropdown/utils/getActorSourceMultiSelectOptions';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { findDuplicateRecordFilterInNonAdvancedRecordFilters } from '@/object-record/record-filter/utils/findDuplicateRecordFilterInNonAdvancedRecordFilters';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
import { MultipleSelectDropdown } from '@/object-record/select/components/MultipleSelectDropdown';
|
||||
import { SelectableItem } from '@/object-record/select/types/SelectableItem';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const EMPTY_FILTER_VALUE = '[]';
|
||||
export const MAX_ITEMS_TO_DISPLAY = 3;
|
||||
|
||||
type ObjectFilterDropdownSourceSelectProps = {
|
||||
viewComponentId?: string;
|
||||
};
|
||||
|
||||
export const ObjectFilterDropdownSourceSelect = ({
|
||||
viewComponentId,
|
||||
}: ObjectFilterDropdownSourceSelectProps) => {
|
||||
export const ObjectFilterDropdownSourceSelect = () => {
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownSelectedRecordIds = useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownSelectedRecordIdsComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSelectedRecordIds = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSelectedRecordIdsComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const fieldMetadataItemUsedInFilterDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter(viewComponentId);
|
||||
|
||||
const sourceTypes = getActorSourceMultiSelectOptions(
|
||||
objectFilterDropdownSelectedRecordIds,
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const { applyObjectFilterDropdownFilterValue } =
|
||||
useApplyObjectFilterDropdownFilterValue();
|
||||
|
||||
const selectedSources = isNonEmptyString(
|
||||
objectFilterDropdownCurrentRecordFilter?.value,
|
||||
)
|
||||
? (JSON.parse(objectFilterDropdownCurrentRecordFilter.value) as string[]) // TODO: replace by a safe parse
|
||||
: [];
|
||||
|
||||
const sourceTypes = getActorSourceMultiSelectOptions(selectedSources);
|
||||
|
||||
const filteredSelectedItems = sourceTypes.filter((option) =>
|
||||
objectFilterDropdownSelectedRecordIds.includes(option.id),
|
||||
);
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
selectedSources.includes(option.id),
|
||||
);
|
||||
|
||||
const handleMultipleItemSelectChange = (
|
||||
@ -70,10 +46,8 @@ export const ObjectFilterDropdownSourceSelect = ({
|
||||
newSelectedValue: boolean,
|
||||
) => {
|
||||
const newSelectedItemIds = newSelectedValue
|
||||
? [...objectFilterDropdownSelectedRecordIds, itemToSelect.id]
|
||||
: objectFilterDropdownSelectedRecordIds.filter(
|
||||
(id) => id !== itemToSelect.id,
|
||||
);
|
||||
? [...selectedSources, itemToSelect.id]
|
||||
: selectedSources.filter((id) => id !== itemToSelect.id);
|
||||
|
||||
if (!isDefined(fieldMetadataItemUsedInFilterDropdown)) {
|
||||
throw new Error(
|
||||
@ -81,8 +55,6 @@ export const ObjectFilterDropdownSourceSelect = ({
|
||||
);
|
||||
}
|
||||
|
||||
setObjectFilterDropdownSelectedRecordIds(newSelectedItemIds);
|
||||
|
||||
const selectedItemNames = sourceTypes
|
||||
.filter((option) => newSelectedItemIds.includes(option.id))
|
||||
.map((option) => option.name);
|
||||
@ -92,46 +64,12 @@ export const ObjectFilterDropdownSourceSelect = ({
|
||||
? `${selectedItemNames.length} source types`
|
||||
: selectedItemNames.join(', ');
|
||||
|
||||
if (
|
||||
isDefined(fieldMetadataItemUsedInFilterDropdown) &&
|
||||
isDefined(selectedOperandInDropdown)
|
||||
) {
|
||||
const newFilterValue =
|
||||
newSelectedItemIds.length > 0
|
||||
? JSON.stringify(newSelectedItemIds)
|
||||
: EMPTY_FILTER_VALUE;
|
||||
const newFilterValue =
|
||||
newSelectedItemIds.length > 0
|
||||
? JSON.stringify(newSelectedItemIds)
|
||||
: EMPTY_FILTER_VALUE;
|
||||
|
||||
const duplicateFilterInCurrentRecordFilters =
|
||||
findDuplicateRecordFilterInNonAdvancedRecordFilters({
|
||||
recordFilters: currentRecordFilters,
|
||||
fieldMetadataItemId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
subFieldName: 'source',
|
||||
});
|
||||
|
||||
const filterIsAlreadyInCurrentRecordFilters = isDefined(
|
||||
duplicateFilterInCurrentRecordFilters,
|
||||
);
|
||||
|
||||
const filterId = filterIsAlreadyInCurrentRecordFilters
|
||||
? duplicateFilterInCurrentRecordFilters?.id
|
||||
: v4();
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ? selectedFilter.id : filterId,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInFilterDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInFilterDropdown.label,
|
||||
operand: selectedOperandInDropdown || ViewFilterOperand.Is,
|
||||
displayValue: filterDisplayValue,
|
||||
fieldMetadataId: fieldMetadataItemUsedInFilterDropdown.id,
|
||||
value: newFilterValue,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
subFieldName: 'source',
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
});
|
||||
}
|
||||
applyObjectFilterDropdownFilterValue(newFilterValue, filterDisplayValue);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -9,7 +9,6 @@ import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-rec
|
||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { FiltersHotkeyScope } from '@/object-record/object-filter-dropdown/types/FiltersHotkeyScope';
|
||||
@ -81,10 +80,6 @@ export const ObjectFilterDropdownSubFieldSelect = () => {
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
|
||||
const setSelectedFilter = useSetRecoilComponentStateV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownCurrentRecordFilter =
|
||||
useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
@ -125,8 +120,6 @@ export const ObjectFilterDropdownSubFieldSelect = () => {
|
||||
);
|
||||
|
||||
if (filterIsAlreadyInCurrentRecordFilters) {
|
||||
setSelectedFilter(duplicateFilterInCurrentRecordFilters);
|
||||
|
||||
setObjectFilterDropdownCurrentRecordFilter(
|
||||
duplicateFilterInCurrentRecordFilters,
|
||||
);
|
||||
|
||||
@ -31,6 +31,12 @@ export const ObjectFilterDropdownTextInput = () => {
|
||||
[hasFocused],
|
||||
);
|
||||
|
||||
const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
applyObjectFilterDropdownFilterValue(newValue);
|
||||
};
|
||||
|
||||
return (
|
||||
<DropdownMenuItemsContainer>
|
||||
<DropdownMenuInput
|
||||
@ -39,11 +45,7 @@ export const ObjectFilterDropdownTextInput = () => {
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder={fieldMetadataItemUsedInDropdown?.label}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
const newValue = event.target.value;
|
||||
|
||||
applyObjectFilterDropdownFilterValue(newValue);
|
||||
}}
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
</DropdownMenuItemsContainer>
|
||||
);
|
||||
|
||||
@ -1,80 +0,0 @@
|
||||
import { ChangeEvent, useCallback, useState } from 'react';
|
||||
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { DropdownMenuSearchInput } from '@/ui/layout/dropdown/components/DropdownMenuSearchInput';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
export const ObjectFilterDropdownTextSearchInput = () => {
|
||||
const [hasFocused, setHasFocused] = useState(false);
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownSearchInput = useRecoilComponentValueV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
);
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter();
|
||||
|
||||
const handleInputRef = useCallback(
|
||||
(node: HTMLInputElement | null) => {
|
||||
if (Boolean(node) && !hasFocused) {
|
||||
node?.focus();
|
||||
node?.select();
|
||||
setHasFocused(true);
|
||||
}
|
||||
},
|
||||
[hasFocused],
|
||||
);
|
||||
return (
|
||||
fieldMetadataItemUsedInDropdown &&
|
||||
selectedOperandInDropdown && (
|
||||
<DropdownMenuSearchInput
|
||||
ref={handleInputRef}
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder={fieldMetadataItemUsedInDropdown.label}
|
||||
value={selectedFilter?.value ?? objectFilterDropdownSearchInput}
|
||||
onChange={(event: ChangeEvent<HTMLInputElement>) => {
|
||||
setObjectFilterDropdownSearchInput(event.target.value);
|
||||
|
||||
applyRecordFilter({
|
||||
id: selectedFilter?.id ?? v4(),
|
||||
fieldMetadataId: fieldMetadataItemUsedInDropdown.id,
|
||||
value: event.target.value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: event.target.value,
|
||||
recordFilterGroupId: selectedFilter?.recordFilterGroupId,
|
||||
type: getFilterTypeFromFieldType(
|
||||
fieldMetadataItemUsedInDropdown.type,
|
||||
),
|
||||
label: fieldMetadataItemUsedInDropdown.label,
|
||||
positionInRecordFilterGroup:
|
||||
selectedFilter?.positionInRecordFilterGroup,
|
||||
subFieldName: selectedFilter?.subFieldName,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
@ -25,7 +25,10 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
const { upsertObjectFilterDropdownCurrentFilter } =
|
||||
useUpsertObjectFilterDropdownCurrentFilter();
|
||||
|
||||
const applyObjectFilterDropdownFilterValue = (newFilterValue: string) => {
|
||||
const applyObjectFilterDropdownFilterValue = (
|
||||
newFilterValue: string,
|
||||
newDisplayValue?: string,
|
||||
) => {
|
||||
if (objectFilterDropdownFilterNotYetCreated) {
|
||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||
throw new Error(
|
||||
@ -41,7 +44,7 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
const newCurrentRecordFilter = {
|
||||
...newRecordFilterFromObjectFilterDropdownStates,
|
||||
value: newFilterValue,
|
||||
displayValue: newFilterValue,
|
||||
displayValue: newDisplayValue ?? newFilterValue,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter);
|
||||
@ -49,7 +52,7 @@ export const useApplyObjectFilterDropdownFilterValue = () => {
|
||||
const newCurrentRecordFilter = {
|
||||
...objectFilterDropdownCurrentRecordFilter,
|
||||
value: newFilterValue,
|
||||
displayValue: newFilterValue,
|
||||
displayValue: newDisplayValue ?? newFilterValue,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter);
|
||||
|
||||
@ -0,0 +1,79 @@
|
||||
import { useUpsertObjectFilterDropdownCurrentFilter } from '@/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter';
|
||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useApplyObjectFilterDropdownOperand = () => {
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
);
|
||||
|
||||
const objectFilterDropdownFilterIsCreated = isDefined(
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
);
|
||||
|
||||
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||
);
|
||||
|
||||
const { upsertObjectFilterDropdownCurrentFilter } =
|
||||
useUpsertObjectFilterDropdownCurrentFilter();
|
||||
|
||||
const { createEmptyRecordFilterFromFieldMetadataItem } =
|
||||
useCreateEmptyRecordFilterFromFieldMetadataItem();
|
||||
|
||||
const applyObjectFilterDropdownOperand = (
|
||||
newOperand: RecordFilterOperand,
|
||||
) => {
|
||||
const isValuelessOperand = [
|
||||
RecordFilterOperand.IsEmpty,
|
||||
RecordFilterOperand.IsNotEmpty,
|
||||
RecordFilterOperand.IsInPast,
|
||||
RecordFilterOperand.IsInFuture,
|
||||
RecordFilterOperand.IsToday,
|
||||
].includes(newOperand);
|
||||
|
||||
if (objectFilterDropdownFilterIsCreated) {
|
||||
const newCurrentRecordFilter = {
|
||||
...objectFilterDropdownCurrentRecordFilter,
|
||||
operand: newOperand,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter);
|
||||
} else if (isValuelessOperand) {
|
||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||
throw new Error(
|
||||
'FieldMetadataItemUsedInDropdown is not defined, cannot create empty record filter, this should not happen',
|
||||
);
|
||||
}
|
||||
|
||||
const { newRecordFilter: emptyRecordFilter } =
|
||||
createEmptyRecordFilterFromFieldMetadataItem(
|
||||
fieldMetadataItemUsedInDropdown,
|
||||
);
|
||||
|
||||
const recordFilterToCreate = {
|
||||
...emptyRecordFilter,
|
||||
operand: newOperand,
|
||||
} satisfies RecordFilter;
|
||||
|
||||
upsertObjectFilterDropdownCurrentFilter(recordFilterToCreate);
|
||||
}
|
||||
|
||||
setSelectedOperandInDropdown(newOperand);
|
||||
};
|
||||
|
||||
return {
|
||||
applyObjectFilterDropdownOperand,
|
||||
};
|
||||
};
|
||||
@ -1,6 +1,6 @@
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
|
||||
@ -17,22 +17,23 @@ export const useEmptyRecordFilter = (componentInstanceId?: string) => {
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const selectedFilterCallbackState = useRecoilComponentCallbackStateV2(
|
||||
selectedFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
const objectFilterDropdownCurrentRecordFilter =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const emptyRecordFilter = useRecoilCallback(
|
||||
({ set }) =>
|
||||
() => {
|
||||
set(objectFilterDropdownSearchInputCallbackState, '');
|
||||
set(objectFilterDropdownSelectedRecordIdsCallbackState, []);
|
||||
set(selectedFilterCallbackState, undefined);
|
||||
set(objectFilterDropdownCurrentRecordFilter, undefined);
|
||||
},
|
||||
[
|
||||
objectFilterDropdownSearchInputCallbackState,
|
||||
objectFilterDropdownSelectedRecordIdsCallbackState,
|
||||
selectedFilterCallbackState,
|
||||
objectFilterDropdownCurrentRecordFilter,
|
||||
],
|
||||
);
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-rec
|
||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
@ -28,11 +27,6 @@ export const useResetFilterDropdown = (componentInstanceId?: string) => {
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const selectedFilterCallbackState = useRecoilComponentCallbackStateV2(
|
||||
selectedFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const selectedOperandInDropdownCallbackState =
|
||||
useRecoilComponentCallbackStateV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
@ -62,7 +56,6 @@ export const useResetFilterDropdown = (componentInstanceId?: string) => {
|
||||
() => {
|
||||
set(objectFilterDropdownSearchInputCallbackState, '');
|
||||
set(objectFilterDropdownSelectedRecordIdsCallbackState, []);
|
||||
set(selectedFilterCallbackState, undefined);
|
||||
set(selectedOperandInDropdownCallbackState, null);
|
||||
set(objectFilterDropdownFilterIsSelectedCallbackState, false);
|
||||
set(objectFilterDropdownIsSelectingCompositeFieldCallbackState, false);
|
||||
@ -72,7 +65,6 @@ export const useResetFilterDropdown = (componentInstanceId?: string) => {
|
||||
[
|
||||
objectFilterDropdownSearchInputCallbackState,
|
||||
objectFilterDropdownSelectedRecordIdsCallbackState,
|
||||
selectedFilterCallbackState,
|
||||
selectedOperandInDropdownCallbackState,
|
||||
objectFilterDropdownFilterIsSelectedCallbackState,
|
||||
objectFilterDropdownIsSelectingCompositeFieldCallbackState,
|
||||
|
||||
@ -1,97 +0,0 @@
|
||||
import { useGetFieldMetadataItemById } from '@/object-metadata/hooks/useGetFieldMetadataItemById';
|
||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { useApplyRecordFilter } from '@/object-record/record-filter/hooks/useApplyRecordFilter';
|
||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||
import { SingleRecordPickerHotkeyScope } from '@/object-record/record-picker/single-record-picker/types/SingleRecordPickerHotkeyScope';
|
||||
|
||||
import { getDefaultSubFieldNameForCompositeFilterableFieldType } from '@/object-record/record-filter/utils/getDefaultSubFieldNameForCompositeFilterableFieldType';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
type SelectFilterParams = {
|
||||
fieldMetadataItemId: string;
|
||||
};
|
||||
|
||||
export const useSelectFilterUsedInDropdown = (componentInstanceId?: string) => {
|
||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
||||
selectedOperandInDropdownComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
||||
objectFilterDropdownSearchInputComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
|
||||
const { applyRecordFilter } = useApplyRecordFilter(componentInstanceId);
|
||||
|
||||
const { getFieldMetadataItemById } = useGetFieldMetadataItemById();
|
||||
|
||||
const selectFilterUsedInDropdown = ({
|
||||
fieldMetadataItemId,
|
||||
}: SelectFilterParams) => {
|
||||
setFieldMetadataItemIdUsedInDropdown(fieldMetadataItemId);
|
||||
|
||||
const fieldMetadataItem = getFieldMetadataItemById(fieldMetadataItemId);
|
||||
|
||||
if (!isDefined(fieldMetadataItem)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
fieldMetadataItem.type === 'RELATION' ||
|
||||
fieldMetadataItem.type === 'SELECT'
|
||||
) {
|
||||
setHotkeyScope(SingleRecordPickerHotkeyScope.SingleRecordPicker);
|
||||
}
|
||||
|
||||
const filterType = getFilterTypeFromFieldType(fieldMetadataItem.type);
|
||||
|
||||
const defaultSubFieldName =
|
||||
getDefaultSubFieldNameForCompositeFilterableFieldType(filterType);
|
||||
|
||||
const firstOperand = getRecordFilterOperands({
|
||||
filterType,
|
||||
subFieldName: defaultSubFieldName,
|
||||
})[0];
|
||||
|
||||
setSelectedOperandInDropdown(firstOperand);
|
||||
|
||||
const { value, displayValue } = getInitialFilterValue(
|
||||
filterType,
|
||||
firstOperand,
|
||||
);
|
||||
|
||||
if (value !== '') {
|
||||
applyRecordFilter({
|
||||
id: v4(),
|
||||
fieldMetadataId: fieldMetadataItem.id,
|
||||
displayValue,
|
||||
operand: firstOperand,
|
||||
value,
|
||||
type: filterType,
|
||||
label: fieldMetadataItem.label,
|
||||
subFieldName: defaultSubFieldName,
|
||||
});
|
||||
}
|
||||
|
||||
setObjectFilterDropdownSearchInput('');
|
||||
};
|
||||
|
||||
return {
|
||||
selectFilterUsedInDropdown,
|
||||
};
|
||||
};
|
||||
@ -1,5 +1,4 @@
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||
@ -10,10 +9,6 @@ export const useUpsertObjectFilterDropdownCurrentFilter = () => {
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const setSelectedFilter = useSetRecoilComponentStateV2(
|
||||
selectedFilterComponentState,
|
||||
);
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const upsertObjectFilterDropdownCurrentFilter = (
|
||||
@ -22,7 +17,6 @@ export const useUpsertObjectFilterDropdownCurrentFilter = () => {
|
||||
upsertRecordFilter(recordFilterToUpsert);
|
||||
|
||||
setObjectFilterDropdownCurrentRecordFilter(recordFilterToUpsert);
|
||||
setSelectedFilter(recordFilterToUpsert);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { RecordFilter } from '../../record-filter/types/RecordFilter';
|
||||
|
||||
export const onFilterSelectComponentState = createComponentStateV2<
|
||||
((filter: RecordFilter | null) => void) | undefined
|
||||
>({
|
||||
key: 'onFilterSelectComponentState',
|
||||
defaultValue: undefined,
|
||||
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||
});
|
||||
@ -1,11 +0,0 @@
|
||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||
import { createComponentStateV2 } from '@/ui/utilities/state/component-state/utils/createComponentStateV2';
|
||||
import { RecordFilter } from '../../record-filter/types/RecordFilter';
|
||||
|
||||
export const selectedFilterComponentState = createComponentStateV2<
|
||||
RecordFilter | undefined | null
|
||||
>({
|
||||
key: 'selectedFilterComponentState',
|
||||
defaultValue: undefined,
|
||||
componentInstanceContext: ObjectFilterDropdownComponentInstanceContext,
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||
import { useRecoilComponentCallbackStateV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentCallbackStateV2';
|
||||
|
||||
import { useRecoilCallback } from 'recoil';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useApplyRecordFilter = (componentInstanceId?: string) => {
|
||||
const selectedFilterCallbackState = useRecoilComponentCallbackStateV2(
|
||||
selectedFilterComponentState,
|
||||
componentInstanceId,
|
||||
);
|
||||
|
||||
const { upsertRecordFilter } = useUpsertRecordFilter();
|
||||
|
||||
const applyRecordFilter = useRecoilCallback(
|
||||
({ set }) =>
|
||||
(filter: RecordFilter | null) => {
|
||||
set(selectedFilterCallbackState, filter);
|
||||
|
||||
if (isDefined(filter)) {
|
||||
upsertRecordFilter(filter);
|
||||
}
|
||||
},
|
||||
[selectedFilterCallbackState, upsertRecordFilter],
|
||||
);
|
||||
|
||||
return {
|
||||
applyRecordFilter,
|
||||
};
|
||||
};
|
||||
@ -1,23 +1,16 @@
|
||||
import { useSelectFilterUsedInDropdown } from '@/object-record/object-filter-dropdown/hooks/useSelectFilterUsedInDropdown';
|
||||
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||
import { useRecordIndexContextOrThrow } from '@/object-record/record-index/contexts/RecordIndexContext';
|
||||
import { useOpenDropdownFromOutside } from '@/ui/layout/dropdown/hooks/useOpenDropdownFromOutside';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { useSetEditableFilterChipDropdownStates } from '@/views/hooks/useSetEditableFilterChipDropdownStates';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
const { recordIndexId } = useRecordIndexContextOrThrow();
|
||||
|
||||
const { filterableFieldMetadataItems } =
|
||||
useFilterableFieldMetadataItemsInRecordIndexContext();
|
||||
|
||||
const { selectFilterUsedInDropdown } =
|
||||
useSelectFilterUsedInDropdown(recordIndexId);
|
||||
|
||||
const currentRecordFilters = useRecoilComponentValueV2(
|
||||
currentRecordFiltersComponentState,
|
||||
);
|
||||
@ -60,8 +53,6 @@ export const useOpenRecordFilterChipFromTableHeader = () => {
|
||||
|
||||
upsertRecordFilter(newRecordFilter);
|
||||
|
||||
selectFilterUsedInDropdown({ fieldMetadataItemId });
|
||||
|
||||
setEditableFilterChipDropdownStates(newRecordFilter);
|
||||
openDropdownFromOutside(newRecordFilter.id);
|
||||
};
|
||||
|
||||
@ -69,8 +69,10 @@ export const RelativeDatePickerHeader = (
|
||||
});
|
||||
}}
|
||||
options={RELATIVE_DATE_DIRECTION_SELECT_OPTIONS}
|
||||
fullWidth
|
||||
/>
|
||||
<TextInput
|
||||
width={50}
|
||||
value={textInputValue}
|
||||
onChange={(text) => {
|
||||
const amountString = text.replace(/[^0-9]|^0+/g, '');
|
||||
@ -106,6 +108,7 @@ export const RelativeDatePickerHeader = (
|
||||
});
|
||||
}}
|
||||
options={unitSelectOptions}
|
||||
fullWidth
|
||||
/>
|
||||
</StyledContainer>
|
||||
);
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
|
||||
import { AdvancedFilterRootRecordFilterGroup } from '@/object-record/advanced-filter/components/AdvancedFilterRootRecordFilterGroup';
|
||||
import { useSetAdvancedFilterDropdownStates } from '@/object-record/advanced-filter/hooks/useSetAdvancedFilterDropdownAllRowsStates';
|
||||
import { rootLevelRecordFilterGroupComponentSelector } from '@/object-record/advanced-filter/states/rootLevelRecordFilterGroupComponentSelector';
|
||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
import { AdvancedFilterChip } from '@/views/components/AdvancedFilterChip';
|
||||
@ -12,6 +13,13 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
rootLevelRecordFilterGroupComponentSelector,
|
||||
);
|
||||
|
||||
const { setAdvancedFilterDropdownStates } =
|
||||
useSetAdvancedFilterDropdownStates();
|
||||
|
||||
const handleOpenAdvancedFilterDropdown = () => {
|
||||
setAdvancedFilterDropdownStates();
|
||||
};
|
||||
|
||||
if (!isDefined(rootLevelRecordFilterGroup)) {
|
||||
return null;
|
||||
}
|
||||
@ -25,6 +33,7 @@ export const AdvancedFilterDropdownButton = () => {
|
||||
dropdownOffset={{ y: 8, x: 0 }}
|
||||
dropdownPlacement="bottom-start"
|
||||
dropdownWidth="100%"
|
||||
onOpen={handleOpenAdvancedFilterDropdown}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { HotkeyScope } from '@/ui/utilities/hotkey/types/HotkeyScope';
|
||||
import { VIEW_BAR_FILTER_DROPDOWN_ID } from '@/views/constants/ViewBarFilterDropdownId';
|
||||
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
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 { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||
@ -22,17 +22,19 @@ export const ViewBarFilterDropdown = ({
|
||||
|
||||
const { removeRecordFilter } = useRemoveRecordFilter();
|
||||
|
||||
const selectedFilter = useRecoilComponentValueV2(
|
||||
selectedFilterComponentState,
|
||||
const objectFilterDropdownCurrentRecordFilter = useRecoilComponentValueV2(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState,
|
||||
);
|
||||
|
||||
const handleDropdownClickOutside = () => {
|
||||
const recordFilterIsEmpty =
|
||||
isDefined(selectedFilter) &&
|
||||
isRecordFilterConsideredEmpty(selectedFilter);
|
||||
isDefined(objectFilterDropdownCurrentRecordFilter) &&
|
||||
isRecordFilterConsideredEmpty(objectFilterDropdownCurrentRecordFilter);
|
||||
|
||||
if (recordFilterIsEmpty) {
|
||||
removeRecordFilter({ recordFilterId: selectedFilter.id });
|
||||
removeRecordFilter({
|
||||
recordFilterId: objectFilterDropdownCurrentRecordFilter.id,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@ import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record
|
||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||
import { objectFilterDropdownSelectedOptionValuesComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedOptionValuesComponentState';
|
||||
import { objectFilterDropdownSelectedRecordIdsComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSelectedRecordIdsComponentState';
|
||||
import { selectedFilterComponentState } from '@/object-record/object-filter-dropdown/states/selectedFilterComponentState';
|
||||
import { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||
import { useFilterableFieldMetadataItemsInRecordIndexContext } from '@/object-record/record-filter/hooks/useFilterableFieldMetadataItemsInRecordIndexContext';
|
||||
@ -42,13 +41,6 @@ export const useSetEditableFilterChipDropdownStates = () => {
|
||||
recordFilter.operand,
|
||||
);
|
||||
|
||||
set(
|
||||
selectedFilterComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
}),
|
||||
recordFilter,
|
||||
);
|
||||
|
||||
set(
|
||||
objectFilterDropdownCurrentRecordFilterComponentState.atomFamily({
|
||||
instanceId: recordFilter.id,
|
||||
|
||||
Reference in New Issue
Block a user