Solves issue #5917. This PR is now ready for the first review! Filters do not fully work yet, there's a problem applying multiple filters like the following: ``` { and: [ { [correspondingField.name]: { gte: start.toISOString(), } as DateFilter, }, { [correspondingField.name]: { lte: end.toISOString(), } as DateFilter, }, ], } ``` I'll do my best to dig into it tonight! --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
@ -54,11 +54,20 @@ export const MultipleFiltersDropdownContent = ({
|
||||
selectedOperandInDropdownState,
|
||||
);
|
||||
|
||||
const isEmptyOperand =
|
||||
const isConfigurable =
|
||||
selectedOperandInDropdown &&
|
||||
[ViewFilterOperand.IsEmpty, ViewFilterOperand.IsNotEmpty].includes(
|
||||
selectedOperandInDropdown,
|
||||
);
|
||||
[
|
||||
ViewFilterOperand.Is,
|
||||
ViewFilterOperand.IsNotNull,
|
||||
ViewFilterOperand.IsNot,
|
||||
ViewFilterOperand.LessThan,
|
||||
ViewFilterOperand.GreaterThan,
|
||||
ViewFilterOperand.IsBefore,
|
||||
ViewFilterOperand.IsAfter,
|
||||
ViewFilterOperand.Contains,
|
||||
ViewFilterOperand.DoesNotContain,
|
||||
ViewFilterOperand.IsRelative,
|
||||
].includes(selectedOperandInDropdown);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
@ -72,7 +81,7 @@ export const MultipleFiltersDropdownContent = ({
|
||||
<ObjectFilterDropdownOperandSelect />
|
||||
</StyledOperandSelectContainer>
|
||||
)}
|
||||
{!isEmptyOperand && selectedOperandInDropdown && (
|
||||
{isConfigurable && selectedOperandInDropdown && (
|
||||
<>
|
||||
{[
|
||||
'TEXT',
|
||||
|
||||
@ -2,10 +2,19 @@ import { useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||
import { getRelativeDateDisplayValue } from '@/object-record/object-filter-dropdown/utils/getRelativeDateDisplayValue';
|
||||
import { InternalDatePicker } from '@/ui/input/components/internal/date/components/InternalDatePicker';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { computeVariableDateViewFilterValue } from '@/views/utils/view-filter-value/computeVariableDateViewFilterValue';
|
||||
import {
|
||||
VariableDateViewFilterValueDirection,
|
||||
VariableDateViewFilterValueUnit,
|
||||
} from '@/views/utils/view-filter-value/resolveDateViewFilterValue';
|
||||
import { resolveFilterValue } from '@/views/utils/view-filter-value/resolveFilterValue';
|
||||
import { useState } from 'react';
|
||||
import { isDefined } from 'twenty-ui';
|
||||
import { FieldMetadataType } from '~/generated-metadata/graphql';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
export const ObjectFilterDropdownDateInput = () => {
|
||||
const {
|
||||
@ -23,28 +32,35 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
selectedOperandInDropdownState,
|
||||
);
|
||||
|
||||
const selectedFilter = useRecoilValue(selectedFilterState);
|
||||
const selectedFilter = useRecoilValue(selectedFilterState) as
|
||||
| (Filter & { definition: { type: 'DATE' | 'DATE_TIME' } })
|
||||
| null
|
||||
| undefined;
|
||||
|
||||
const initialFilterValue = selectedFilter
|
||||
? resolveFilterValue(selectedFilter)
|
||||
: null;
|
||||
const [internalDate, setInternalDate] = useState<Date | null>(
|
||||
selectedFilter?.value ? new Date(selectedFilter.value) : new Date(),
|
||||
initialFilterValue instanceof Date ? initialFilterValue : null,
|
||||
);
|
||||
|
||||
const isDateTimeInput =
|
||||
filterDefinitionUsedInDropdown?.type === FieldMetadataType.DateTime;
|
||||
|
||||
const handleChange = (date: Date | null) => {
|
||||
setInternalDate(date);
|
||||
const handleAbsoluteDateChange = (newDate: Date | null) => {
|
||||
setInternalDate(newDate);
|
||||
|
||||
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
selectFilter?.({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId,
|
||||
value: isDefined(date) ? date.toISOString() : '',
|
||||
value: newDate?.toISOString() ?? '',
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: isDefined(date)
|
||||
displayValue: isDefined(newDate)
|
||||
? isDateTimeInput
|
||||
? date.toLocaleString()
|
||||
: date.toLocaleDateString()
|
||||
? newDate.toLocaleString()
|
||||
: newDate.toLocaleDateString()
|
||||
: '',
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
@ -52,11 +68,56 @@ export const ObjectFilterDropdownDateInput = () => {
|
||||
setIsObjectFilterDropdownUnfolded(false);
|
||||
};
|
||||
|
||||
const handleRelativeDateChange = (
|
||||
relativeDate: {
|
||||
direction: VariableDateViewFilterValueDirection;
|
||||
amount?: number;
|
||||
unit: VariableDateViewFilterValueUnit;
|
||||
} | null,
|
||||
) => {
|
||||
if (!filterDefinitionUsedInDropdown || !selectedOperandInDropdown) return;
|
||||
|
||||
const value = relativeDate
|
||||
? computeVariableDateViewFilterValue(
|
||||
relativeDate.direction,
|
||||
relativeDate.amount,
|
||||
relativeDate.unit,
|
||||
)
|
||||
: '';
|
||||
|
||||
selectFilter?.({
|
||||
id: selectedFilter?.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: filterDefinitionUsedInDropdown.fieldMetadataId,
|
||||
value,
|
||||
operand: selectedOperandInDropdown,
|
||||
displayValue: getRelativeDateDisplayValue(relativeDate),
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
|
||||
setIsObjectFilterDropdownUnfolded(false);
|
||||
};
|
||||
|
||||
const isRelativeOperand =
|
||||
selectedOperandInDropdown === ViewFilterOperand.IsRelative;
|
||||
|
||||
const resolvedValue = selectedFilter
|
||||
? resolveFilterValue(selectedFilter)
|
||||
: null;
|
||||
|
||||
const relativeDate =
|
||||
resolvedValue && !(resolvedValue instanceof Date)
|
||||
? resolvedValue
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<InternalDatePicker
|
||||
relativeDate={relativeDate}
|
||||
highlightedDateRange={relativeDate}
|
||||
isRelative={isRelativeOperand}
|
||||
date={internalDate}
|
||||
onChange={handleChange}
|
||||
onMouseSelect={handleChange}
|
||||
onChange={handleAbsoluteDateChange}
|
||||
onRelativeDateChange={handleRelativeDateChange}
|
||||
onMouseSelect={handleAbsoluteDateChange}
|
||||
isDateTimeInput={isDateTimeInput}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -2,12 +2,12 @@ import { useRecoilValue } from 'recoil';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
import { MenuItem } from '@/ui/navigation/menu-item/components/MenuItem';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { isDefined } from '~/utils/isDefined';
|
||||
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { getOperandLabel } from '../utils/getOperandLabel';
|
||||
import { getOperandsForFilterType } from '../utils/getOperandsForFilterType';
|
||||
|
||||
@ -36,22 +36,25 @@ export const ObjectFilterDropdownOperandSelect = () => {
|
||||
);
|
||||
|
||||
const handleOperandChange = (newOperand: ViewFilterOperand) => {
|
||||
const isEmptyOperand = [
|
||||
const isValuelessOperand = [
|
||||
ViewFilterOperand.IsEmpty,
|
||||
ViewFilterOperand.IsNotEmpty,
|
||||
ViewFilterOperand.IsInPast,
|
||||
ViewFilterOperand.IsInFuture,
|
||||
ViewFilterOperand.IsToday,
|
||||
].includes(newOperand);
|
||||
|
||||
setSelectedOperandInDropdown(newOperand);
|
||||
setIsObjectFilterDropdownOperandSelectUnfolded(false);
|
||||
|
||||
if (isEmptyOperand) {
|
||||
if (isValuelessOperand && isDefined(filterDefinitionUsedInDropdown)) {
|
||||
selectFilter?.({
|
||||
id: v4(),
|
||||
fieldMetadataId: filterDefinitionUsedInDropdown?.fieldMetadataId ?? '',
|
||||
displayValue: '',
|
||||
operand: newOperand,
|
||||
value: '',
|
||||
definition: filterDefinitionUsedInDropdown as FilterDefinition,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -60,12 +63,19 @@ export const ObjectFilterDropdownOperandSelect = () => {
|
||||
isDefined(filterDefinitionUsedInDropdown) &&
|
||||
isDefined(selectedFilter)
|
||||
) {
|
||||
const { value, displayValue } = getInitialFilterValue(
|
||||
filterDefinitionUsedInDropdown.type,
|
||||
newOperand,
|
||||
selectedFilter.value,
|
||||
selectedFilter.displayValue,
|
||||
);
|
||||
|
||||
selectFilter?.({
|
||||
id: selectedFilter.id ? selectedFilter.id : v4(),
|
||||
fieldMetadataId: selectedFilter.fieldMetadataId,
|
||||
displayValue: selectedFilter.displayValue,
|
||||
displayValue,
|
||||
operand: newOperand,
|
||||
value: selectedFilter.value,
|
||||
value,
|
||||
definition: filterDefinitionUsedInDropdown,
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { useFilterDropdown } from '@/object-record/object-filter-dropdown/hooks/useFilterDropdown';
|
||||
import { FilterDefinition } from '@/object-record/object-filter-dropdown/types/FilterDefinition';
|
||||
import { getInitialFilterValue } from '@/object-record/object-filter-dropdown/utils/getInitialFilterValue';
|
||||
import { getOperandsForFilterType } from '@/object-record/object-filter-dropdown/utils/getOperandsForFilterType';
|
||||
import { RelationPickerHotkeyScope } from '@/object-record/relation-picker/types/RelationPickerHotkeyScope';
|
||||
import { useSetHotkeyScope } from '@/ui/utilities/hotkey/hooks/useSetHotkeyScope';
|
||||
import { v4 } from 'uuid';
|
||||
|
||||
type SelectFilterParams = {
|
||||
filterDefinition: FilterDefinition;
|
||||
@ -13,6 +15,7 @@ export const useSelectFilter = () => {
|
||||
setFilterDefinitionUsedInDropdown,
|
||||
setSelectedOperandInDropdown,
|
||||
setObjectFilterDropdownSearchInput,
|
||||
selectFilter: filterDropdownSelectFilter,
|
||||
} = useFilterDropdown();
|
||||
|
||||
const setHotkeyScope = useSetHotkeyScope();
|
||||
@ -31,6 +34,22 @@ export const useSelectFilter = () => {
|
||||
getOperandsForFilterType(filterDefinition.type)?.[0],
|
||||
);
|
||||
|
||||
const { value, displayValue } = getInitialFilterValue(
|
||||
filterDefinition.type,
|
||||
getOperandsForFilterType(filterDefinition.type)?.[0],
|
||||
);
|
||||
|
||||
if (value !== '') {
|
||||
filterDropdownSelectFilter({
|
||||
id: v4(),
|
||||
fieldMetadataId: filterDefinition.fieldMetadataId,
|
||||
displayValue,
|
||||
operand: getOperandsForFilterType(filterDefinition.type)?.[0],
|
||||
value,
|
||||
definition: filterDefinition,
|
||||
});
|
||||
}
|
||||
|
||||
setObjectFilterDropdownSearchInput('');
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
|
||||
import { FilterDefinition } from './FilterDefinition';
|
||||
|
||||
export type Filter = {
|
||||
|
||||
@ -19,6 +19,16 @@ describe('getOperandsForFilterType', () => {
|
||||
ViewFilterOperand.LessThan,
|
||||
];
|
||||
|
||||
const dateOperands = [
|
||||
ViewFilterOperand.Is,
|
||||
ViewFilterOperand.IsRelative,
|
||||
ViewFilterOperand.IsInPast,
|
||||
ViewFilterOperand.IsInFuture,
|
||||
ViewFilterOperand.IsToday,
|
||||
ViewFilterOperand.IsBefore,
|
||||
ViewFilterOperand.IsAfter,
|
||||
];
|
||||
|
||||
const relationOperand = [ViewFilterOperand.Is, ViewFilterOperand.IsNot];
|
||||
|
||||
const testCases = [
|
||||
@ -31,7 +41,8 @@ describe('getOperandsForFilterType', () => {
|
||||
['ACTOR', [...containsOperands, ...emptyOperands]],
|
||||
['CURRENCY', [...numberOperands, ...emptyOperands]],
|
||||
['NUMBER', [...numberOperands, ...emptyOperands]],
|
||||
['DATE_TIME', [...numberOperands, ...emptyOperands]],
|
||||
['DATE', [...dateOperands, ...emptyOperands]],
|
||||
['DATE_TIME', [...dateOperands, ...emptyOperands]],
|
||||
['RELATION', [...relationOperand, ...emptyOperands]],
|
||||
[undefined, []],
|
||||
[null, []],
|
||||
|
||||
@ -0,0 +1,42 @@
|
||||
import { Filter } from '@/object-record/object-filter-dropdown/types/Filter';
|
||||
import { FilterType } from '@/object-record/object-filter-dropdown/types/FilterType';
|
||||
import { ViewFilterOperand } from '@/views/types/ViewFilterOperand';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const getInitialFilterValue = (
|
||||
newType: FilterType,
|
||||
newOperand: ViewFilterOperand,
|
||||
oldValue?: string,
|
||||
oldDisplayValue?: string,
|
||||
): Pick<Filter, 'value' | 'displayValue'> | Record<string, never> => {
|
||||
switch (newType) {
|
||||
case 'DATE':
|
||||
case 'DATE_TIME': {
|
||||
const activeDatePickerOperands = [
|
||||
ViewFilterOperand.IsBefore,
|
||||
ViewFilterOperand.Is,
|
||||
ViewFilterOperand.IsAfter,
|
||||
];
|
||||
|
||||
if (activeDatePickerOperands.includes(newOperand)) {
|
||||
const date = z.coerce.date().safeParse(oldValue).data ?? new Date();
|
||||
const value = date.toISOString();
|
||||
const displayValue =
|
||||
newType === 'DATE'
|
||||
? date.toLocaleString()
|
||||
: date.toLocaleDateString();
|
||||
|
||||
return { value, displayValue };
|
||||
}
|
||||
|
||||
if (newOperand === ViewFilterOperand.IsRelative) {
|
||||
return { value: '', displayValue: '' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return {
|
||||
value: oldValue ?? '',
|
||||
displayValue: oldDisplayValue ?? '',
|
||||
};
|
||||
};
|
||||
@ -12,6 +12,10 @@ export const getOperandLabel = (
|
||||
return 'Greater than';
|
||||
case ViewFilterOperand.LessThan:
|
||||
return 'Less than';
|
||||
case ViewFilterOperand.IsBefore:
|
||||
return 'Is before';
|
||||
case ViewFilterOperand.IsAfter:
|
||||
return 'Is after';
|
||||
case ViewFilterOperand.Is:
|
||||
return 'Is';
|
||||
case ViewFilterOperand.IsNot:
|
||||
@ -22,6 +26,14 @@ export const getOperandLabel = (
|
||||
return 'Is empty';
|
||||
case ViewFilterOperand.IsNotEmpty:
|
||||
return 'Is not empty';
|
||||
case ViewFilterOperand.IsRelative:
|
||||
return 'Is relative';
|
||||
case ViewFilterOperand.IsInPast:
|
||||
return 'Is in past';
|
||||
case ViewFilterOperand.IsInFuture:
|
||||
return 'Is in future';
|
||||
case ViewFilterOperand.IsToday:
|
||||
return 'Is today';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
@ -47,6 +59,16 @@ export const getOperandLabelShort = (
|
||||
return '\u00A0> ';
|
||||
case ViewFilterOperand.LessThan:
|
||||
return '\u00A0< ';
|
||||
case ViewFilterOperand.IsBefore:
|
||||
return '\u00A0< ';
|
||||
case ViewFilterOperand.IsAfter:
|
||||
return '\u00A0> ';
|
||||
case ViewFilterOperand.IsInPast:
|
||||
return ': Past';
|
||||
case ViewFilterOperand.IsInFuture:
|
||||
return ': Future';
|
||||
case ViewFilterOperand.IsToday:
|
||||
return ': Today';
|
||||
default:
|
||||
return ': ';
|
||||
}
|
||||
|
||||
@ -31,13 +31,23 @@ export const getOperandsForFilterType = (
|
||||
];
|
||||
case 'CURRENCY':
|
||||
case 'NUMBER':
|
||||
case 'DATE_TIME':
|
||||
case 'DATE':
|
||||
return [
|
||||
ViewFilterOperand.GreaterThan,
|
||||
ViewFilterOperand.LessThan,
|
||||
...emptyOperands,
|
||||
];
|
||||
case 'DATE_TIME':
|
||||
case 'DATE':
|
||||
return [
|
||||
ViewFilterOperand.Is,
|
||||
ViewFilterOperand.IsRelative,
|
||||
ViewFilterOperand.IsInPast,
|
||||
ViewFilterOperand.IsInFuture,
|
||||
ViewFilterOperand.IsToday,
|
||||
ViewFilterOperand.IsBefore,
|
||||
ViewFilterOperand.IsAfter,
|
||||
...emptyOperands,
|
||||
];
|
||||
case 'RATING':
|
||||
return [
|
||||
ViewFilterOperand.Is,
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
import {
|
||||
VariableDateViewFilterValueDirection,
|
||||
VariableDateViewFilterValueUnit,
|
||||
} from '@/views/utils/view-filter-value/resolveDateViewFilterValue';
|
||||
import { plural } from 'pluralize';
|
||||
import { capitalize } from '~/utils/string/capitalize';
|
||||
export const getRelativeDateDisplayValue = (
|
||||
relativeDate: {
|
||||
direction: VariableDateViewFilterValueDirection;
|
||||
amount?: number;
|
||||
unit: VariableDateViewFilterValueUnit;
|
||||
} | null,
|
||||
) => {
|
||||
if (!relativeDate) return '';
|
||||
const { direction, amount, unit } = relativeDate;
|
||||
|
||||
const directionStr = capitalize(direction.toLowerCase());
|
||||
const amountStr = direction === 'THIS' ? '' : amount;
|
||||
const unitStr = amount
|
||||
? amount > 1
|
||||
? plural(unit.toLowerCase())
|
||||
: unit.toLowerCase()
|
||||
: undefined;
|
||||
|
||||
return [directionStr, amountStr, unitStr]
|
||||
.filter((item) => item !== undefined)
|
||||
.join(' ');
|
||||
};
|
||||
@ -25,6 +25,9 @@ import {
|
||||
convertLessThanRatingToArrayOfRatingValues,
|
||||
convertRatingToRatingValue,
|
||||
} from '@/object-record/object-filter-dropdown/components/ObjectFilterDropdownRatingInput';
|
||||
import { resolveFilterValue } from '@/views/utils/view-filter-value/resolveFilterValue';
|
||||
import { endOfDay, roundToNearestMinutes, startOfDay } from 'date-fns';
|
||||
import { z } from 'zod';
|
||||
import { Filter } from '../../object-filter-dropdown/types/Filter';
|
||||
|
||||
export type ObjectDropdownFilter = Omit<Filter, 'definition'> & {
|
||||
@ -289,16 +292,19 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
(field) => field.id === rawUIFilter.fieldMetadataId,
|
||||
);
|
||||
|
||||
const isEmptyOperand = [
|
||||
const isValuelessOperand = [
|
||||
ViewFilterOperand.IsEmpty,
|
||||
ViewFilterOperand.IsNotEmpty,
|
||||
ViewFilterOperand.IsInPast,
|
||||
ViewFilterOperand.IsInFuture,
|
||||
ViewFilterOperand.IsToday,
|
||||
].includes(rawUIFilter.operand);
|
||||
|
||||
if (!correspondingField) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isEmptyOperand) {
|
||||
if (!isValuelessOperand) {
|
||||
if (!isDefined(rawUIFilter.value) || rawUIFilter.value === '') {
|
||||
continue;
|
||||
}
|
||||
@ -341,24 +347,31 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
}
|
||||
break;
|
||||
case 'DATE':
|
||||
case 'DATE_TIME':
|
||||
case 'DATE_TIME': {
|
||||
const resolvedFilterValue = resolveFilterValue(rawUIFilter);
|
||||
const now = roundToNearestMinutes(new Date());
|
||||
const date =
|
||||
resolvedFilterValue instanceof Date ? resolvedFilterValue : now;
|
||||
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.GreaterThan:
|
||||
case ViewFilterOperand.IsAfter: {
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
gte: rawUIFilter.value,
|
||||
gt: date.toISOString(),
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.LessThan:
|
||||
}
|
||||
case ViewFilterOperand.IsBefore: {
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
lte: rawUIFilter.value,
|
||||
lt: date.toISOString(),
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ViewFilterOperand.IsEmpty:
|
||||
case ViewFilterOperand.IsNotEmpty:
|
||||
case ViewFilterOperand.IsNotEmpty: {
|
||||
applyEmptyFilters(
|
||||
rawUIFilter.operand,
|
||||
correspondingField,
|
||||
@ -366,12 +379,99 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
rawUIFilter.definition.type,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case ViewFilterOperand.IsRelative: {
|
||||
const dateRange = z
|
||||
.object({ start: z.date(), end: z.date() })
|
||||
.safeParse(resolvedFilterValue).data;
|
||||
|
||||
const defaultDateRange = resolveFilterValue({
|
||||
value: 'PAST_1_DAY',
|
||||
definition: {
|
||||
type: 'DATE',
|
||||
},
|
||||
operand: ViewFilterOperand.IsRelative,
|
||||
});
|
||||
|
||||
if (!defaultDateRange)
|
||||
throw new Error('Failed to resolve default date range');
|
||||
|
||||
const { start, end } = dateRange ?? defaultDateRange;
|
||||
|
||||
objectRecordFilters.push({
|
||||
and: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
gte: start.toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
lte: end.toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ViewFilterOperand.Is: {
|
||||
const isValid = resolvedFilterValue instanceof Date;
|
||||
const date = isValid ? resolvedFilterValue : now;
|
||||
|
||||
objectRecordFilters.push({
|
||||
and: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
lte: endOfDay(date).toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
gte: startOfDay(date).toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
}
|
||||
case ViewFilterOperand.IsInPast:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
lte: now.toISOString(),
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.IsInFuture:
|
||||
objectRecordFilters.push({
|
||||
[correspondingField.name]: {
|
||||
gte: now.toISOString(),
|
||||
} as DateFilter,
|
||||
});
|
||||
break;
|
||||
case ViewFilterOperand.IsToday: {
|
||||
objectRecordFilters.push({
|
||||
and: [
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
lte: endOfDay(now).toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
{
|
||||
[correspondingField.name]: {
|
||||
gte: startOfDay(now).toISOString(),
|
||||
} as DateFilter,
|
||||
},
|
||||
],
|
||||
});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`,
|
||||
`Unknown operand ${rawUIFilter.operand} for ${rawUIFilter.definition.type} filter`, //
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'RATING':
|
||||
switch (rawUIFilter.operand) {
|
||||
case ViewFilterOperand.Is:
|
||||
@ -446,7 +546,7 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
}
|
||||
break;
|
||||
case 'RELATION': {
|
||||
if (!isEmptyOperand) {
|
||||
if (!isValuelessOperand) {
|
||||
try {
|
||||
JSON.parse(rawUIFilter.value);
|
||||
} catch (e) {
|
||||
@ -743,7 +843,7 @@ export const turnObjectDropdownFilterIntoQueryFilter = (
|
||||
}
|
||||
break;
|
||||
case 'SELECT': {
|
||||
if (isEmptyOperand) {
|
||||
if (isValuelessOperand) {
|
||||
applyEmptyFilters(
|
||||
rawUIFilter.operand,
|
||||
correspondingField,
|
||||
|
||||
Reference in New Issue
Block a user