Fixes date filter chip bugs (#12788)
This PR fixes a bug that occurs during filter operand changes. As a date filter can contain values that have a different shape, mainly date ISO string and hard-coded relative dates, changing the operand without resetting the value to its default was causing a crash. This PR also extracts the logic that computes the right part of a filter chip into a util instead of a difficult to understand ternary, thus solving small bugs in the value displayed also. Fixes https://github.com/twentyhq/twenty/issues/12778
This commit is contained in:
@ -0,0 +1,9 @@
|
|||||||
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
|
|
||||||
|
export const DATE_OPERANDS_THAT_SHOULD_BE_INITIALIZED_WITH_NOW: RecordFilterOperand[] =
|
||||||
|
[
|
||||||
|
RecordFilterOperand.Is,
|
||||||
|
RecordFilterOperand.IsNot,
|
||||||
|
RecordFilterOperand.IsAfter,
|
||||||
|
RecordFilterOperand.IsBefore,
|
||||||
|
];
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { DATE_OPERANDS_THAT_SHOULD_BE_INITIALIZED_WITH_NOW } from '@/object-record/object-filter-dropdown/constants/DateOperandsThatShouldBeInitializedWithNow';
|
||||||
import { useUpsertObjectFilterDropdownCurrentFilter } from '@/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter';
|
import { useUpsertObjectFilterDropdownCurrentFilter } from '@/object-record/object-filter-dropdown/hooks/useUpsertObjectFilterDropdownCurrentFilter';
|
||||||
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
import { fieldMetadataItemUsedInDropdownComponentSelector } from '@/object-record/object-filter-dropdown/states/fieldMetadataItemUsedInDropdownComponentSelector';
|
||||||
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
import { objectFilterDropdownCurrentRecordFilterComponentState } from '@/object-record/object-filter-dropdown/states/objectFilterDropdownCurrentRecordFilterComponentState';
|
||||||
@ -5,6 +6,7 @@ import { selectedOperandInDropdownComponentState } from '@/object-record/object-
|
|||||||
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
|
import { useCreateEmptyRecordFilterFromFieldMetadataItem } from '@/object-record/record-filter/hooks/useCreateEmptyRecordFilterFromFieldMetadataItem';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
|
import { getDateFilterDisplayValue } from '@/object-record/record-filter/utils/getDateFilterDisplayValue';
|
||||||
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 { isDefined } from 'twenty-shared/utils';
|
import { isDefined } from 'twenty-shared/utils';
|
||||||
@ -18,7 +20,7 @@ export const useApplyObjectFilterDropdownOperand = () => {
|
|||||||
selectedOperandInDropdownComponentState,
|
selectedOperandInDropdownComponentState,
|
||||||
);
|
);
|
||||||
|
|
||||||
const objectFilterDropdownFilterIsCreated = isDefined(
|
const objectFilterDropdownFilterHasBeenCreated = isDefined(
|
||||||
objectFilterDropdownCurrentRecordFilter,
|
objectFilterDropdownCurrentRecordFilter,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -43,13 +45,13 @@ export const useApplyObjectFilterDropdownOperand = () => {
|
|||||||
RecordFilterOperand.IsToday,
|
RecordFilterOperand.IsToday,
|
||||||
].includes(newOperand);
|
].includes(newOperand);
|
||||||
|
|
||||||
if (objectFilterDropdownFilterIsCreated) {
|
let recordFilterToUpsert: RecordFilter | null | undefined = null;
|
||||||
const newCurrentRecordFilter = {
|
|
||||||
|
if (objectFilterDropdownFilterHasBeenCreated) {
|
||||||
|
recordFilterToUpsert = {
|
||||||
...objectFilterDropdownCurrentRecordFilter,
|
...objectFilterDropdownCurrentRecordFilter,
|
||||||
operand: newOperand,
|
operand: newOperand,
|
||||||
} satisfies RecordFilter;
|
} satisfies RecordFilter;
|
||||||
|
|
||||||
upsertObjectFilterDropdownCurrentFilter(newCurrentRecordFilter);
|
|
||||||
} else if (isValuelessOperand) {
|
} else if (isValuelessOperand) {
|
||||||
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
if (!isDefined(fieldMetadataItemUsedInDropdown)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -62,12 +64,37 @@ export const useApplyObjectFilterDropdownOperand = () => {
|
|||||||
fieldMetadataItemUsedInDropdown,
|
fieldMetadataItemUsedInDropdown,
|
||||||
);
|
);
|
||||||
|
|
||||||
const recordFilterToCreate = {
|
recordFilterToUpsert = {
|
||||||
...emptyRecordFilter,
|
...emptyRecordFilter,
|
||||||
operand: newOperand,
|
operand: newOperand,
|
||||||
} satisfies RecordFilter;
|
} satisfies RecordFilter;
|
||||||
|
}
|
||||||
|
|
||||||
upsertObjectFilterDropdownCurrentFilter(recordFilterToCreate);
|
if (
|
||||||
|
isDefined(recordFilterToUpsert) &&
|
||||||
|
(recordFilterToUpsert.type === 'DATE' ||
|
||||||
|
recordFilterToUpsert.type === 'DATE_TIME')
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
DATE_OPERANDS_THAT_SHOULD_BE_INITIALIZED_WITH_NOW.includes(newOperand)
|
||||||
|
) {
|
||||||
|
const newDateValue = new Date();
|
||||||
|
|
||||||
|
recordFilterToUpsert.value = newDateValue.toISOString();
|
||||||
|
const { displayValue } = getDateFilterDisplayValue(
|
||||||
|
newDateValue,
|
||||||
|
recordFilterToUpsert.type,
|
||||||
|
);
|
||||||
|
|
||||||
|
recordFilterToUpsert.displayValue = displayValue;
|
||||||
|
} else {
|
||||||
|
recordFilterToUpsert.value = '';
|
||||||
|
recordFilterToUpsert.displayValue = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefined(recordFilterToUpsert)) {
|
||||||
|
upsertObjectFilterDropdownCurrentFilter(recordFilterToUpsert);
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedOperandInDropdown(newOperand);
|
setSelectedOperandInDropdown(newOperand);
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
|
import { useFieldMetadataItemById } from '@/object-metadata/hooks/useFieldMetadataItemById';
|
||||||
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
import { getCompositeSubFieldLabel } from '@/object-record/object-filter-dropdown/utils/getCompositeSubFieldLabel';
|
||||||
import { getOperandLabelShort } from '@/object-record/object-filter-dropdown/utils/getOperandLabel';
|
|
||||||
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
import { isCompositeFieldType } from '@/object-record/object-filter-dropdown/utils/isCompositeFieldType';
|
||||||
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
import { isEmptinessOperand } from '@/object-record/record-filter/utils/isEmptinessOperand';
|
|
||||||
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
|
||||||
import { isValidSubFieldName } from '@/settings/data-model/utils/isValidSubFieldName';
|
import { isValidSubFieldName } from '@/settings/data-model/utils/isValidSubFieldName';
|
||||||
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
import { SortOrFilterChip } from '@/views/components/SortOrFilterChip';
|
||||||
|
import { getRecordFilterLabelValue } from '@/views/utils/getRecordFilterLabelValue';
|
||||||
import { isNonEmptyString } from '@sniptt/guards';
|
import { isNonEmptyString } from '@sniptt/guards';
|
||||||
import { useIcons } from 'twenty-ui/display';
|
import { useIcons } from 'twenty-ui/display';
|
||||||
|
|
||||||
@ -29,9 +27,6 @@ export const EditableFilterChip = ({
|
|||||||
|
|
||||||
const FieldMetadataItemIcon = getIcon(fieldMetadataItem.icon);
|
const FieldMetadataItemIcon = getIcon(fieldMetadataItem.icon);
|
||||||
|
|
||||||
const operandLabelShort = getOperandLabelShort(recordFilter.operand);
|
|
||||||
const operandIsEmptiness = isEmptinessOperand(recordFilter.operand);
|
|
||||||
|
|
||||||
const recordFilterSubFieldName = recordFilter.subFieldName;
|
const recordFilterSubFieldName = recordFilter.subFieldName;
|
||||||
|
|
||||||
const subFieldLabel =
|
const subFieldLabel =
|
||||||
@ -48,10 +43,8 @@ export const EditableFilterChip = ({
|
|||||||
? `${recordFilter.label} / ${subFieldLabel}`
|
? `${recordFilter.label} / ${subFieldLabel}`
|
||||||
: recordFilter.label;
|
: recordFilter.label;
|
||||||
|
|
||||||
const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter);
|
|
||||||
|
|
||||||
const labelKey = `${fieldNameLabel}`;
|
const labelKey = `${fieldNameLabel}`;
|
||||||
const labelValue = `${!operandIsEmptiness && !recordFilterIsEmpty ? operandLabelShort : operandIsEmptiness ? ` ${operandLabelShort}` : ''} ${operandIsEmptiness ? '' : recordFilter.displayValue}`;
|
const labelValue = getRecordFilterLabelValue(recordFilter);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SortOrFilterChip
|
<SortOrFilterChip
|
||||||
|
|||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { getOperandLabelShort } from '@/object-record/object-filter-dropdown/utils/getOperandLabel';
|
||||||
|
import { RecordFilter } from '@/object-record/record-filter/types/RecordFilter';
|
||||||
|
import { RecordFilterOperand } from '@/object-record/record-filter/types/RecordFilterOperand';
|
||||||
|
import { isEmptinessOperand } from '@/object-record/record-filter/utils/isEmptinessOperand';
|
||||||
|
import { isRecordFilterConsideredEmpty } from '@/object-record/record-filter/utils/isRecordFilterConsideredEmpty';
|
||||||
|
|
||||||
|
export const getRecordFilterLabelValue = (recordFilter: RecordFilter) => {
|
||||||
|
const operandLabelShort = getOperandLabelShort(recordFilter.operand);
|
||||||
|
const operandIsEmptiness = isEmptinessOperand(recordFilter.operand);
|
||||||
|
const recordFilterIsEmpty = isRecordFilterConsideredEmpty(recordFilter);
|
||||||
|
|
||||||
|
const isDateOrDateTimeFilter =
|
||||||
|
recordFilter.type === 'DATE' || recordFilter.type === 'DATE_TIME';
|
||||||
|
|
||||||
|
if (isDateOrDateTimeFilter) {
|
||||||
|
switch (recordFilter.operand) {
|
||||||
|
case RecordFilterOperand.IsToday:
|
||||||
|
case RecordFilterOperand.IsInFuture:
|
||||||
|
case RecordFilterOperand.IsInPast:
|
||||||
|
return operandLabelShort;
|
||||||
|
default:
|
||||||
|
return `${operandLabelShort} ${recordFilter.displayValue}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!operandIsEmptiness && !recordFilterIsEmpty) {
|
||||||
|
return `${operandLabelShort} ${recordFilter.displayValue}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (operandIsEmptiness) {
|
||||||
|
return `${operandLabelShort}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return recordFilter.displayValue;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user