Fix advanced filter dropdown input components (#11381)
This PR fixes the filter value input components that are used in advanced dropdown filter, which slightly differ from the classic object filter dropdown in the view bar. We notably needed the same experience as other text inputs in the application, for entering filter values. ## New text and number filter experience : <img width="681" alt="image" src="https://github.com/user-attachments/assets/b373bb6b-dc00-4396-9294-9b866b91fa02" /> ## New date filter experience : <img width="683" alt="image" src="https://github.com/user-attachments/assets/8aea22e2-6f3b-4641-9f3d-6d7ba537bc27" /> To obtain the same experience for date input as in workflow forms, it would require to duplicate or factorize a lot of complex code that manipulates dates and user events with the input, it would be better tackled in another issue related to a larger refactor effort : https://github.com/twentyhq/core-team-issues/issues/736 Fixes https://github.com/twentyhq/core-team-issues/issues/674
This commit is contained in:
@ -1,21 +1,23 @@
|
|||||||
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups';
|
import { useChildRecordFiltersAndRecordFilterGroups } from '@/object-record/advanced-filter/hooks/useChildRecordFiltersAndRecordFilterGroups';
|
||||||
import { useDefaultFieldMetadataItemForFilter } from '@/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter';
|
import { useDefaultFieldMetadataItemForFilter } from '@/object-record/advanced-filter/hooks/useDefaultFieldMetadataItemForFilter';
|
||||||
|
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
|
||||||
import { getAdvancedFilterAddFilterRuleSelectDropdownId } from '@/object-record/advanced-filter/utils/getAdvancedFilterAddFilterRuleSelectDropdownId';
|
import { getAdvancedFilterAddFilterRuleSelectDropdownId } from '@/object-record/advanced-filter/utils/getAdvancedFilterAddFilterRuleSelectDropdownId';
|
||||||
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
import { useUpsertRecordFilterGroup } from '@/object-record/record-filter-group/hooks/useUpsertRecordFilterGroup';
|
||||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||||
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-group/types/RecordFilterGroupLogicalOperator';
|
||||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
import { IconLibraryPlus, IconPlus } from 'twenty-ui/display';
|
import { IconLibraryPlus, IconPlus } from 'twenty-ui/display';
|
||||||
import { LightButton } from 'twenty-ui/input';
|
import { LightButton } from 'twenty-ui/input';
|
||||||
import { MenuItem } from 'twenty-ui/navigation';
|
import { MenuItem } from 'twenty-ui/navigation';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
type AdvancedFilterAddFilterRuleSelectProps = {
|
type AdvancedFilterAddFilterRuleSelectProps = {
|
||||||
recordFilterGroup: RecordFilterGroup;
|
recordFilterGroup: RecordFilterGroup;
|
||||||
@ -45,6 +47,9 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
const { defaultFieldMetadataItemForFilter } =
|
const { defaultFieldMetadataItemForFilter } =
|
||||||
useDefaultFieldMetadataItemForFilter();
|
useDefaultFieldMetadataItemForFilter();
|
||||||
|
|
||||||
|
const { setRecordFilterUsedInAdvancedFilterDropdownRow } =
|
||||||
|
useSetRecordFilterUsedInAdvancedFilterDropdownRow();
|
||||||
|
|
||||||
const handleAddFilter = () => {
|
const handleAddFilter = () => {
|
||||||
if (!isDefined(defaultFieldMetadataItemForFilter)) {
|
if (!isDefined(defaultFieldMetadataItemForFilter)) {
|
||||||
throw new Error('Missing default field metadata item for filter');
|
throw new Error('Missing default field metadata item for filter');
|
||||||
@ -56,7 +61,7 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
defaultFieldMetadataItemForFilter.type,
|
defaultFieldMetadataItemForFilter.type,
|
||||||
);
|
);
|
||||||
|
|
||||||
upsertRecordFilter({
|
const newRecordFilter: RecordFilter = {
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFieldMetadataItemForFilter.id,
|
fieldMetadataId: defaultFieldMetadataItemForFilter.id,
|
||||||
type: filterType,
|
type: filterType,
|
||||||
@ -68,7 +73,11 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
recordFilterGroupId: recordFilterGroup.id,
|
recordFilterGroupId: recordFilterGroup.id,
|
||||||
positionInRecordFilterGroup: newPositionInRecordFilterGroup,
|
positionInRecordFilterGroup: newPositionInRecordFilterGroup,
|
||||||
label: defaultFieldMetadataItemForFilter.label,
|
label: defaultFieldMetadataItemForFilter.label,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
upsertRecordFilter(newRecordFilter);
|
||||||
|
|
||||||
|
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAddFilterGroup = () => {
|
const handleAddFilterGroup = () => {
|
||||||
@ -97,7 +106,7 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
defaultFieldMetadataItemForFilter.type,
|
defaultFieldMetadataItemForFilter.type,
|
||||||
);
|
);
|
||||||
|
|
||||||
upsertRecordFilter({
|
const newRecordFilter: RecordFilter = {
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFieldMetadataItemForFilter.id,
|
fieldMetadataId: defaultFieldMetadataItemForFilter.id,
|
||||||
type: filterType,
|
type: filterType,
|
||||||
@ -109,7 +118,11 @@ export const AdvancedFilterAddFilterRuleSelect = ({
|
|||||||
recordFilterGroupId: newRecordFilterGroupId,
|
recordFilterGroupId: newRecordFilterGroupId,
|
||||||
positionInRecordFilterGroup: 1,
|
positionInRecordFilterGroup: 1,
|
||||||
label: defaultFieldMetadataItemForFilter.label,
|
label: defaultFieldMetadataItemForFilter.label,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
upsertRecordFilter(newRecordFilter);
|
||||||
|
|
||||||
|
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isFilterRuleGroupOptionVisible = !isDefined(
|
const isFilterRuleGroupOptionVisible = !isDefined(
|
||||||
|
|||||||
@ -0,0 +1,122 @@
|
|||||||
|
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}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { ObjectFilterDropdownOptionSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownOptionSelect';
|
||||||
|
import { ObjectFilterDropdownRatingInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
||||||
|
import { ObjectFilterDropdownRecordSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRecordSelect';
|
||||||
|
import { ObjectFilterDropdownSearchInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSearchInput';
|
||||||
|
import { ObjectFilterDropdownSourceSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownSourceSelect';
|
||||||
|
import { DropdownMenuSeparator } from '@/ui/layout/dropdown/components/DropdownMenuSeparator';
|
||||||
|
|
||||||
|
import { getFilterTypeFromFieldType } from '@/object-metadata/utils/formatFieldMetadataItemsAsFilterDefinitions';
|
||||||
|
import { AdvancedFilterDropdownDateInput } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownDateInput';
|
||||||
|
import { ObjectFilterDropdownBooleanSelect } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownBooleanSelect';
|
||||||
|
import { ObjectFilterDropdownTextInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownTextInput';
|
||||||
|
import { DATE_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/DateFilterTypes';
|
||||||
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
|
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
||||||
|
import { isFilterOnActorSourceSubField } from '@/object-record/object-filter-dropdown/utils/isFilterOnActorSourceSubField';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
type AdvancedFilterDropdownFilterInputProps = {
|
||||||
|
filterDropdownId?: string;
|
||||||
|
recordFilterId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AdvancedFilterDropdownFilterInput = ({
|
||||||
|
filterDropdownId,
|
||||||
|
recordFilterId,
|
||||||
|
}: AdvancedFilterDropdownFilterInputProps) => {
|
||||||
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
|
filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const subFieldNameUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
subFieldNameUsedInDropdownComponentState,
|
||||||
|
filterDropdownId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterType = getFilterTypeFromFieldType(
|
||||||
|
fieldMetadataItemUsedInDropdown.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isActorSourceCompositeFilter = isFilterOnActorSourceSubField(
|
||||||
|
subFieldNameUsedInDropdown,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{filterType === 'RATING' && <ObjectFilterDropdownRatingInput />}
|
||||||
|
{DATE_FILTER_TYPES.includes(filterType) && (
|
||||||
|
<AdvancedFilterDropdownDateInput />
|
||||||
|
)}
|
||||||
|
{filterType === 'RELATION' && (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownSearchInput />
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ObjectFilterDropdownRecordSelect recordFilterId={recordFilterId} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{filterType === 'ACTOR' &&
|
||||||
|
(isActorSourceCompositeFilter ? (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownSourceSelect />
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownTextInput />
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
{['SELECT', 'MULTI_SELECT'].includes(filterType) && (
|
||||||
|
<>
|
||||||
|
<ObjectFilterDropdownSearchInput />
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<ObjectFilterDropdownOptionSelect />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{filterType === 'BOOLEAN' && <ObjectFilterDropdownBooleanSelect />}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
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 { 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(
|
||||||
|
selectedOperandInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedFilter = useRecoilComponentValueV2(
|
||||||
|
selectedFilterComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { applyRecordFilter } = useApplyRecordFilter();
|
||||||
|
|
||||||
|
const [inputValue, setInputValue] = useState(
|
||||||
|
() => selectedFilter?.value || '',
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!selectedOperandInDropdown || !fieldMetadataItemUsedInDropdown) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextInputV2
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Enter value"
|
||||||
|
fullWidth
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
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 { TextInputV2 } from '@/ui/input/components/TextInputV2';
|
||||||
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
|
export const AdvancedFilterDropdownTextInput = () => {
|
||||||
|
const selectedOperandInDropdown = useRecoilComponentValueV2(
|
||||||
|
selectedOperandInDropdownComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const fieldMetadataItemUsedInDropdown = useRecoilComponentValueV2(
|
||||||
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedFilter = useRecoilComponentValueV2(
|
||||||
|
selectedFilterComponentState,
|
||||||
|
);
|
||||||
|
|
||||||
|
const { applyRecordFilter } = useApplyRecordFilter();
|
||||||
|
|
||||||
|
const [inputValue, setInputValue] = useState(
|
||||||
|
() => selectedFilter?.value || '',
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!selectedOperandInDropdown || !fieldMetadataItemUsedInDropdown) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextInputV2
|
||||||
|
value={inputValue}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="Enter value"
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@ -3,7 +3,8 @@ import { AdvancedFilterFieldSelectDropdownButton } from '@/object-record/advance
|
|||||||
import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell';
|
import { AdvancedFilterLogicalOperatorCell } from '@/object-record/advanced-filter/components/AdvancedFilterLogicalOperatorCell';
|
||||||
import { AdvancedFilterRecordFilterOperandSelect } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect';
|
import { AdvancedFilterRecordFilterOperandSelect } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOperandSelect';
|
||||||
import { AdvancedFilterRecordFilterOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown';
|
import { AdvancedFilterRecordFilterOptionsDropdown } from '@/object-record/advanced-filter/components/AdvancedFilterRecordFilterOptionsDropdown';
|
||||||
import { AdvancedFilterValueInputDropdownButton } from '@/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButton';
|
import { AdvancedFilterValueInput } from '@/object-record/advanced-filter/components/AdvancedFilterValueInput';
|
||||||
|
import { getAdvancedFilterObjectFilterDropdownComponentInstanceId } from '@/object-record/advanced-filter/utils/getAdvancedFilterObjectFilterDropdownComponentInstanceId';
|
||||||
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
import { ObjectFilterDropdownComponentInstanceContext } from '@/object-record/object-filter-dropdown/states/contexts/ObjectFilterDropdownComponentInstanceContext';
|
||||||
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
import { RecordFilterGroup } from '@/object-record/record-filter-group/types/RecordFilterGroup';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
@ -19,7 +20,11 @@ export const AdvancedFilterRecordFilterRow = ({
|
|||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ObjectFilterDropdownComponentInstanceContext.Provider
|
<ObjectFilterDropdownComponentInstanceContext.Provider
|
||||||
value={{ instanceId: `advanced-filter-${recordFilter.id}` }}
|
value={{
|
||||||
|
instanceId: getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||||
|
recordFilter.id,
|
||||||
|
),
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<AdvancedFilterDropdownRow>
|
<AdvancedFilterDropdownRow>
|
||||||
<AdvancedFilterLogicalOperatorCell
|
<AdvancedFilterLogicalOperatorCell
|
||||||
@ -32,9 +37,7 @@ export const AdvancedFilterRecordFilterRow = ({
|
|||||||
<AdvancedFilterRecordFilterOperandSelect
|
<AdvancedFilterRecordFilterOperandSelect
|
||||||
recordFilterId={recordFilter.id}
|
recordFilterId={recordFilter.id}
|
||||||
/>
|
/>
|
||||||
<AdvancedFilterValueInputDropdownButton
|
<AdvancedFilterValueInput recordFilterId={recordFilter.id} />
|
||||||
recordFilterId={recordFilter.id}
|
|
||||||
/>
|
|
||||||
<AdvancedFilterRecordFilterOptionsDropdown
|
<AdvancedFilterRecordFilterOptionsDropdown
|
||||||
recordFilterId={recordFilter.id}
|
recordFilterId={recordFilter.id}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||||
|
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
import { FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||||
import { useAdvancedFilterFieldSelectDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterFieldSelectDropdown';
|
import { useAdvancedFilterFieldSelectDropdown } from '@/object-record/advanced-filter/hooks/useAdvancedFilterFieldSelectDropdown';
|
||||||
import { useSelectFieldUsedInAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown';
|
import { useSelectFieldUsedInAdvancedFilterDropdown } from '@/object-record/advanced-filter/hooks/useSelectFieldUsedInAdvancedFilterDropdown';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { objectFilterDropdownFilterIsSelectedComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownFilterIsSelectedComponentState';
|
|
||||||
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
import { objectFilterDropdownIsSelectingCompositeFieldComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownIsSelectingCompositeFieldComponentState';
|
||||||
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
import { objectFilterDropdownSubMenuFieldTypeComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSubMenuFieldTypeComponentState';
|
||||||
import { subFieldNameUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/subFieldNameUsedInDropdownComponentState';
|
|
||||||
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
||||||
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
import { getFilterableFieldTypeLabel } from '@/object-record/object-filter-dropdown/utils/getFilterableFieldTypeLabel';
|
||||||
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
import { SETTINGS_COMPOSITE_FIELD_TYPE_CONFIGS } from '@/settings/data-model/constants/SettingsCompositeFieldTypeConfigs';
|
||||||
@ -35,14 +31,6 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
|||||||
fieldMetadataItemUsedInDropdownComponentSelector,
|
fieldMetadataItemUsedInDropdownComponentSelector,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [, setObjectFilterDropdownFilterIsSelected] = useRecoilComponentStateV2(
|
|
||||||
objectFilterDropdownFilterIsSelectedComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setSubFieldNameUsedInDropdown] = useRecoilComponentStateV2(
|
|
||||||
subFieldNameUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const [, setObjectFilterDropdownIsSelectingCompositeField] =
|
const [, setObjectFilterDropdownIsSelectingCompositeField] =
|
||||||
useRecoilComponentStateV2(
|
useRecoilComponentStateV2(
|
||||||
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
objectFilterDropdownIsSelectingCompositeFieldComponentState,
|
||||||
@ -55,10 +43,6 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
|||||||
objectFilterDropdownSubMenuFieldTypeComponentState,
|
objectFilterDropdownSubMenuFieldTypeComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { closeAdvancedFilterFieldSelectDropdown } =
|
const { closeAdvancedFilterFieldSelectDropdown } =
|
||||||
useAdvancedFilterFieldSelectDropdown(recordFilterId);
|
useAdvancedFilterFieldSelectDropdown(recordFilterId);
|
||||||
|
|
||||||
@ -83,11 +67,8 @@ export const AdvancedFilterSubFieldSelectMenu = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubMenuBack = () => {
|
const handleSubMenuBack = () => {
|
||||||
setFieldMetadataItemIdUsedInDropdown(null);
|
|
||||||
setObjectFilterDropdownSubMenuFieldType(null);
|
setObjectFilterDropdownSubMenuFieldType(null);
|
||||||
setObjectFilterDropdownIsSelectingCompositeField(false);
|
setObjectFilterDropdownIsSelectingCompositeField(false);
|
||||||
setObjectFilterDropdownFilterIsSelected(false);
|
|
||||||
setSubFieldNameUsedInDropdown(null);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isDefined(objectFilterDropdownSubMenuFieldType)) {
|
if (!isDefined(objectFilterDropdownSubMenuFieldType)) {
|
||||||
|
|||||||
@ -1,64 +1,61 @@
|
|||||||
|
import { AdvancedFilterDropdownFilterInput } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownFilterInput';
|
||||||
|
import { AdvancedFilterDropdownTextInput } from '@/object-record/advanced-filter/components/AdvancedFilterDropdownTextInput';
|
||||||
import { AdvancedFilterValueInputDropdownButtonClickableSelect } from '@/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect';
|
import { AdvancedFilterValueInputDropdownButtonClickableSelect } from '@/object-record/advanced-filter/components/AdvancedFilterValueInputDropdownButtonClickableSelect';
|
||||||
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
import { DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET } from '@/object-record/advanced-filter/constants/DefaultAdvancedFilterDropdownOffset';
|
||||||
import { ObjectFilterDropdownFilterInput } from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownFilterInput';
|
import { NUMBER_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/NumberFilterTypes';
|
||||||
import { fieldMetadataItemIdUsedInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemIdUsedInDropdownComponentState';
|
import { TEXT_FILTER_TYPES } from '@/object-record/object-filter-dropdown/constants/TextFilterTypes';
|
||||||
import { objectFilterDropdownSearchInputComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownSearchInputComponentState';
|
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 { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands';
|
import { configurableViewFilterOperands } from '@/object-record/object-filter-dropdown/utils/configurableViewFilterOperands';
|
||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||||
|
import { DropdownOffset } from '@/ui/layout/dropdown/types/DropdownOffset';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
import { useSetRecoilComponentStateV2 } from '@/ui/utilities/state/component-state/hooks/useSetRecoilComponentStateV2';
|
||||||
|
|
||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
const StyledValueDropdownContainer = styled.div`
|
const StyledValueDropdownContainer = styled.div`
|
||||||
flex: 3;
|
flex: 3;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
type AdvancedFilterValueInputDropdownButtonProps = {
|
type AdvancedFilterValueInputProps = {
|
||||||
recordFilterId: string;
|
recordFilterId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AdvancedFilterValueInputDropdownButton = ({
|
export const AdvancedFilterValueInput = ({
|
||||||
recordFilterId,
|
recordFilterId,
|
||||||
}: AdvancedFilterValueInputDropdownButtonProps) => {
|
}: AdvancedFilterValueInputProps) => {
|
||||||
const dropdownId = `advanced-filter-view-filter-value-input-${recordFilterId}`;
|
const dropdownId = `advanced-filter-view-filter-value-input-${recordFilterId}`;
|
||||||
|
|
||||||
const currentRecordFilters = useRecoilComponentValueV2(
|
const currentRecordFilters = useRecoilComponentValueV2(
|
||||||
currentRecordFiltersComponentState,
|
currentRecordFiltersComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const filter = currentRecordFilters.find(
|
const recordFilter = currentRecordFilters.find(
|
||||||
(recordFilter) => recordFilter.id === recordFilterId,
|
(recordFilter) => recordFilter.id === recordFilterId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const isDisabled = !filter?.fieldMetadataId || !filter.operand;
|
const isDisabled = !recordFilter?.fieldMetadataId || !recordFilter.operand;
|
||||||
|
|
||||||
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
const setObjectFilterDropdownSearchInput = useSetRecoilComponentStateV2(
|
||||||
objectFilterDropdownSearchInputComponentState,
|
objectFilterDropdownSearchInputComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const setFieldMetadataItemIdUsedInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
fieldMetadataItemIdUsedInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedOperandInDropdown = useSetRecoilComponentStateV2(
|
|
||||||
selectedOperandInDropdownComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedFilter = useSetRecoilComponentStateV2(
|
|
||||||
selectedFilterComponentState,
|
|
||||||
);
|
|
||||||
|
|
||||||
const operandHasNoInput =
|
const operandHasNoInput =
|
||||||
filter && !configurableViewFilterOperands.has(filter.operand);
|
recordFilter && !configurableViewFilterOperands.has(recordFilter.operand);
|
||||||
|
|
||||||
const handleFilterValueDropdownClose = () => {
|
const handleFilterValueDropdownClose = () => {
|
||||||
setObjectFilterDropdownSearchInput('');
|
setObjectFilterDropdownSearchInput('');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const filterType = recordFilter?.type;
|
||||||
|
|
||||||
|
const dropdownContentOffset =
|
||||||
|
filterType === 'DATE' || filterType === 'DATE_TIME'
|
||||||
|
? ({ y: -33, x: 0 } satisfies DropdownOffset)
|
||||||
|
: DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledValueDropdownContainer>
|
<StyledValueDropdownContainer>
|
||||||
{operandHasNoInput ? (
|
{operandHasNoInput ? (
|
||||||
@ -67,6 +64,10 @@ export const AdvancedFilterValueInputDropdownButton = ({
|
|||||||
<AdvancedFilterValueInputDropdownButtonClickableSelect
|
<AdvancedFilterValueInputDropdownButtonClickableSelect
|
||||||
recordFilterId={recordFilterId}
|
recordFilterId={recordFilterId}
|
||||||
/>
|
/>
|
||||||
|
) : isDefined(filterType) &&
|
||||||
|
(TEXT_FILTER_TYPES.includes(filterType) ||
|
||||||
|
NUMBER_FILTER_TYPES.includes(filterType)) ? (
|
||||||
|
<AdvancedFilterDropdownTextInput />
|
||||||
) : (
|
) : (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
dropdownId={dropdownId}
|
dropdownId={dropdownId}
|
||||||
@ -75,16 +76,13 @@ export const AdvancedFilterValueInputDropdownButton = ({
|
|||||||
recordFilterId={recordFilterId}
|
recordFilterId={recordFilterId}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
onOpen={() => {
|
|
||||||
setFieldMetadataItemIdUsedInDropdown(filter.fieldMetadataId);
|
|
||||||
setSelectedOperandInDropdown(filter.operand);
|
|
||||||
setSelectedFilter(filter);
|
|
||||||
}}
|
|
||||||
dropdownComponents={
|
dropdownComponents={
|
||||||
<ObjectFilterDropdownFilterInput recordFilterId={filter.id} />
|
<AdvancedFilterDropdownFilterInput
|
||||||
|
recordFilterId={recordFilter.id}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
dropdownHotkeyScope={{ scope: dropdownId }}
|
dropdownHotkeyScope={{ scope: dropdownId }}
|
||||||
dropdownOffset={DEFAULT_ADVANCED_FILTER_DROPDOWN_OFFSET}
|
dropdownOffset={dropdownContentOffset}
|
||||||
dropdownPlacement="bottom-start"
|
dropdownPlacement="bottom-start"
|
||||||
dropdownMenuWidth={280}
|
dropdownMenuWidth={280}
|
||||||
onClose={handleFilterValueDropdownClose}
|
onClose={handleFilterValueDropdownClose}
|
||||||
@ -3,10 +3,30 @@ import { getAdvancedFilterInputPlaceholderText } from '@/object-record/advanced-
|
|||||||
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
import { currentRecordFiltersComponentState } from '@/object-record/record-filter/states/currentRecordFiltersComponentState';
|
||||||
import { SelectControl } from '@/ui/input/components/SelectControl';
|
import { SelectControl } from '@/ui/input/components/SelectControl';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
|
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
|
|
||||||
|
import styled from '@emotion/styled';
|
||||||
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
|
||||||
|
// TODO: factorize this with https://github.com/twentyhq/core-team-issues/issues/752
|
||||||
|
const StyledControlContainer = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: ${({ theme }) => theme.spacing(1)};
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: ${({ theme }) => theme.spacing(8)};
|
||||||
|
max-width: 100%;
|
||||||
|
padding: 0 ${({ theme }) => theme.spacing(2)};
|
||||||
|
background-color: ${({ theme }) => theme.background.transparent.lighter};
|
||||||
|
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||||
|
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||||
|
color: ${({ theme }) => theme.font.color.primary};
|
||||||
|
cursor: pointer;
|
||||||
|
text-align: left;
|
||||||
|
`;
|
||||||
|
|
||||||
type AdvancedFilterValueInputDropdownButtonClickableSelectProps = {
|
type AdvancedFilterValueInputDropdownButtonClickableSelectProps = {
|
||||||
recordFilterId: string;
|
recordFilterId: string;
|
||||||
};
|
};
|
||||||
@ -42,7 +62,12 @@ export const AdvancedFilterValueInputDropdownButtonClickableSelect = ({
|
|||||||
? placeholderText
|
? placeholderText
|
||||||
: (recordFilter?.displayValue ?? '');
|
: (recordFilter?.displayValue ?? '');
|
||||||
|
|
||||||
return (
|
const isDateTimeType =
|
||||||
|
recordFilter?.type === 'DATE' || recordFilter?.type === 'DATE_TIME';
|
||||||
|
|
||||||
|
return isDateTimeType ? (
|
||||||
|
<StyledControlContainer>{advancedFilterInputText}</StyledControlContainer>
|
||||||
|
) : (
|
||||||
<SelectControl
|
<SelectControl
|
||||||
selectedOption={{
|
selectedOption={{
|
||||||
label: advancedFilterInputText,
|
label: advancedFilterInputText,
|
||||||
@ -50,6 +75,7 @@ export const AdvancedFilterValueInputDropdownButtonClickableSelect = ({
|
|||||||
disabled: isDisabled,
|
disabled: isDisabled,
|
||||||
}}
|
}}
|
||||||
textAccent={shouldUsePlaceholder ? 'placeholder' : 'default'}
|
textAccent={shouldUsePlaceholder ? 'placeholder' : 'default'}
|
||||||
|
isDisabled={isDateTimeType}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
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 { selectedOperandInDropdownComponentState } from '@/object-record/object-filter-dropdown/states/selectedOperandInDropdownComponentState';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { useRecoilCallback } from 'recoil';
|
||||||
|
|
||||||
|
export const useSetRecordFilterUsedInAdvancedFilterDropdownRow = () => {
|
||||||
|
const setRecordFilterUsedInAdvancedFilterDropdownRow = useRecoilCallback(
|
||||||
|
({ set }) =>
|
||||||
|
(recordFilter: RecordFilter) => {
|
||||||
|
const advancedFilterRowObjectFilterDropdownComponentInstanceId =
|
||||||
|
getAdvancedFilterObjectFilterDropdownComponentInstanceId(
|
||||||
|
recordFilter.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
set(
|
||||||
|
fieldMetadataItemIdUsedInDropdownComponentState.atomFamily({
|
||||||
|
instanceId:
|
||||||
|
advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||||
|
}),
|
||||||
|
recordFilter.fieldMetadataId,
|
||||||
|
);
|
||||||
|
|
||||||
|
set(
|
||||||
|
selectedOperandInDropdownComponentState.atomFamily({
|
||||||
|
instanceId:
|
||||||
|
advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||||
|
}),
|
||||||
|
recordFilter.operand,
|
||||||
|
);
|
||||||
|
|
||||||
|
set(
|
||||||
|
selectedFilterComponentState.atomFamily({
|
||||||
|
instanceId:
|
||||||
|
advancedFilterRowObjectFilterDropdownComponentInstanceId,
|
||||||
|
}),
|
||||||
|
recordFilter,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
setRecordFilterUsedInAdvancedFilterDropdownRow,
|
||||||
|
};
|
||||||
|
};
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
export const getAdvancedFilterObjectFilterDropdownComponentInstanceId = (
|
||||||
|
recordFilterId: string,
|
||||||
|
) => {
|
||||||
|
return `advanced-filter-${recordFilterId}`;
|
||||||
|
};
|
||||||
@ -8,6 +8,8 @@ import { RecordFilterGroupLogicalOperator } from '@/object-record/record-filter-
|
|||||||
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
import { useUpsertRecordFilter } from '@/object-record/record-filter/hooks/useUpsertRecordFilter';
|
||||||
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
import { getRecordFilterOperands } from '@/object-record/record-filter/utils/getRecordFilterOperands';
|
||||||
|
|
||||||
|
import { useSetRecordFilterUsedInAdvancedFilterDropdownRow } from '@/object-record/advanced-filter/hooks/useSetRecordFilterUsedInAdvancedFilterDropdownRow';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
import { useDropdown } from '@/ui/layout/dropdown/hooks/useDropdown';
|
||||||
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
import { useRecoilComponentValueV2 } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValueV2';
|
||||||
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
import { ADVANCED_FILTER_DROPDOWN_ID } from '@/views/constants/AdvancedFilterDropdownId';
|
||||||
@ -16,11 +18,11 @@ import { ViewFilterGroupLogicalOperator } from '@/views/types/ViewFilterGroupLog
|
|||||||
import styled from '@emotion/styled';
|
import styled from '@emotion/styled';
|
||||||
import { useLingui } from '@lingui/react/macro';
|
import { useLingui } from '@lingui/react/macro';
|
||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
|
import { Pill } from 'twenty-ui/components';
|
||||||
import { IconFilter } from 'twenty-ui/display';
|
import { IconFilter } from 'twenty-ui/display';
|
||||||
import { MenuItemLeftContent, StyledMenuItemBase } from 'twenty-ui/navigation';
|
import { MenuItemLeftContent, StyledMenuItemBase } from 'twenty-ui/navigation';
|
||||||
import { Pill } from 'twenty-ui/components';
|
import { v4 } from 'uuid';
|
||||||
|
|
||||||
export const StyledContainer = styled.div`
|
export const StyledContainer = styled.div`
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -80,6 +82,9 @@ export const AdvancedFilterButton = () => {
|
|||||||
currentRecordFilterGroupsComponentState,
|
currentRecordFilterGroupsComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { setRecordFilterUsedInAdvancedFilterDropdownRow } =
|
||||||
|
useSetRecordFilterUsedInAdvancedFilterDropdownRow();
|
||||||
|
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
if (!isDefined(currentView)) {
|
if (!isDefined(currentView)) {
|
||||||
throw new Error('Missing current view id');
|
throw new Error('Missing current view id');
|
||||||
@ -118,7 +123,7 @@ export const AdvancedFilterButton = () => {
|
|||||||
filterType,
|
filterType,
|
||||||
})[0];
|
})[0];
|
||||||
|
|
||||||
upsertRecordFilter({
|
const newRecordFilter: RecordFilter = {
|
||||||
id: v4(),
|
id: v4(),
|
||||||
fieldMetadataId: defaultFieldMetadataItem.id,
|
fieldMetadataId: defaultFieldMetadataItem.id,
|
||||||
operand: firstOperand,
|
operand: firstOperand,
|
||||||
@ -128,7 +133,11 @@ export const AdvancedFilterButton = () => {
|
|||||||
type: getFilterTypeFromFieldType(defaultFieldMetadataItem.type),
|
type: getFilterTypeFromFieldType(defaultFieldMetadataItem.type),
|
||||||
label: defaultFieldMetadataItem.label,
|
label: defaultFieldMetadataItem.label,
|
||||||
positionInRecordFilterGroup: 1,
|
positionInRecordFilterGroup: 1,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
upsertRecordFilter(newRecordFilter);
|
||||||
|
|
||||||
|
setRecordFilterUsedInAdvancedFilterDropdownRow(newRecordFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeObjectFilterDropdown();
|
closeObjectFilterDropdown();
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { SelectOption } from 'twenty-ui/input';
|
|||||||
|
|
||||||
export type SelectControlTextAccent = 'default' | 'placeholder';
|
export type SelectControlTextAccent = 'default' | 'placeholder';
|
||||||
|
|
||||||
|
// TODO: factorize this with https://github.com/twentyhq/core-team-issues/issues/752
|
||||||
const StyledControlContainer = styled.div<{
|
const StyledControlContainer = styled.div<{
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
hasIcon: boolean;
|
hasIcon: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user