Files
twenty/packages
Charles Bochet 965ff4337f fix(front): mass update targets explicitly selected records (#21548)
## Problem

Mass update silently does nothing for explicitly-selected records in a
filtered view (reported in
[quality-feedbacks](https://discord.com/channels/1130383047699738754/1515444299934728213)
— "Mass update does not work (for boolean?)", high severity).

When you select specific records (selection mode) and run **Update
records**, the action built its target filter with
`computeContextStoreFilters`, which intersects the selected record ids
with the **current view filters**:

```ts
// selection mode (before)
queryFilter = makeAndFilterVariables([
  anyFieldFilter,
  { id: { in: selectedRecordIds } },
  computeRecordGqlOperationFilter({ ...view filters... }), // ← intersect with view
]);
```

`useIncrementalUpdateManyRecords` first **fetches** the ids matching
that filter, then updates them:

```ts
if (firstPageRecordIds.length > 0) {
  await mutateRecordsBatch(...); // never runs when the fetch returns 0
}
```

So any selected record that doesn't match the view filter is silently
dropped. When *none* of the selected records match, the fetch returns 0
→ the `updateMany` mutation never fires → only the trailing
refetch/aggregate queries run, and nothing changes. The confirmation
modal still says "Update N records" (it reads
`selectedRecordIds.length`), and the side-panel header shows "0
selected" (it reads the find result) — the exact symptoms in the report.

This is especially easy to hit when updating the very field a view is
filtered on (e.g. a view filtered "QA Done = false" and you set "QA Done
= true" on the selected rows).

## Fix

In **selection mode**, target exactly the selected ids — the user picked
those records, so the action must act on them regardless of the active
view filter / any-field search:

```ts
// selection mode (after)
return { id: { in: contextStoreTargetedRecordsRule.selectedRecordIds } };
```

Exclusion mode (select-all) is unchanged — it still needs the view
filter to define "all matching except N". This also makes the side-panel
"N selected" count and other selection-mode actions (delete, export, …)
consistent with the explicit selection.

## Reproduction (deterministic)

1. Companies view filtered **QA Done = false**.
2. Select 3 rows individually.
3. Change those rows so they no longer match the filter (set `qaDone =
true`) without refetching the view — they stay selected.
4. Open **Update**, set **Employees = 100**, confirm "Update 3 records".

**Before:** `Employees` stays `NULL`; side panel shows "0 selected".
**After:** `Employees = 100` on all 3; side panel shows "3 selected".

## Tests

- Updated `computeContextStoreFilters` selection-mode test to the new
shape.
- Added a regression test asserting selection mode targets only the
selected ids and ignores active view filters / any-field search.

`nx lint:diff-with-main`, `nx typecheck twenty-front`, and the unit
tests pass.

<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/21548?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-14 19:11:46 +00:00
..