-
Notifications
You must be signed in to change notification settings - Fork 1
MILAB-6002: fix PlDataTable column visibility reset on re-run with changed filters #1666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
PaulNewling
wants to merge
13
commits into
main
Choose a base branch
from
MILAB-6002_table-visibility-deviations
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
db9c6ca
MILAB-6002: fix PlDataTable column visibility reset on re-run
PaulNewling 96f7580
MILAB-6002: address review feedback and polish docs
PaulNewling c2e034e
MILAB-6002: share column-visibility reconciliation via resolveColumnH…
PaulNewling 7a1b48d
MILAB-6002: set shownColIds to null in default PTable params
PaulNewling 4052595
MILAB-6002: address review feedback (semver, makeColDef sets, docs)
PaulNewling fb37c94
MILAB-6002: make deprecated createPlDataTableV2 deviation-aware
PaulNewling f3a73ad
MILAB-6002: guard saved column visibility against a not-ready grid; s…
PaulNewling ced539f
MILAB-6002: fix migrateV7toV8 input aliasing; expand model test coverage
PaulNewling dab39ba
MILAB-6002: make makePartialState's prior-state dependency explicit
PaulNewling 6000b48
MILAB-6002: align migrateV7toV8 pTableParams handling with migrateV6toV7
PaulNewling dd9ad7b
MILAB-6002: route createPlDataTableV2 through computeHiddenColumns
PaulNewling 917ae13
MILAB-6002: drop dead optional chaining in stateForReloadCompare
PaulNewling effebc4
MILAB-6002: tighten changeset wording
PaulNewling File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| '@platforma-sdk/model': minor | ||
| '@platforma-sdk/ui-vue': patch | ||
| --- | ||
|
|
||
| PlDataTable: persist column visibility as user deviations from block defaults | ||
|
|
||
| Column visibility reset when a block re-ran with a changed filter/ranking | ||
| configuration (MILAB-6002). The saved grid state stored the absolute | ||
| hidden-column set, which once present overrode the block's default visibility. A | ||
| column whose default flipped between runs — e.g. a filter/ranking column | ||
| reverting to `optional` when its filter is removed — stayed visible instead of | ||
| reverting to hidden. | ||
|
|
||
| Column visibility is now the user's explicit show/hide deviations from the | ||
| block's `pl7.app/table/visibility` default, so the current default always applies | ||
| to untouched columns. Persisted state migrates v7 -> v8: a one-time reset of | ||
| custom column show/hide, after which defaults apply correctly. | ||
|
|
||
| Adds `resolveColumnHidden` to the public model API — the shared default-vs-override | ||
| precedence used by the visible table handle and the grid — so this is a `minor` bump. | ||
|
|
||
| Also routes the deprecated `createPlDataTableV2` path through the shared | ||
| `computeHiddenColumns`, so the ~29 blocks still on it reconcile the same deviations (and | ||
| honour `shownColIds`) as the grid instead of misreading the lists as an absolute hidden | ||
| set — which over-included columns once visibility was customised. |
76 changes: 76 additions & 0 deletions
76
sdk/model/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import { | ||
| Annotation, | ||
| type PColumnSpec, | ||
| type PObjectId, | ||
| type PTableColumnId, | ||
| } from "@milaboratories/pl-model-common"; | ||
| import { describe, expect, test } from "vitest"; | ||
| import { computeHiddenColumnsV2 } from "./createPlDataTableV2"; | ||
|
|
||
| function col(id: string, visibility?: "optional" | "hidden"): { id: PObjectId; spec: PColumnSpec } { | ||
| return { | ||
| id: id as PObjectId, | ||
| spec: { | ||
| kind: "PColumn", | ||
| name: id, | ||
| valueType: "Int", | ||
| axesSpec: [], | ||
| annotations: visibility ? { [Annotation.Table.Visibility]: visibility } : {}, | ||
| } as PColumnSpec, | ||
| }; | ||
| } | ||
|
|
||
| const colRef = (id: string): PTableColumnId => | ||
| ({ type: "column", id: id as PObjectId }) as PTableColumnId; | ||
|
|
||
| const hiddenIds = (s: Set<PObjectId>): string[] => [...s].sort(); | ||
|
|
||
| describe("computeHiddenColumnsV2 (deviation-aware)", () => { | ||
| test("with no overrides, hides optional columns and shows the rest", () => { | ||
| const cols = [col("visible"), col("opt", "optional")]; | ||
| expect(hiddenIds(computeHiddenColumnsV2(cols, null, null))).toEqual(["opt"]); | ||
| }); | ||
|
|
||
| test("a user-hidden column (block default visible) becomes hidden", () => { | ||
| const cols = [col("a"), col("b")]; | ||
| expect(hiddenIds(computeHiddenColumnsV2(cols, [colRef("a")], null))).toEqual(["a"]); | ||
| }); | ||
|
|
||
| test("a user-shown column (block default optional) becomes visible", () => { | ||
| const cols = [col("a", "optional"), col("b", "optional")]; | ||
| expect(hiddenIds(computeHiddenColumnsV2(cols, null, [colRef("a")]))).toEqual(["b"]); | ||
| }); | ||
|
|
||
| // Regression for the old absolute-set reader: a non-null hide list was treated as | ||
| // "hide exactly these", so an empty list (user only showed a column) unhid EVERY | ||
| // optional column. Deviations must keep untouched optional columns hidden. | ||
| test("empty hiddenColIds with a show-override keeps other optional columns hidden", () => { | ||
| const cols = [col("opt1", "optional"), col("opt2", "optional")]; | ||
| expect(hiddenIds(computeHiddenColumnsV2(cols, [], [colRef("opt1")]))).toEqual(["opt2"]); | ||
| }); | ||
|
|
||
| // MILAB-6002: an untouched column follows its CURRENT default across re-runs, | ||
| // rather than being pinned by a stale saved set. | ||
| test("a column whose default flips to optional is re-hidden when untouched", () => { | ||
| expect(hiddenIds(computeHiddenColumnsV2([col("flip")], null, null))).toEqual([]); | ||
| expect(hiddenIds(computeHiddenColumnsV2([col("flip", "optional")], null, null))).toEqual([ | ||
| "flip", | ||
| ]); | ||
| }); | ||
|
|
||
| // Forced-hidden (`visibility: "hidden"`) columns are dropped from the visible table, | ||
| // matching V3 and the grid (delegates to computeHiddenColumns). Guards against | ||
| // regressing V2 back to leaving them in. | ||
| test("a forced-hidden column is hidden", () => { | ||
| expect(hiddenIds(computeHiddenColumnsV2([col("forced", "hidden")], null, null))).toEqual([ | ||
| "forced", | ||
| ]); | ||
| }); | ||
|
|
||
| // Axis references in the override lists are ignored (only column overrides apply). | ||
| test("axis-type override entries are ignored", () => { | ||
| const cols = [col("a")]; | ||
| const axisRef = { type: "axis", id: { name: "x" } } as unknown as PTableColumnId; | ||
| expect(hiddenIds(computeHiddenColumnsV2(cols, [axisRef], null))).toEqual([]); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
sdk/model/src/components/PlDataTable/createPlDataTable/createPlDataTableV3.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| import { | ||
| Annotation, | ||
| type PColumnSpec, | ||
| type PObjectId, | ||
| type PTableColumnId, | ||
| type PTableSorting, | ||
| } from "@milaboratories/pl-model-common"; | ||
| import { describe, expect, test } from "vitest"; | ||
| import { computeHiddenColumns } from "./createPlDataTableV3"; | ||
|
|
||
| function col(id: string, visibility?: "optional" | "hidden"): { id: PObjectId; spec: PColumnSpec } { | ||
| return { | ||
| id: id as PObjectId, | ||
| spec: { | ||
| kind: "PColumn", | ||
| name: id, | ||
| valueType: "Int", | ||
| axesSpec: [], | ||
| annotations: visibility ? { [Annotation.Table.Visibility]: visibility } : {}, | ||
| } as PColumnSpec, | ||
| }; | ||
| } | ||
|
|
||
| const colRef = (id: string): PTableColumnId => | ||
| ({ type: "column", id: id as PObjectId }) as PTableColumnId; | ||
|
|
||
| const hiddenIds = (s: Set<PObjectId>): string[] => [...s].sort(); | ||
|
|
||
| describe("computeHiddenColumns", () => { | ||
| test("with no saved overrides, hides forced-hidden and optional columns and shows the rest", () => { | ||
| const cols = [col("visible"), col("opt", "optional"), col("hid", "hidden")]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, null, null, null, null))).toEqual(["hid", "opt"]); | ||
| }); | ||
|
|
||
| test("a user-hidden column (block default visible) becomes hidden", () => { | ||
| const cols = [col("a"), col("b")]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, null, null, [colRef("a")], null))).toEqual(["a"]); | ||
| }); | ||
|
|
||
| test("a user-shown column (block default optional) becomes visible", () => { | ||
| const cols = [col("a", "optional"), col("b", "optional")]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, null, null, null, [colRef("a")]))).toEqual(["b"]); | ||
| }); | ||
|
|
||
| test("show overrides win over hide overrides", () => { | ||
| const cols = [col("a")]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, null, null, [colRef("a")], [colRef("a")]))).toEqual( | ||
| [], | ||
| ); | ||
| }); | ||
|
|
||
| test("forced-hidden columns stay hidden even when the user showed them", () => { | ||
| const cols = [col("a", "hidden")]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, null, null, null, [colRef("a")]))).toEqual(["a"]); | ||
| }); | ||
|
|
||
| // MILAB-6002 regression: an untouched column follows its CURRENT default across | ||
| // re-runs, rather than being pinned by a stale saved hidden set. | ||
| test("a column whose default flips to optional is re-hidden when untouched", () => { | ||
| expect(hiddenIds(computeHiddenColumns([col("flip")], null, null, null, null))).toEqual([]); | ||
| expect( | ||
| hiddenIds(computeHiddenColumns([col("flip", "optional")], null, null, null, null)), | ||
| ).toEqual(["flip"]); | ||
| }); | ||
|
|
||
| test("sorted columns are force-kept visible even when optional", () => { | ||
| const cols = [col("a", "optional")]; | ||
| const sorting = [{ column: colRef("a") }] as unknown as PTableSorting[]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, sorting, null, null, null))).toEqual([]); | ||
| }); | ||
|
|
||
| // Preservation (collectPreservedColumnIds) wins over an explicit user hide: a column the | ||
| // user hid but is now sorted/filtered is force-kept visible so the active sort/filter has | ||
| // its data. Pins the precedence between resolveColumnHidden and preservation — the grid's | ||
| // makeColDef does NOT preserve, so the column is in the model's visible table yet hidden in | ||
| // the grid (intended "sort by hidden column"; see the model/UI divergence note). | ||
| test("a sorted column the user explicitly hid is still force-kept visible", () => { | ||
| const cols = [col("a")]; // block default visible | ||
| const sorting = [{ column: colRef("a") }] as unknown as PTableSorting[]; | ||
| expect(hiddenIds(computeHiddenColumns(cols, sorting, null, [colRef("a")], null))).toEqual([]); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why separate function? this is a one-liner, let's inline it