Skip to content

Commit de05b35

Browse files
authored
fix: default conditional filter to field mode (#2198)
* fix: default conditional filter to field mode * test: align field reference operator expectations
1 parent b81a35d commit de05b35

File tree

3 files changed

+80
-44
lines changed

3 files changed

+80
-44
lines changed

packages/core/src/models/view/filter/field-reference.spec.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,26 @@ import {
66
isFieldReferenceOperatorSupported,
77
} from './field-reference';
88
import {
9+
contains,
10+
doesNotContain,
11+
hasAllOf,
12+
hasAnyOf,
13+
hasNoneOf,
914
is,
1015
isAfter,
16+
isAnyOf,
1117
isBefore,
18+
isExactly,
1219
isGreater,
1320
isGreaterEqual,
1421
isLess,
1522
isLessEqual,
1623
isNot,
24+
isNotExactly,
25+
isNoneOf,
1726
isOnOrAfter,
1827
isOnOrBefore,
28+
isWithIn,
1929
} from './operator';
2030

2131
describe('field reference operator helpers', () => {
@@ -48,8 +58,13 @@ describe('field reference operator helpers', () => {
4858
type: FieldType.CreatedBy,
4959
} as const;
5060

51-
it('returns equality operators for string fields', () => {
52-
expect(getFieldReferenceSupportedOperators(stringField)).toEqual([is.value, isNot.value]);
61+
it('returns text operators for string fields', () => {
62+
expect(getFieldReferenceSupportedOperators(stringField)).toEqual([
63+
is.value,
64+
isNot.value,
65+
contains.value,
66+
doesNotContain.value,
67+
]);
5368
});
5469

5570
it('returns comparison operators for number fields', () => {
@@ -67,21 +82,30 @@ describe('field reference operator helpers', () => {
6782
expect(getFieldReferenceSupportedOperators(dateField)).toEqual([
6883
is.value,
6984
isNot.value,
85+
isWithIn.value,
7086
isBefore.value,
7187
isAfter.value,
7288
isOnOrBefore.value,
7389
isOnOrAfter.value,
7490
]);
7591
});
7692

77-
it('excludes operators for multi-value user field', () => {
78-
expect(getFieldReferenceSupportedOperators(multiUserField)).toEqual([]);
93+
it('returns collection operators for multi-value user field', () => {
94+
expect(getFieldReferenceSupportedOperators(multiUserField)).toEqual([
95+
hasAnyOf.value,
96+
hasAllOf.value,
97+
isExactly.value,
98+
hasNoneOf.value,
99+
isNotExactly.value,
100+
]);
79101
});
80102

81103
it('checks operator support', () => {
82104
expect(isFieldReferenceOperatorSupported(dateField, isBefore.value)).toBe(true);
83105
expect(isFieldReferenceOperatorSupported(stringField, isAfter.value)).toBe(false);
84-
expect(isFieldReferenceOperatorSupported(multiUserField, is.value)).toBe(false);
106+
expect(isFieldReferenceOperatorSupported(multiUserField, hasAnyOf.value)).toBe(true);
107+
expect(isFieldReferenceOperatorSupported(stringField, isAnyOf.value)).toBe(false);
108+
expect(isFieldReferenceOperatorSupported(stringField, isNoneOf.value)).toBe(false);
85109
expect(isFieldReferenceOperatorSupported(numberField, null)).toBe(false);
86110
});
87111

packages/core/src/models/view/filter/field-reference.ts

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
22
import { CellValueType, FieldType } from '../../field/constant';
33
import type { IOperator } from './operator';
4-
import {
5-
getValidFilterOperators,
6-
is,
7-
isAfter,
8-
isBefore,
9-
isGreater,
10-
isGreaterEqual,
11-
isLess,
12-
isLessEqual,
13-
isNot,
14-
isOnOrAfter,
15-
isOnOrBefore,
16-
} from './operator';
4+
import { getValidFilterOperators, isEmpty, isNotEmpty } from './operator';
175

186
type FieldShape = {
197
cellValueType: CellValueType;
@@ -70,32 +58,11 @@ export function isFieldReferenceComparable(field: FieldShape, reference: FieldSh
7058
return getFieldReferenceComparisonKind(field) === getFieldReferenceComparisonKind(reference);
7159
}
7260

73-
const FIELD_REFERENCE_OPERATOR_MAP: Record<CellValueType, ReadonlySet<IOperator>> = {
74-
[CellValueType.String]: new Set<IOperator>([is.value, isNot.value]),
75-
[CellValueType.Number]: new Set<IOperator>([
76-
is.value,
77-
isNot.value,
78-
isGreater.value,
79-
isGreaterEqual.value,
80-
isLess.value,
81-
isLessEqual.value,
82-
]),
83-
[CellValueType.Boolean]: new Set<IOperator>([is.value, isNot.value]),
84-
[CellValueType.DateTime]: new Set<IOperator>([
85-
is.value,
86-
isNot.value,
87-
isBefore.value,
88-
isAfter.value,
89-
isOnOrBefore.value,
90-
isOnOrAfter.value,
91-
]),
92-
};
61+
const FIELD_REFERENCE_UNSUPPORTED_OPERATORS = new Set<IOperator>([isEmpty.value, isNotEmpty.value]);
9362

9463
export function getFieldReferenceSupportedOperators(field: FieldShape): IOperator[] {
9564
const validOperators = getValidFilterOperators(field);
96-
const supported = FIELD_REFERENCE_OPERATOR_MAP[field.cellValueType] ?? new Set<IOperator>();
97-
98-
return validOperators.filter((op) => supported.has(op));
65+
return validOperators.filter((op) => !FIELD_REFERENCE_UNSUPPORTED_OPERATORS.has(op));
9966
}
10067

10168
export function isFieldReferenceOperatorSupported(
@@ -105,6 +72,10 @@ export function isFieldReferenceOperatorSupported(
10572
if (!operator) {
10673
return false;
10774
}
108-
const supported = getFieldReferenceSupportedOperators(field);
109-
return supported.includes(operator);
75+
if (FIELD_REFERENCE_UNSUPPORTED_OPERATORS.has(operator)) {
76+
return false;
77+
}
78+
79+
const validOperators = getValidFilterOperators(field);
80+
return validOperators.includes(operator);
11081
}

packages/sdk/src/components/filter/view-filter/custom-component/BaseFieldValue.tsx

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
TooltipTrigger,
1919
cn,
2020
} from '@teable/ui-lib';
21-
import { cloneElement, useCallback, useEffect, useMemo, useState } from 'react';
21+
import { cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2222
import type { ReactElement } from 'react';
2323
import { useTranslation } from '../../../../context/app/i18n';
2424
import type { DateField, IFieldInstance } from '../../../../model';
@@ -103,6 +103,47 @@ const ConditionalRollupValue = (props: IConditionalRollupValueProps) => {
103103
);
104104

105105
const toggleDisabled = !operatorSupportsReferences || !referenceFields.length;
106+
const lastDefaultKeyRef = useRef<string | null>(null);
107+
108+
useEffect(() => {
109+
if (!referenceFields.length || !field || !operator || !operatorSupportsReferences) {
110+
return;
111+
}
112+
113+
const currentKey = `${field.id}:${operator}`;
114+
if (value !== null && value !== undefined) {
115+
lastDefaultKeyRef.current = currentKey;
116+
return;
117+
}
118+
119+
if (lastDefaultKeyRef.current === currentKey) {
120+
return;
121+
}
122+
123+
const comparableField = referenceFields.find(
124+
(candidate) => !isReferenceFieldDisabled(candidate)
125+
);
126+
const targetField = comparableField ?? referenceFields[0];
127+
if (!targetField) {
128+
return;
129+
}
130+
131+
lastDefaultKeyRef.current = currentKey;
132+
onSelect({
133+
type: 'field',
134+
fieldId: targetField.id,
135+
tableId: targetField.tableId ?? referenceTableId,
136+
} satisfies IFieldReferenceValue);
137+
}, [
138+
field,
139+
isReferenceFieldDisabled,
140+
onSelect,
141+
operator,
142+
operatorSupportsReferences,
143+
referenceFields,
144+
referenceTableId,
145+
value,
146+
]);
106147

107148
const handleToggle = () => {
108149
if (toggleDisabled) {

0 commit comments

Comments
 (0)