fix(query): isolate viewbox filter state from the base table's #282

Merged
allan merged 5 commits from issue-239 into additional-validations-regex 2026-07-24 14:24:31 +00:00
Owner

ViewBox filter incorrect when base table is filtered

Issue

Closes #239

Summary

  • The base VIEW table and any open viewbox on a different table were sharing a single
    cached filter-dialog state whenever the viewbox was opened from the VIEW page — filtering
    one would silently show up in the other's filter dialog, in both directions.
  • Root cause: QueryComponent (the shared filter dialog used by the VIEW page, the EDITOR
    page, and viewboxes alike) picks which bucket of the globals filter cache to read/write
    via an inline computation duplicated four times in query.component.ts. All four checked
    viewboxId only when rootParam was 'home'/'editor' — never when it was 'view', so
    a viewbox opened from the VIEW page fell straight through to the base table's own
    globals.viewer.filter bucket instead of its own globals.viewboxes[id].filter.
  • Fix: extracted the routing logic into one pure, unit-tested function,
    getFilterObjPath(rootParam, viewboxId), which checks viewboxId first and
    unconditionally. All four call sites now delegate to it instead of repeating the
    conditional.
  • Also fixed a related crash found while reproducing: an unguarded
    $dataformats.vars[column].type access in viewboxes.component.html that throws when
    column isn't a key in the map. Investigated first — traced hotColumns
    (colHeadersVisible) back to the same selectedViewboxTable.hotTable source as
    $dataformats, so this is not the same root cause as the filter-crossing bug (both
    are read synchronously from one object); it's a separate, narrower guard.

Changes

File Change
client/src/app/query/utils/getFilterObjPath.ts (new) Pure function resolving the filter-cache bucket path. viewboxId wins, unconditionally.
client/src/app/query/utils/getFilterObjPath.spec.ts (new) 7 unit tests, including the exact regression case (('view', 42)'viewboxes.42', previously 'viewer').
client/src/app/query/query.component.ts All four inline objPath computations (setToGlobals, getFromGlobals, the columnsSub/valuesSub subscriptions) replaced with calls to getFilterObjPath. Also collapses valuesSub's two now-identical branches (previously duplicated only because of the hardcoded bucket names) into one.
client/src/app/shared/viewboxes/viewboxes.component.html Added optional chaining through $dataformats?.vars?.[column]?.type to stop a TypeError when a visible column isn't present in the data-formats map.
client/cypress/e2e/viewbox.cy.ts Replaced a long-disabled, unrelated commented-out test with an active one covering both directions of the bug: filter the base table → open a viewbox on a different table → its dialog must not show the base filter; then filter the viewbox → reopen the base table's dialog → it must still show its own filter.
# ViewBox filter incorrect when base table is filtered ## Issue Closes #239 ## Summary - The base VIEW table and any open viewbox on a different table were sharing a single cached filter-dialog state whenever the viewbox was opened from the VIEW page — filtering one would silently show up in the other's filter dialog, in both directions. - Root cause: `QueryComponent` (the shared filter dialog used by the VIEW page, the EDITOR page, and viewboxes alike) picks which bucket of the `globals` filter cache to read/write via an inline computation duplicated four times in `query.component.ts`. All four checked `viewboxId` only when `rootParam` was `'home'`/`'editor'` — never when it was `'view'`, so a viewbox opened from the VIEW page fell straight through to the base table's own `globals.viewer.filter` bucket instead of its own `globals.viewboxes[id].filter`. - Fix: extracted the routing logic into one pure, unit-tested function, `getFilterObjPath(rootParam, viewboxId)`, which checks `viewboxId` first and unconditionally. All four call sites now delegate to it instead of repeating the conditional. - Also fixed a related crash found while reproducing: an unguarded `$dataformats.vars[column].type` access in `viewboxes.component.html` that throws when `column` isn't a key in the map. Investigated first — traced `hotColumns` (`colHeadersVisible`) back to the same `selectedViewboxTable.hotTable` source as `$dataformats`, so this is **not** the same root cause as the filter-crossing bug (both are read synchronously from one object); it's a separate, narrower guard. ## Changes | File | Change | |---|---| | `client/src/app/query/utils/getFilterObjPath.ts` (new) | Pure function resolving the filter-cache bucket path. `viewboxId` wins, unconditionally. | | `client/src/app/query/utils/getFilterObjPath.spec.ts` (new) | 7 unit tests, including the exact regression case (`('view', 42)` → `'viewboxes.42'`, previously `'viewer'`). | | `client/src/app/query/query.component.ts` | All four inline `objPath` computations (`setToGlobals`, `getFromGlobals`, the `columnsSub`/`valuesSub` subscriptions) replaced with calls to `getFilterObjPath`. Also collapses `valuesSub`'s two now-identical branches (previously duplicated only because of the hardcoded bucket names) into one. | | `client/src/app/shared/viewboxes/viewboxes.component.html` | Added optional chaining through `$dataformats?.vars?.[column]?.type` to stop a `TypeError` when a visible column isn't present in the data-formats map. | | `client/cypress/e2e/viewbox.cy.ts` | Replaced a long-disabled, unrelated commented-out test with an active one covering both directions of the bug: filter the base table → open a viewbox on a different table → its dialog must not show the base filter; then filter the viewbox → reopen the base table's dialog → it must still show its own filter. |
Yury added 1 commit 2026-07-24 09:31:03 +00:00
fix(query): isolate viewbox filter state from the base table's
Build / Build-and-ng-test (pull_request) Successful in 5m8s
Build / Build-and-test-development (pull_request) Successful in 15m11s
Lighthouse Checks / lighthouse (pull_request) Successful in 21m21s
7a35cf4a45
Also guards $dataformats.vars[column] in viewboxes.component.html against
a column not present in the map (unrelated crash hit while reproducing).
Yury added 1 commit 2026-07-24 10:12:17 +00:00
chore: added viewbox.cy.ts to CI tests
Build / Build-and-ng-test (pull_request) Successful in 4m54s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m0s
Build / Build-and-test-development (pull_request) Failing after 21m21s
ee4e9b9271
Yury added 1 commit 2026-07-24 13:21:54 +00:00
test(cypress): fix flaky viewbox.cy.ts assertions and DOM lookups
Build / Build-and-ng-test (pull_request) Successful in 5m53s
Lighthouse Checks / lighthouse (pull_request) Successful in 22m19s
Build / Build-and-test-development (pull_request) Successful in 20m2s
37a98e1d64
Replace one-shot .then()/for-loop matching with retrying .should()/cy.contains()
lookups, drop stale cached DOM node references (viyaLib) in favor of live re-queries.
Yury requested review from allan 2026-07-24 13:54:09 +00:00
Yury requested review from sead 2026-07-24 13:54:10 +00:00
Yury added 1 commit 2026-07-24 13:54:28 +00:00
Merge branch 'additional-validations-regex' into issue-239
Build / Build-and-test-development (pull_request) Canceled after 0s
Build / Build-and-ng-test (pull_request) Canceled after 1m15s
Lighthouse Checks / lighthouse (pull_request) Canceled after 1m17s
7050808d80
allan added 1 commit 2026-07-24 13:54:53 +00:00
Merge branch 'additional-validations-regex' into issue-239
Build / Build-and-ng-test (pull_request) Successful in 4m53s
Lighthouse Checks / lighthouse (pull_request) Successful in 20m48s
Build / Build-and-test-development (pull_request) Successful in 19m27s
5c56c7579f
allan merged commit 8efea8c744 into additional-validations-regex 2026-07-24 14:24:31 +00:00
allan deleted branch issue-239 2026-07-24 14:24:31 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dc/dc#282