Skip to content

Commit 3ab8bc3

Browse files
committed
fix(tables): retain deferred filter conditions
1 parent d72f5fd commit 3ab8bc3

2 files changed

Lines changed: 68 additions & 3 deletions

File tree

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-filter/table-filter.test.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ describe('TableFilter', () => {
184184
})
185185
})
186186

187+
it('keeps a deferred condition applied while another rule is removed', () => {
188+
const onChange = vi.fn()
189+
renderFilter(onChange, {
190+
any: [
191+
{ all: [{ field: 'col-name', op: 'eq', value: 'Ada' }] },
192+
{
193+
all: [
194+
{ field: 'col-name', op: 'isEmpty' },
195+
{ field: 'col-name', op: 'eq', value: 'Linus' },
196+
],
197+
},
198+
],
199+
})
200+
201+
const operatorTrigger = Array.from(container.querySelectorAll('button')).find(
202+
(button) => button.textContent?.trim() === 'is empty'
203+
)
204+
act(() => {
205+
operatorTrigger?.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, button: 0 }))
206+
})
207+
const equalsOption = Array.from(
208+
document.querySelectorAll<HTMLElement>('[role="menuitem"]')
209+
).find((item) => item.textContent?.trim() === 'equals')
210+
act(() => equalsOption?.click())
211+
212+
expect(onChange).not.toHaveBeenCalled()
213+
214+
const removeButtons = container.querySelectorAll<HTMLButtonElement>(
215+
'button[aria-label="Remove filter"]'
216+
)
217+
act(() => removeButtons[2]?.click())
218+
219+
expect(onChange).toHaveBeenCalledWith({
220+
any: [
221+
{ all: [{ field: 'col-name', op: 'eq', value: 'Ada' }] },
222+
{ all: [{ field: 'col-name', op: 'isEmpty' }] },
223+
],
224+
})
225+
})
226+
187227
it('loads a saved OR filter verbatim without an unsolicited autosave', () => {
188228
const onChange = vi.fn()
189229
renderFilter(onChange, {

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-filter/table-filter.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export function TableFilter({
5959
onClose,
6060
}: TableFilterProps) {
6161
const lastAppliedFilterRef = useRef<string | undefined>(undefined)
62+
const deferredAppliedRulesRef = useRef<Map<string, FilterRule>>(new Map())
6263
const [rules, setRules] = useState<FilterRule[]>(() => {
6364
const fromFilter = predicateToFilterRules(filter)
6465
return fromFilter.length > 0 ? fromFilter : [createRule(columns)]
@@ -75,15 +76,39 @@ export function TableFilter({
7576

7677
const applyRules = useCallback(
7778
(update: (current: FilterRule[]) => FilterRule[], deferIncompleteRuleId?: string) => {
78-
const nextRules = update(rulesRef.current)
79+
const currentRules = rulesRef.current
80+
const nextRules = update(currentRules)
7981
rulesRef.current = nextRules
8082
setRules(nextRules)
8183
if (!autoApply) return
8284

8385
const deferredRule = nextRules.find((rule) => rule.id === deferIncompleteRuleId)
84-
if (deferredRule && !isCompleteRule(deferredRule)) return
86+
if (deferredRule && !isCompleteRule(deferredRule)) {
87+
const previouslyAppliedRule = currentRules.find((rule) => rule.id === deferredRule.id)
88+
if (previouslyAppliedRule && isCompleteRule(previouslyAppliedRule)) {
89+
const deferredRules = deferredAppliedRulesRef.current
90+
if (!deferredRules.has(deferredRule.id)) {
91+
deferredRules.set(deferredRule.id, previouslyAppliedRule)
92+
}
93+
}
94+
}
95+
96+
const nextRulesById = new Map(nextRules.map((rule) => [rule.id, rule]))
97+
for (const [id] of deferredAppliedRulesRef.current) {
98+
const nextRule = nextRulesById.get(id)
99+
if (!nextRule || isCompleteRule(nextRule)) {
100+
deferredAppliedRulesRef.current.delete(id)
101+
}
102+
}
103+
104+
const appliedRules = nextRules.map((rule) => {
105+
const deferredRule = deferredAppliedRulesRef.current.get(rule.id)
106+
return deferredRule && !isCompleteRule(rule)
107+
? { ...deferredRule, logicalOperator: rule.logicalOperator }
108+
: rule
109+
})
85110

86-
const nextFilter = toAppliedPredicate(nextRules, columns, true)
111+
const nextFilter = toAppliedPredicate(appliedRules, columns, true)
87112
const signature = JSON.stringify(nextFilter)
88113
if (signature === lastAppliedFilterRef.current) return
89114
lastAppliedFilterRef.current = signature

0 commit comments

Comments
 (0)