Skip to content

Fix filter operator switching behavior#7304

Open
sk10727-a11y wants to merge 6 commits intoactualbudget:masterfrom
jadenar07:filter-fix
Open

Fix filter operator switching behavior#7304
sk10727-a11y wants to merge 6 commits intoactualbudget:masterfrom
jadenar07:filter-fix

Conversation

@sk10727-a11y
Copy link
Copy Markdown

@sk10727-a11y sk10727-a11y commented Mar 27, 2026

Description

Fixes an issue where switching filter operators between exact-match (is, one of) and text-based operators (contains, matches) would populate the input with UUIDs instead of human-readable names.

This PR adds logic to correctly transform values when switching between operator types for ID-based fields (accounts, categories, category groups, payees):

  • Single-ID → text: Converts stored ID → text, since there is a one-to-one mapping
  • Text → Single-ID: Converts text → ID (if uniquely matched), ensuring correctness without guessing
  • Multi-ID → text: If the array size is 1, resolves ID to text (if uniquely matched); otherwise, clears the value, since multiple IDs cannot be reliably represented as a single string
  • Text → Multi-ID: Resolves text to a single ID (if uniquely matched) and wraps it in an array, matching the expected multi-value format

Unique to the accounts filter, there are account no-value operators (is on budget, is off budget):

  • No-value → text: Converts preserved ID(s) → text when possible
  • No-value → Single-ID: Converts preserved text → ID when a unique match exists
  • No-value → Multi-ID: Resolves preserved text to a single ID (if uniquely matched) and wraps it in an array; otherwise clears the value

Note:

  • Single-ID exact-match operators: is, is not → store a single ID value
  • Multi-ID exact-match operators: one of, not one of → store an array of IDs
  • Text-based operators: contains, matches, does not contain → store plain strings
  • Account no-value operators: is on budget, is off budget → do not use input values but preserve state for future conversions

This ensures the input always matches the expected format for the selected operator and prevents UUID leakage in the UI.

Related issue(s)

Fixes #7123.

Testing

Tested the following transitions across accounts, categories, category groups, and payees:

  • is → contains, matches, does not contain: ID correctly converted to text
  • is not → text operators: same behavior as above
  • contains / matches → is, is not: text converted back to ID when an exact match exists
  • contains / matches → one of: text converted to single ID and wrapped in array
  • one of / not one of → text operators: prevented invalid conversion (cleared value)
  • is → one of: single ID preserved and wrapped in array

Account-specific cases:

  • is → is on budget / is off budget → contains: correctly converts back to text
  • one of → is on budget / is off budget → text: clears or converts appropriately
  • text → is on budget / is off budget → is: attempts to resolve back to ID

How to test

  1. Navigate to an account
  2. Create or edit a filter on an ID-based field (accounts, category, category group, payees)
  3. Switch between operators
  4. Verify the input remains human-readable and matches the outlined behavior

Checklist

  • Release notes added (see link above)
  • No obvious regressions in affected areas
  • Self-review has been performed - I understand what each change in the code does and why it is needed

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 27 12.41 MB → 12.41 MB (+4.93 kB) +0.04%
loot-core 1 4.84 MB 0%
api 1 3.83 MB 0%
cli 1 7.89 MB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
27 12.41 MB → 12.41 MB (+4.93 kB) +0.04%
Changeset
File Δ Size
src/components/filters/FiltersMenu.tsx 📈 +4.93 kB (+28.72%) 17.17 kB → 22.11 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/index.js 3.31 MB → 3.32 MB (+4.93 kB) +0.15%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
static/js/BackgroundImage.js 121.09 kB 0%
static/js/FormulaEditor.js 852.77 kB 0%
static/js/ReportRouter.js 1.17 MB 0%
static/js/TransactionList.js 82.49 kB 0%
static/js/ca.js 189.75 kB 0%
static/js/da.js 104.66 kB 0%
static/js/de.js 174.38 kB 0%
static/js/en-GB.js 8.2 kB 0%
static/js/en.js 175.65 kB 0%
static/js/es.js 181.8 kB 0%
static/js/fr.js 177.08 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 165.87 kB 0%
static/js/narrow.js 363.02 kB 0%
static/js/nb-NO.js 151.85 kB 0%
static/js/nl.js 108.93 kB 0%
static/js/pl.js 88.34 kB 0%
static/js/pt-BR.js 177.44 kB 0%
static/js/resize-observer.js 18.06 kB 0%
static/js/th.js 179.3 kB 0%
static/js/theme.js 30.79 kB 0%
static/js/uk.js 212.6 kB 0%
static/js/useTransactionBatchActions.js 4.33 MB 0%
static/js/wide.js 295 B 0%
static/js/workbox-window.prod.es5.js 7.33 kB 0%
static/js/zh-Hans.js 94.19 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 4.84 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
kcab.worker.BkkdkSI8.js 4.84 MB 0%

api

Total

Files count Total bundle size % Changed
1 3.83 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
index.js 3.83 MB 0%

cli

Total

Files count Total bundle size % Changed
1 7.89 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
cli.js 7.89 MB 0%

@actual-github-bot actual-github-bot bot changed the title Filter fix [WIP] Filter fix Mar 27, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit c6c35c2
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget/deploys/69d68f3d2b8bea0008ac58d6
😎 Deploy Preview https://deploy-preview-7304.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hello contributor!

We would love to review your PR! Before we can do that, please make sure:

  • ✅ All CI checks pass
  • ✅ The PR is moved from draft to open (if applicable)
  • ✅ The "[WIP]" prefix is removed from the PR title
  • ✅ All CodeRabbit code review comments are resolved (if you disagree with anything - reply to the bot with your reasoning so we can read through it). The bot will eventually approve the PR.

We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges.

For more information, please see our Contributing Guide.

@sk10727-a11y sk10727-a11y changed the title [WIP] Filter fix Fix filter operator switching behavio Mar 27, 2026
@sk10727-a11y sk10727-a11y changed the title Fix filter operator switching behavio Fix filter operator switching behavior Mar 27, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Mar 27, 2026

Deploy Preview for actualbudget-storybook ready!

Name Link
🔨 Latest commit c6c35c2
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget-storybook/deploys/69d68f3db8bbcd0008bc0815
😎 Deploy Preview https://deploy-preview-7304--actualbudget-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

updated to allow conversion from multi-ID to text if only one array value and to handle no-value operators for account filter

final fixes before upstream sync
Fix UUID leakage when switching filter operators
Fix UUID leakage when switching filter operators#
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

FiltersMenu.tsx now loads accounts, categories, and payees to map stored IDs to display text, replaces hyphenated op tokens with camelCase variants, and centralizes operator switching in a local setOp(nextOp) that translates and preserves values across op type transitions.

Changes

Cohort / File(s) Summary
Filter Operator Switching & Value Translation
packages/desktop-client/src/components/filters/FiltersMenu.tsx
Integrated useAccounts, useCategories, and usePayees to map IDs ↔ display strings; replaced hyphenated ops with camelCase (isNot, oneOf, notOneOf, doesNotContain); added setOp(nextOp) to centralize op switching and convert/preserve values between single-ID, multi-ID, text, and account no-value ops; updated op button handlers and conditional input rendering for account/payee.
Release Notes
upcoming-release-notes/7304.md
Added a Bugfixes release note: “Fix UUID showing when switching filter operators”.

Sequence Diagram(s)

sequenceDiagram
  participant User as User
  participant FM as FiltersMenu
  participant Acc as AccountsService
  participant Cat as CategoriesService
  participant Pay as PayeesService
  participant FR as FilterReducer

  User->>FM: change operator / press op button
  FM->>FM: setOp(nextOp) (determine op type transition)
  alt needs ID↔text or single↔multi translation
    FM->>Acc: lookup account names/IDs
    FM->>Cat: lookup category names/IDs
    FM->>Pay: lookup payee names/IDs
    Acc-->>FM: account mappings
    Cat-->>FM: category mappings
    Pay-->>FM: payee mappings
    FM->>FM: convert/preserve value(s)
  end
  FM->>FR: dispatch set-value? / set-op
  FR-->>FM: new filter state
  FM-->>User: updated UI (inputs / tokens)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇 I hopped through fields where UUIDs lay,
I nudged the ops and sent them on their way.
IDs became names, switches now behave—
Filters wear faces, not a cryptic grave.
🥕✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR directly addresses issue #7123 by implementing operator switching logic that converts ID values to human-readable text names, preventing UUID display.
Out of Scope Changes check ✅ Passed All changes focus on fixing operator switching behavior for ID-based filter fields and adding supporting release notes, directly aligned with the issue objectives.
Title check ✅ Passed The title directly and clearly summarizes the main change: fixing the behavior when switching between filter operators, which is the core issue addressed in this PR that resolves UUID leakage and value transformation problems.
Description check ✅ Passed The pull request description clearly relates to the changeset and provides detailed context about the bug fix, implementation logic, and testing performed.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx`:
- Around line 227-321: In setOp, normalize value shapes for all exact-ID
operator transitions: when switching to multi-ID ops (use isMultiIdOp(nextOp)),
always dispatch set-value with an array (e.g., [id] or []), and when switching
to single-ID ops (isSingleIdOp(nextOp)), unwrap single-element arrays into a
bare string or '' if none; update the Text→Multi and Text→Single branches that
call resolveTextToId (use resolvedValue ? [resolvedValue] : [] for multi, and
resolvedValue || '' for single) and the Multi→Text/Single→Text branches to
unwrap arrays (use value[0] when Array.isArray(value)). Also ensure transitions
from contains/matches/doesNotContain → oneOf/notOneOf set [] on failed lookup
instead of leaving the old string, and in the account no-value branches (field
=== 'account' && isNoValueAccountOp(op)) preserve existing ID arrays when
returning to single/multi ID ops (if value is already an array, keep or unwrap
it appropriately) — use the helper functions resolveTextToId and resolveIdToText
and always call dispatch({type: 'set-value', value: ...}) with the normalized
shape before dispatch({type: 'set-op', op: nextOp}).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d39d12fe-c9df-4294-a7d4-0ebd3b368ccf

📥 Commits

Reviewing files that changed from the base of the PR and between 8504a5a and 2429bcc.

📒 Files selected for processing (2)
  • packages/desktop-client/src/components/filters/FiltersMenu.tsx
  • upcoming-release-notes/7304.md

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (2)
packages/desktop-client/src/components/filters/FiltersMenu.tsx (2)

236-267: ⚠️ Potential issue | 🟠 Major

Clear unmatched names before entering exact-ID operators.

If lookup fails here, the exact-match branches keep free text in state (is/isNot keep the raw string, oneOf/notOneOf can end up with raw text, and the no-value account path falls back to value/[value]). That breaks the new “exact ops store IDs only” contract and can hand invalid values to the exact-ID inputs or validator.

Suggested fix
   if (isIdField && isTextOp(op) && isSingleIdOp(nextOp)) {
     const resolvedValue = resolveTextToId(field, subfield, value);
-    if (resolvedValue) {
-      dispatch({
-        type: 'set-value',
-        value: resolvedValue,
-      });
-    }
+    dispatch({
+      type: 'set-value',
+      value: resolvedValue ?? '',
+    });
   }
@@
   if (isIdField && isTextOp(op) && isMultiIdOp(nextOp)) {
     const resolvedValue = resolveTextToId(field, subfield, value);
-    if (resolvedValue) {
-      dispatch({
-        type: 'set-value',
-        value: resolvedValue ? [resolvedValue] : [],
-      });
-    }
+    dispatch({
+      type: 'set-value',
+      value: resolvedValue ? [resolvedValue] : [],
+    });
   }
@@
   if (field === 'account' && isNoValueAccountOp(op) && isSingleIdOp(nextOp)) {
     if (typeof value === 'string') {
-      const resolvedValue = resolveTextToId(field, subfield, value);
+      const resolvedValue =
+        resolveIdToText(field, subfield, value) !== ''
+          ? value
+          : resolveTextToId(field, subfield, value);
       dispatch({
         type: 'set-value',
-        value: resolvedValue || value,
+        value: resolvedValue ?? '',
       });
     } else {
       dispatch({
         type: 'set-value',
         value: '',
@@
   if (field === 'account' && isNoValueAccountOp(op) && isMultiIdOp(nextOp)) {
     if (typeof value === 'string') {
-      const resolvedValue = resolveTextToId(field, subfield, value);
+      const resolvedValue =
+        resolveIdToText(field, subfield, value) !== ''
+          ? value
+          : resolveTextToId(field, subfield, value);

       dispatch({
         type: 'set-value',
-        value: resolvedValue ? [resolvedValue] : [value],
+        value: resolvedValue ? [resolvedValue] : [],
       });
     } else {
       dispatch({
         type: 'set-value',
         value: [],

Also applies to: 289-313

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx` around lines
236 - 267, When converting text -> exact-ID operators in FiltersMenu (the
branches that call resolveTextToId and then dispatch 'set-value'), ensure that a
failed lookup clears the value instead of leaving raw free-text: if
resolveTextToId(field, subfield, value) returns falsy, dispatch set-value with
'' for single-ID operators (is/isNot) and [] for multi-ID operators
(oneOf/notOneOf); apply the same clearing logic to the corresponding mirrored
branches (the other text->ID and multi-ID->text conversion blocks) so no raw
string can be kept when entering exact-ID operators.

227-321: ⚠️ Potential issue | 🟠 Major

Preserve multi-account selections when switching into onBudget/offBudget.

There’s still no isMultiIdOp(op) && isNoValueAccountOp(nextOp) path, so this falls through to packages/desktop-client/src/components/filters/updateFilterReducer.ts and unwraps the array to its first ID. Toggling back from a no-value account operator then cannot recover the original multi-selection.

Suggested fix
   const setOp = (nextOp: T['op']) => {
+    if (field === 'account' && isMultiIdOp(op) && isNoValueAccountOp(nextOp)) {
+      dispatch({ type: 'set-op', op: nextOp });
+      dispatch({ type: 'set-value', value });
+      return;
+    }
+
     // Single ID -> Text: Convert stored ID to text with one to one mapping
     if (isIdField && isSingleIdOp(op) && isTextOp(nextOp)) {
       dispatch({
         type: 'set-value',
         value: resolveIdToText(field, subfield, value),
@@
     // No-value Account -> Single-ID: If preserved value is text, resolve to an ID;
     // If it is already a single ID string, keep as-is
     if (field === 'account' && isNoValueAccountOp(op) && isSingleIdOp(nextOp)) {
-      if (typeof value === 'string') {
+      if (Array.isArray(value)) {
+        dispatch({
+          type: 'set-value',
+          value: value[0] ?? '',
+        });
+      } else if (typeof value === 'string') {
         const resolvedValue = resolveTextToId(field, subfield, value);
         dispatch({
           type: 'set-value',
           value: resolvedValue || value,
         });
@@
     // No-value Account -> Multi-ID: If the preserved value is text, resolve to a single ID and wrap;
     // if the preserved value is already a single ID string, wrap it directly;
     // otherwise clear
     if (field === 'account' && isNoValueAccountOp(op) && isMultiIdOp(nextOp)) {
-      if (typeof value === 'string') {
+      if (Array.isArray(value)) {
+        dispatch({
+          type: 'set-value',
+          value,
+        });
+      } else if (typeof value === 'string') {
         const resolvedValue = resolveTextToId(field, subfield, value);

         dispatch({
           type: 'set-value',
           value: resolvedValue ? [resolvedValue] : [value],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx` around lines
227 - 321, The setOp handler is missing a branch for when switching from a
multi-ID operator into a no-value account operator, causing the array to be
unwrapped later; add a case in setOp that checks if field === 'account' &&
isMultiIdOp(op) && isNoValueAccountOp(nextOp) and dispatches { type:
'set-value', value: Array.isArray(value) ? value : [] } (preserving the
multi-selection) before the final dispatch({ type: 'set-op', op: nextOp });
reference setOp, isMultiIdOp, isNoValueAccountOp, dispatch, field, and value.
🧹 Nitpick comments (1)
packages/desktop-client/src/components/filters/FiltersMenu.tsx (1)

147-158: Prefer function declarations for these op classifiers.

These helpers are pure, and the repo rule prefers function over const arrows here.

As per coding guidelines, "packages//src/**/.{ts,tsx,js}: Use the function keyword for pure functions instead of arrow functions or const declarations"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx` around lines
147 - 158, Change the op-classifier helpers from const arrow assignments to
named function declarations: replace isPayeeIdOp, isSingleIdOp, isMultiIdOp,
isTextOp, and isNoValueAccountOp (currently defined as const <name> = (op:
T['op']) => ...) with function <name>(op: T['op']) { ... } forms so they follow
the repo guideline to use the `function` keyword for pure helpers; keep the same
logic and return values and ensure exported/local references remain unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx`:
- Around line 236-267: When converting text -> exact-ID operators in FiltersMenu
(the branches that call resolveTextToId and then dispatch 'set-value'), ensure
that a failed lookup clears the value instead of leaving raw free-text: if
resolveTextToId(field, subfield, value) returns falsy, dispatch set-value with
'' for single-ID operators (is/isNot) and [] for multi-ID operators
(oneOf/notOneOf); apply the same clearing logic to the corresponding mirrored
branches (the other text->ID and multi-ID->text conversion blocks) so no raw
string can be kept when entering exact-ID operators.
- Around line 227-321: The setOp handler is missing a branch for when switching
from a multi-ID operator into a no-value account operator, causing the array to
be unwrapped later; add a case in setOp that checks if field === 'account' &&
isMultiIdOp(op) && isNoValueAccountOp(nextOp) and dispatches { type:
'set-value', value: Array.isArray(value) ? value : [] } (preserving the
multi-selection) before the final dispatch({ type: 'set-op', op: nextOp });
reference setOp, isMultiIdOp, isNoValueAccountOp, dispatch, field, and value.

---

Nitpick comments:
In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx`:
- Around line 147-158: Change the op-classifier helpers from const arrow
assignments to named function declarations: replace isPayeeIdOp, isSingleIdOp,
isMultiIdOp, isTextOp, and isNoValueAccountOp (currently defined as const <name>
= (op: T['op']) => ...) with function <name>(op: T['op']) { ... } forms so they
follow the repo guideline to use the `function` keyword for pure helpers; keep
the same logic and return values and ensure exported/local references remain
unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 14f02f09-9109-4b0b-a59e-34113755346e

📥 Commits

Reviewing files that changed from the base of the PR and between 2429bcc and c777c68.

📒 Files selected for processing (2)
  • packages/desktop-client/src/components/filters/FiltersMenu.tsx
  • upcoming-release-notes/7304.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • upcoming-release-notes/7304.md

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/src/components/filters/FiltersMenu.tsx`:
- Around line 521-524: The render condition in FiltersMenu.tsx prevents account
filters from showing inputs by including `field !== 'account'`; remove that
`field !== 'account'` guard so account filters are allowed to render when they
have values — keep the existing checks `type !== 'boolean'`, `(field !== 'payee'
|| !isPayeeIdOp(op))`, and `!isNoValueAccountOp(op)` so the
`onBudget`/`offBudget` no-value operators still hide the editor while normal
`is`, `contains`, `matches`, `oneOf`, etc. render correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b4378683-e308-4d77-9993-955c56ac8a04

📥 Commits

Reviewing files that changed from the base of the PR and between c777c68 and be9e4bd.

📒 Files selected for processing (1)
  • packages/desktop-client/src/components/filters/FiltersMenu.tsx

@sk10727-a11y sk10727-a11y changed the title Fix filter operator switching behavior [WIP] Fix filter operator switching behavior Mar 27, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 27, 2026
@sk10727-a11y sk10727-a11y changed the title [WIP] Fix filter operator switching behavior Fix filter operator switching behavior Mar 27, 2026
@matt-fidd matt-fidd force-pushed the master branch 2 times, most recently from 5c7c70d to d262f7d Compare April 5, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Changing Category Group from is to contains replaces budget with the raw UUID

1 participant