@marimo-team/islands 0.25.3-dev192 → 0.25.3-dev196
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ConnectedDataExplorerComponent-BBbOElk3.js → ConnectedDataExplorerComponent-BRuwLOIx.js} +9 -9
- package/dist/{ErrorBoundary-Dw6uRKVk.js → ErrorBoundary-C3Xv3yzV.js} +2 -2
- package/dist/{abnfDiagram-VCTEODGH-DhMT6Uhd.js → abnfDiagram-VCTEODGH-LlJTOOU_.js} +2 -2
- package/dist/{architectureDiagram-5GKGNRK7-BVbEiJLq.js → architectureDiagram-5GKGNRK7-9PQtGLLZ.js} +1 -1
- package/dist/{arrays-R6JsImiT.js → arrays-DA6KkLfq.js} +6 -12
- package/dist/assets/__vite-browser-external-BCJsx8QS.js +1 -0
- package/dist/assets/{worker-C6e9ERyd.js → worker-DodjWT_Z.js} +2 -2
- package/dist/{capabilities-CI4xUPsp.js → capabilities-CvWU-ey_.js} +1 -1
- package/dist/{chat-ui-BguxTQEL.js → chat-ui-Bl2euMBD.js} +93 -93
- package/dist/{chunk-IMKFNOWR-By5hSbJJ.js → chunk-IMKFNOWR-DcXv-BD5.js} +1 -1
- package/dist/{chunk-SHT3W25Y-DFrEYG54.js → chunk-SHT3W25Y-VwnELN23.js} +1 -1
- package/dist/{chunk-SVP7TREG-DFXGc9ew.js → chunk-SVP7TREG-DgQpI5Zi.js} +1 -1
- package/dist/{chunk-TICWLB2K-DZdNIpoZ.js → chunk-TICWLB2K-CTg6VTJT.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-Cgj_eEQA.js → classDiagram-ZZMXUADV-UzmcFrnW.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-DLAUrSqj.js → classDiagram-v2-VYDZK3BY-DhjiI6IQ.js} +2 -2
- package/dist/{code-visibility-v_7ijLtx.js → code-visibility-BCcqmP58.js} +38 -42
- package/dist/{common-BUwWHpnK.js → common-DrNB2bY2.js} +849 -849
- package/dist/{cynefinDiagram-5FMLGOSQ-Cikf9AKa.js → cynefinDiagram-5FMLGOSQ-O4ShIbJX.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-C5KEi5_l.js → dagre-GXQ25YYZ-dtHhhcPu.js} +1 -1
- package/dist/{data-grid-overlay-editor-4IZymnXZ.js → data-grid-overlay-editor-TGXV_Hf4.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BaoBTQjR.js → diagram-S7CK7UJ4-ppPYVZ6W.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-DDufBsUA.js → diagram-UQ7AKVKN-CMZDf--k.js} +1 -1
- package/dist/{diagram-VX7I27RA-CY6RALJ8.js → diagram-VX7I27RA-CFvJdx-C.js} +1 -1
- package/dist/{diagram-Z3DM3KII-Bc-LHsD6.js → diagram-Z3DM3KII-Dt6_uFbv.js} +1 -1
- package/dist/{dropdown-menu-drDjxJyV.js → dropdown-menu-CeaOsjWZ.js} +2 -2
- package/dist/{ebnfDiagram-PWID7BFC-Cz0J-tcC.js → ebnfDiagram-PWID7BFC-DpRFrKK-.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-DTXTDgFu.js → erDiagram-RLTQ6QDP-CqAU4b0u.js} +1 -1
- package/dist/{error-entries-CZ1NQ6Kv.js → error-entries-CYGwr5-O.js} +5596 -6012
- package/dist/feedback-button-PTiPn2GP.js +374 -0
- package/dist/{flowDiagram-HODETNUW-RbwWf2zc.js → flowDiagram-HODETNUW-i8-Gw8HO.js} +2 -2
- package/dist/{formats-DbXnijtH.js → formats-BtoHHy42.js} +1 -1
- package/dist/{glide-data-editor-DU8_EDG5.js → glide-data-editor-BSyexjkB.js} +5 -5
- package/dist/{globals-BeBDOk22.js → globals-B7gkJAxm.js} +2 -2
- package/dist/{html-to-image-D_4_hQ8U.js → html-to-image-Cy5UDpQJ.js} +56 -56
- package/dist/{infoDiagram-27XIBGKW-DlmzZjmI.js → infoDiagram-27XIBGKW-DpfOKdLL.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-EN3TYP_q.js → ishikawaDiagram-5VMMS53U-Dg7mrMG7.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-CK_-Ru7Q.js → kanban-definition-UXKFOSKX-QB6e3Jrj.js} +1 -1
- package/dist/main.js +5875 -5876
- package/dist/{mermaid-DU9ZRmkG.js → mermaid-CeWG4Egr.js} +48 -48
- package/dist/{mindmap-definition-YA3MSWOX-C-hqgUvF.js → mindmap-definition-YA3MSWOX-BTz3uTGe.js} +1 -1
- package/dist/{number-overlay-editor-BoIkyh6H.js → number-overlay-editor-Bb91yQ46.js} +1 -1
- package/dist/{once-eG8Vmvjd.js → once-DWGO2mQ2.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-BiMejYPB.js → pegDiagram-XKGWAZYB-3ZIEa3mB.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-B1zCZ1eq.js → pieDiagram-E7YTZNPT-BJAlk046.js} +1 -1
- package/dist/{process-output-DxSCHBWp.js → process-output-q9MTAIMX.js} +2 -2
- package/dist/{railroadDiagram-O6MQD6OU-BLcfaASl.js → railroadDiagram-O6MQD6OU-Dn3bsSRa.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-DtBOf52-.js → requirementDiagram-BXWQKSXE-wcOmQQCL.js} +1 -1
- package/dist/{reveal-component-5M3a2rpj.js → reveal-component-vTdjiyDv.js} +17 -17
- package/dist/{sequenceDiagram-WJ2MYXX4-DIwF19_n.js → sequenceDiagram-WJ2MYXX4-DSh_qxoF.js} +1 -1
- package/dist/{spec-DZDnnlgT.js → spec-C7Fos-If.js} +1 -1
- package/dist/{stateDiagram-D77RDMKH-sWk1AdYL.js → stateDiagram-D77RDMKH-DH_H8NMH.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-CiNo-OI7.js → stateDiagram-v2-MP3YSRHH-D_JM7MEK.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Bj3hiOY5.js → swimlanes-42K2YHIH-CfoTJO-9.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-BzEo2r_N.js → swimlanesDiagram-VR7AAH4N-Z_QhvK0G.js} +2 -2
- package/dist/{swiper-component-BkCm-kLg.js → swiper-component-D2geL1Ku.js} +1 -1
- package/dist/{timeline-definition-24CTP7MA-CrPQk42H.js → timeline-definition-24CTP7MA-BFtdScaL.js} +1 -1
- package/dist/{toDate-Cu2pIZcC.js → toDate-CQAFSwos.js} +24 -24
- package/dist/{useAsyncData-DEhLdRIu.js → useAsyncData-BeyZyjso.js} +1 -1
- package/dist/{useDeepCompareMemoize-RjZGVhBV.js → useDeepCompareMemoize-DOQgae0W.js} +1 -1
- package/dist/{useIframeCapabilities-CSdWn6NP.js → useIframeCapabilities-DNvaj9wM.js} +1 -1
- package/dist/{useLifecycle-DtcB2s1z.js → useLifecycle-n2lnCFS8.js} +1 -1
- package/dist/{useTheme-CoEtr4mK.js → useTheme-CY777LXN.js} +303 -99
- package/dist/{vega-component-BhjTrP9-.js → vega-component-0nQzA-I8.js} +6 -6
- package/dist/{vennDiagram-4TSXK5OY-BaYMoIpj.js → vennDiagram-4TSXK5OY-BXY8IGCA.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-DjHeuj8p.js → wardleyDiagram-VM6X3IG4-D0tFe6eC.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-Bc_hcuXS.js → xychartDiagram-S5SC5T6Z-Dx8wFM-y.js} +1 -1
- package/package.json +1 -1
- package/src/__mocks__/notebook.ts +0 -1
- package/src/__mocks__/partial.ts +26 -0
- package/src/__tests__/main.test.tsx +24 -1
- package/src/components/app-config/app-config-form.tsx +5 -9
- package/src/components/editor/__tests__/data-attributes.test.tsx +0 -1
- package/src/components/editor/__tests__/output-persistence.test.tsx +0 -1
- package/src/components/editor/actions/useCellActionButton.tsx +6 -5
- package/src/components/editor/actions/useConfigActions.tsx +3 -4
- package/src/components/editor/actions/useNotebookActions.tsx +5 -4
- package/src/components/editor/cell/code/cell-editor.tsx +13 -6
- package/src/components/editor/cell/collapse.tsx +6 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +1 -7
- package/src/components/editor/controls/Controls.tsx +1 -1
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +8 -6
- package/src/components/editor/navigation/__tests__/navigation.test.ts +15 -15
- package/src/components/editor/navigation/__tests__/selection.test.ts +44 -21
- package/src/components/editor/navigation/focus-utils.ts +19 -0
- package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +6 -13
- package/src/components/editor/navigation/navigation.ts +52 -43
- package/src/components/editor/navigation/selection.ts +30 -29
- package/src/components/editor/notebook-cell.tsx +10 -18
- package/src/components/editor/renderers/cell-array.tsx +6 -5
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
- package/src/components/pages/edit-page.tsx +0 -13
- package/src/components/scratchpad/scratchpad.tsx +0 -1
- package/src/components/slides/reveal-component.tsx +1 -1
- package/src/components/slides/slide-cell-view.tsx +0 -1
- package/src/components/sort/SortableCellsProvider.tsx +6 -5
- package/src/core/MarimoApp.tsx +1 -1
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +0 -37
- package/src/core/cells/__tests__/actions.test.ts +190 -80
- package/src/core/cells/__tests__/arrange.test.ts +263 -0
- package/src/core/cells/__tests__/cells.test.ts +11 -1101
- package/src/core/cells/__tests__/document.test.ts +3 -32
- package/src/core/cells/__tests__/editor.test.ts +57 -0
- package/src/core/cells/__tests__/harness.ts +82 -0
- package/src/core/cells/__tests__/layout.test.ts +189 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +7 -1
- package/src/core/cells/__tests__/session.test.ts +329 -174
- package/src/core/cells/__tests__/utils.test.ts +0 -1
- package/src/core/cells/actions.ts +247 -82
- package/src/core/cells/arrange.ts +341 -0
- package/src/core/cells/cells.ts +27 -516
- package/src/core/cells/document.ts +6 -5
- package/src/core/cells/edit.ts +30 -0
- package/src/core/cells/editor.ts +82 -0
- package/src/core/cells/layout.ts +152 -0
- package/src/core/cells/session.ts +75 -52
- package/src/core/cells/types.ts +0 -5
- package/src/core/cells/utils.ts +6 -4
- package/src/core/config/__tests__/app-config.test.ts +64 -0
- package/src/core/config/__tests__/config-schema.test.ts +1 -1
- package/src/core/config/config-schema.ts +6 -2
- package/src/core/config/config.ts +26 -12
- package/src/core/islands/bootstrap.ts +0 -1
- package/src/core/kernel/handlers.ts +1 -13
- package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
- package/src/core/meta/code-visibility.ts +18 -9
- package/src/core/notebook/__tests__/operations.test.ts +51 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +33 -7
- package/src/core/notebook/index.ts +2 -1
- package/src/core/notebook/operations.ts +30 -0
- package/src/core/saving/__tests__/state.test.ts +111 -0
- package/src/core/saving/save-component.tsx +19 -33
- package/src/core/saving/state.ts +38 -39
- package/src/core/saving/useAutoSave.ts +8 -35
- package/src/core/session/__tests__/backend.test.ts +1 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +1 -0
- package/src/core/session/active-notebook.ts +11 -0
- package/src/core/session/backend.ts +17 -19
- package/src/core/session/embedded.ts +7 -0
- package/src/core/session/useNotebookReplica.ts +3 -1
- package/src/core/session/useNotebookSession.tsx +7 -8
- package/src/core/transports/__tests__/static.test.ts +139 -8
- package/src/core/transports/static.ts +98 -16
- package/src/core/wasm/__tests__/bridge.test.ts +1 -0
- package/src/mount.tsx +19 -10
- package/src/stories/cell.stories.tsx +0 -2
- package/src/stories/layout/vertical/one-column.stories.tsx +0 -2
- package/src/utils/__tests__/id-tree.test.ts +20 -1548
- package/src/utils/id-tree.tsx +12 -537
- package/dist/assets/__vite-browser-external-C8gQho07.js +0 -1
- package/dist/feedback-button-MpeoIn1D.js +0 -379
- package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
- package/src/components/editor/navigation/state.ts +0 -65
|
@@ -25,240 +25,6 @@ describe("CollapsibleTree", () => {
|
|
|
25
25
|
`);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
it("collapses nodes correctly with no end", () => {
|
|
29
|
-
const collapsedTree = tree.collapse("two", undefined);
|
|
30
|
-
expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
|
|
31
|
-
expect(collapsedTree.isCollapsed("two")).toBe(true);
|
|
32
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
33
|
-
"one
|
|
34
|
-
two (collapsed)
|
|
35
|
-
three
|
|
36
|
-
four
|
|
37
|
-
"
|
|
38
|
-
`);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it("collapses nodes correctly with an 'until' in the middle", () => {
|
|
42
|
-
const collapsedTree = tree.collapse("two", "three");
|
|
43
|
-
expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
|
|
44
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
45
|
-
"one
|
|
46
|
-
two (collapsed)
|
|
47
|
-
three
|
|
48
|
-
four
|
|
49
|
-
"
|
|
50
|
-
`);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
it("collapses nodes correctly with an 'until' at the end", () => {
|
|
54
|
-
const collapsedTree = tree.collapse("two", "four");
|
|
55
|
-
expect(collapsedTree.nodes[1].isCollapsed).toBe(true);
|
|
56
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
57
|
-
"one
|
|
58
|
-
two (collapsed)
|
|
59
|
-
three
|
|
60
|
-
four
|
|
61
|
-
"
|
|
62
|
-
`);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("collapses nodes correctly if just the last node", () => {
|
|
66
|
-
const collapsedTree = tree.collapse("four", undefined);
|
|
67
|
-
expect(collapsedTree.nodes[3].isCollapsed).toBe(true);
|
|
68
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
69
|
-
"one
|
|
70
|
-
two
|
|
71
|
-
three
|
|
72
|
-
four (collapsed)
|
|
73
|
-
"
|
|
74
|
-
`);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("collapses nodes correctly if just the first node", () => {
|
|
78
|
-
const collapsedTree = tree.collapse("one", undefined);
|
|
79
|
-
expect(collapsedTree.nodes[0].isCollapsed).toBe(true);
|
|
80
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
81
|
-
"one (collapsed)
|
|
82
|
-
two
|
|
83
|
-
three
|
|
84
|
-
four
|
|
85
|
-
"
|
|
86
|
-
`);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it("can double collapse", () => {
|
|
90
|
-
const collapsedTree = tree
|
|
91
|
-
.collapse("three", undefined)
|
|
92
|
-
.collapse("two", undefined);
|
|
93
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
94
|
-
"one
|
|
95
|
-
two (collapsed)
|
|
96
|
-
three (collapsed)
|
|
97
|
-
four
|
|
98
|
-
"
|
|
99
|
-
`);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
it("failures to collapse", () => {
|
|
103
|
-
expect(() =>
|
|
104
|
-
tree.collapse("five", undefined),
|
|
105
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
106
|
-
"[Error: Node five not found in tree. Valid ids: one,two,three,four]",
|
|
107
|
-
);
|
|
108
|
-
expect(() =>
|
|
109
|
-
tree.collapse("one", "five"),
|
|
110
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
111
|
-
"[Error: Node five not found in tree]",
|
|
112
|
-
);
|
|
113
|
-
expect(() =>
|
|
114
|
-
tree.collapse("two", "one"),
|
|
115
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
116
|
-
"[Error: Node one is before node two]",
|
|
117
|
-
);
|
|
118
|
-
expect(() => {
|
|
119
|
-
tree = tree.collapse("two", undefined);
|
|
120
|
-
tree = tree.collapse("two", undefined);
|
|
121
|
-
}).toThrowErrorMatchingInlineSnapshot(
|
|
122
|
-
"[Error: Node two is already collapsed]",
|
|
123
|
-
);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it("collapses all nodes from leaves to root in one call", () => {
|
|
127
|
-
const collapsedTree = tree.collapseAll([
|
|
128
|
-
{ id: "one", until: undefined },
|
|
129
|
-
{ id: "two", until: undefined },
|
|
130
|
-
{ id: "three", until: undefined },
|
|
131
|
-
{ id: "four", until: undefined },
|
|
132
|
-
]);
|
|
133
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
134
|
-
"one (collapsed)
|
|
135
|
-
two (collapsed)
|
|
136
|
-
three (collapsed)
|
|
137
|
-
four (collapsed)
|
|
138
|
-
"
|
|
139
|
-
`);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("collapses some nodes from leaves to root in one call", () => {
|
|
143
|
-
const collapsedTree = tree.collapseAll([
|
|
144
|
-
{ id: "one", until: undefined },
|
|
145
|
-
null,
|
|
146
|
-
{ id: "three", until: "four" },
|
|
147
|
-
null,
|
|
148
|
-
]);
|
|
149
|
-
expect(collapsedTree.toString()).toMatchInlineSnapshot(`
|
|
150
|
-
"one (collapsed)
|
|
151
|
-
two
|
|
152
|
-
three (collapsed)
|
|
153
|
-
four
|
|
154
|
-
"
|
|
155
|
-
`);
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
it("failures to collapse all", () => {
|
|
159
|
-
expect(() => tree.collapseAll([])).toThrowErrorMatchingInlineSnapshot(
|
|
160
|
-
"[Error: No collapse ranges provided]",
|
|
161
|
-
);
|
|
162
|
-
expect(() =>
|
|
163
|
-
tree.collapseAll([
|
|
164
|
-
{ id: "one", until: undefined },
|
|
165
|
-
{ id: "two", until: undefined },
|
|
166
|
-
]),
|
|
167
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
168
|
-
"[Error: Collapse ranges length 2 does not match tree length 4]",
|
|
169
|
-
);
|
|
170
|
-
expect(() =>
|
|
171
|
-
tree.collapseAll([null, { id: "one", until: undefined }, null, null]),
|
|
172
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
173
|
-
"[Error: Node two does not match collapse range id one]",
|
|
174
|
-
);
|
|
175
|
-
expect(() =>
|
|
176
|
-
tree.collapseAll([{ id: "one", until: "five" }, null, null, null]),
|
|
177
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
178
|
-
"[Error: Node five not found in tree]",
|
|
179
|
-
);
|
|
180
|
-
expect(() =>
|
|
181
|
-
tree.collapseAll([null, { id: "two", until: "one" }, null, null]),
|
|
182
|
-
).toThrowErrorMatchingInlineSnapshot(
|
|
183
|
-
"[Error: Node one is before node two]",
|
|
184
|
-
);
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
it("expands nodes correctly", () => {
|
|
188
|
-
const collapsed = tree.collapse("two", undefined);
|
|
189
|
-
expect(collapsed.nodes[1].isCollapsed).toBe(true);
|
|
190
|
-
const expandedTree = collapsed.expand("two");
|
|
191
|
-
expect(expandedTree.nodes[1].isCollapsed).toBe(false);
|
|
192
|
-
expect(expandedTree.toString()).toMatchInlineSnapshot(`
|
|
193
|
-
"one
|
|
194
|
-
two
|
|
195
|
-
three
|
|
196
|
-
four
|
|
197
|
-
"
|
|
198
|
-
`);
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
it("expands all nested collapsed nodes correctly in one call", () => {
|
|
202
|
-
let collapsed = tree.collapse("three", undefined);
|
|
203
|
-
expect(collapsed.nodes[2].isCollapsed).toBe(true);
|
|
204
|
-
collapsed = collapsed.collapse("two", undefined);
|
|
205
|
-
expect(collapsed.nodes[1].isCollapsed).toBe(true);
|
|
206
|
-
const expandedTree = collapsed.expandAll();
|
|
207
|
-
expect(expandedTree.nodes[1].isCollapsed).toBe(false);
|
|
208
|
-
expect(expandedTree.toString()).toMatchInlineSnapshot(`
|
|
209
|
-
"one
|
|
210
|
-
two
|
|
211
|
-
three
|
|
212
|
-
four
|
|
213
|
-
"
|
|
214
|
-
`);
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
it("fails to expand when node not found", () => {
|
|
218
|
-
expect(() => tree.expand("five")).toThrowErrorMatchingInlineSnapshot(
|
|
219
|
-
"[Error: Node five not found in tree. Valid ids: one,two,three,four]",
|
|
220
|
-
);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it("expand on already expanded node is a no-op", () => {
|
|
224
|
-
// Expanding an already expanded node should return the same tree (no-op)
|
|
225
|
-
const result = tree.expand("one");
|
|
226
|
-
expect(result).toBe(tree);
|
|
227
|
-
// Can call multiple times without error
|
|
228
|
-
const result2 = tree.expand("one");
|
|
229
|
-
expect(result2).toBe(tree);
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it("moves nodes correctly", () => {
|
|
233
|
-
const movedTree = tree.move(0, 1);
|
|
234
|
-
expect(movedTree.toString()).toMatchInlineSnapshot(`
|
|
235
|
-
"two
|
|
236
|
-
one
|
|
237
|
-
three
|
|
238
|
-
four
|
|
239
|
-
"
|
|
240
|
-
`);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
it("moves a collapsed node correctly", () => {
|
|
244
|
-
const collapsed = tree.collapse("two", "three");
|
|
245
|
-
expect(collapsed.toString()).toMatchInlineSnapshot(`
|
|
246
|
-
"one
|
|
247
|
-
two (collapsed)
|
|
248
|
-
three
|
|
249
|
-
four
|
|
250
|
-
"
|
|
251
|
-
`);
|
|
252
|
-
const movedTree = collapsed.move(1, 2);
|
|
253
|
-
expect(movedTree.toString()).toMatchInlineSnapshot(`
|
|
254
|
-
"one
|
|
255
|
-
four
|
|
256
|
-
two (collapsed)
|
|
257
|
-
three
|
|
258
|
-
"
|
|
259
|
-
`);
|
|
260
|
-
});
|
|
261
|
-
|
|
262
28
|
it("inserts nodes correctly", () => {
|
|
263
29
|
tree = tree.insert("newNode", 1);
|
|
264
30
|
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
@@ -294,93 +60,6 @@ describe("CollapsibleTree", () => {
|
|
|
294
60
|
`);
|
|
295
61
|
});
|
|
296
62
|
|
|
297
|
-
it("counts children correctly", () => {
|
|
298
|
-
expect(tree.getCount("who")).toBe(0);
|
|
299
|
-
expect(tree.getCount("one")).toBe(0);
|
|
300
|
-
// Collapse three and get count
|
|
301
|
-
tree = tree.collapse("three", undefined);
|
|
302
|
-
expect(tree.getCount("three")).toBe(1);
|
|
303
|
-
// Collapse two and get count
|
|
304
|
-
tree = tree.collapse("two", undefined);
|
|
305
|
-
expect(tree.getCount("two")).toBe(2);
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
it("finds deep correctly", () => {
|
|
309
|
-
expect(tree.find("three")).toEqual(["three"]);
|
|
310
|
-
tree = tree.collapse("three", undefined).collapse("two", undefined);
|
|
311
|
-
expect(tree.find("three")).toEqual(["two", "three"]);
|
|
312
|
-
expect(tree.find("four")).toEqual(["two", "three", "four"]);
|
|
313
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
314
|
-
"one
|
|
315
|
-
two (collapsed)
|
|
316
|
-
three (collapsed)
|
|
317
|
-
four
|
|
318
|
-
"
|
|
319
|
-
`);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it("finds and expands correctly at a leaf", () => {
|
|
323
|
-
tree = tree.collapse("three", undefined).collapse("two", undefined);
|
|
324
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
325
|
-
"one
|
|
326
|
-
two (collapsed)
|
|
327
|
-
three (collapsed)
|
|
328
|
-
four
|
|
329
|
-
"
|
|
330
|
-
`);
|
|
331
|
-
const prevTree = tree;
|
|
332
|
-
tree = tree.findAndExpandDeep("four");
|
|
333
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
334
|
-
"one
|
|
335
|
-
two
|
|
336
|
-
three
|
|
337
|
-
four
|
|
338
|
-
"
|
|
339
|
-
`);
|
|
340
|
-
// doesn't mutate
|
|
341
|
-
expect(prevTree.toString()).not.toEqual(tree.toString());
|
|
342
|
-
});
|
|
343
|
-
|
|
344
|
-
it("finds and expands correctly at a non-leaf", () => {
|
|
345
|
-
tree = tree.collapse("three", undefined).collapse("two", undefined);
|
|
346
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
347
|
-
"one
|
|
348
|
-
two (collapsed)
|
|
349
|
-
three (collapsed)
|
|
350
|
-
four
|
|
351
|
-
"
|
|
352
|
-
`);
|
|
353
|
-
const prevTree = tree;
|
|
354
|
-
tree = tree.findAndExpandDeep("three");
|
|
355
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
356
|
-
"one
|
|
357
|
-
two
|
|
358
|
-
three
|
|
359
|
-
four
|
|
360
|
-
"
|
|
361
|
-
`);
|
|
362
|
-
// doesn't mutate
|
|
363
|
-
expect(prevTree.toString()).not.toEqual(tree.toString());
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
it("can delete nodes", () => {
|
|
367
|
-
tree = tree.collapse("three", undefined).collapse("two", undefined);
|
|
368
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
369
|
-
"one
|
|
370
|
-
two (collapsed)
|
|
371
|
-
three (collapsed)
|
|
372
|
-
four
|
|
373
|
-
"
|
|
374
|
-
`);
|
|
375
|
-
tree = tree.deleteAtIndex(1);
|
|
376
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
377
|
-
"one
|
|
378
|
-
three (collapsed)
|
|
379
|
-
four
|
|
380
|
-
"
|
|
381
|
-
`);
|
|
382
|
-
});
|
|
383
|
-
|
|
384
63
|
it("can delete non-collapsed nodes without throwing", () => {
|
|
385
64
|
// Deleting a non-collapsed node should not throw
|
|
386
65
|
// (previously this would throw "Node is already expanded" internally)
|
|
@@ -399,50 +78,6 @@ describe("CollapsibleTree", () => {
|
|
|
399
78
|
);
|
|
400
79
|
});
|
|
401
80
|
|
|
402
|
-
it("top-level ids are correct", () => {
|
|
403
|
-
expect(tree.topLevelIds).toMatchInlineSnapshot(`
|
|
404
|
-
[
|
|
405
|
-
"one",
|
|
406
|
-
"two",
|
|
407
|
-
"three",
|
|
408
|
-
"four",
|
|
409
|
-
]
|
|
410
|
-
`);
|
|
411
|
-
|
|
412
|
-
const collapsed = tree.collapse("two", undefined);
|
|
413
|
-
expect(collapsed.topLevelIds).toMatchInlineSnapshot(`
|
|
414
|
-
[
|
|
415
|
-
"one",
|
|
416
|
-
"two",
|
|
417
|
-
]
|
|
418
|
-
`);
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
it("in order ids are correct", () => {
|
|
422
|
-
expect(tree.inOrderIds).toMatchInlineSnapshot(`
|
|
423
|
-
[
|
|
424
|
-
"one",
|
|
425
|
-
"two",
|
|
426
|
-
"three",
|
|
427
|
-
"four",
|
|
428
|
-
]
|
|
429
|
-
`);
|
|
430
|
-
|
|
431
|
-
const collapsed = tree.collapse("two", undefined);
|
|
432
|
-
|
|
433
|
-
// Not mutable
|
|
434
|
-
expect(tree.inOrderIds).toEqual(tree.inOrderIds);
|
|
435
|
-
|
|
436
|
-
expect(collapsed.inOrderIds).toMatchInlineSnapshot(`
|
|
437
|
-
[
|
|
438
|
-
"one",
|
|
439
|
-
"two",
|
|
440
|
-
"three",
|
|
441
|
-
"four",
|
|
442
|
-
]
|
|
443
|
-
`);
|
|
444
|
-
});
|
|
445
|
-
|
|
446
81
|
it("atOrThrow throws if not found", () => {
|
|
447
82
|
expect(() => tree.atOrThrow(5)).toThrowErrorMatchingInlineSnapshot(
|
|
448
83
|
"[Error: Node at index 5 not found in tree]",
|
|
@@ -454,49 +89,6 @@ describe("CollapsibleTree", () => {
|
|
|
454
89
|
expect(tree.last()).toBe("four");
|
|
455
90
|
});
|
|
456
91
|
|
|
457
|
-
it("length is correct", () => {
|
|
458
|
-
expect(tree.length).toBe(4);
|
|
459
|
-
|
|
460
|
-
const collapsed = tree.collapse("two", undefined);
|
|
461
|
-
expect(collapsed.length).toBe(2);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
it("moves to front and back correctly", () => {
|
|
465
|
-
tree = tree.collapse("three", undefined).moveToBack("three");
|
|
466
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
467
|
-
"one
|
|
468
|
-
two
|
|
469
|
-
three (collapsed)
|
|
470
|
-
four
|
|
471
|
-
"
|
|
472
|
-
`);
|
|
473
|
-
|
|
474
|
-
tree = tree.moveToFront("two");
|
|
475
|
-
expect(tree.toString()).toMatchInlineSnapshot(`
|
|
476
|
-
"two
|
|
477
|
-
one
|
|
478
|
-
three (collapsed)
|
|
479
|
-
four
|
|
480
|
-
"
|
|
481
|
-
`);
|
|
482
|
-
});
|
|
483
|
-
|
|
484
|
-
it("getDescendants correctly", () => {
|
|
485
|
-
expect(tree.getDescendants("two")).toEqual([]);
|
|
486
|
-
expect(tree.getDescendants("who")).toEqual([]);
|
|
487
|
-
|
|
488
|
-
tree = tree.collapse("three", undefined).collapse("two", undefined);
|
|
489
|
-
expect(tree.getDescendants("two")).toMatchInlineSnapshot(`
|
|
490
|
-
[
|
|
491
|
-
"three",
|
|
492
|
-
"four",
|
|
493
|
-
]
|
|
494
|
-
`);
|
|
495
|
-
|
|
496
|
-
// We only get descendants of the top level
|
|
497
|
-
expect(tree.getDescendants("three")).toMatchInlineSnapshot("[]");
|
|
498
|
-
});
|
|
499
|
-
|
|
500
92
|
it("handles slice correctly", () => {
|
|
501
93
|
// Normal slice in middle
|
|
502
94
|
expect(tree.slice(1, 3)).toEqual(["two", "three"]);
|
|
@@ -526,14 +118,6 @@ describe("CollapsibleTree", () => {
|
|
|
526
118
|
expect(tree.slice(1, 2)).toEqual(["two"]);
|
|
527
119
|
});
|
|
528
120
|
|
|
529
|
-
it("handles slice with collapsed nodes", () => {
|
|
530
|
-
const collapsed = tree.collapse("two", "three");
|
|
531
|
-
|
|
532
|
-
// Should only return top-level nodes, not descendants
|
|
533
|
-
expect(collapsed.slice(0, 2)).toEqual(["one", "two"]);
|
|
534
|
-
expect(collapsed.slice(1, 3)).toEqual(["two", "four"]);
|
|
535
|
-
});
|
|
536
|
-
|
|
537
121
|
it("handles after correctly", () => {
|
|
538
122
|
// Normal case - get next node
|
|
539
123
|
expect(tree.after("one")).toBe("two");
|
|
@@ -549,20 +133,6 @@ describe("CollapsibleTree", () => {
|
|
|
549
133
|
);
|
|
550
134
|
});
|
|
551
135
|
|
|
552
|
-
it("handles after with collapsed nodes", () => {
|
|
553
|
-
const collapsed = tree.collapse("two", "three");
|
|
554
|
-
|
|
555
|
-
// Should return next top-level node
|
|
556
|
-
expect(collapsed.after("one")).toBe("two");
|
|
557
|
-
expect(collapsed.after("two")).toBe("four");
|
|
558
|
-
expect(collapsed.after("four")).toBeUndefined();
|
|
559
|
-
|
|
560
|
-
// Should throw for collapsed children that aren't top-level
|
|
561
|
-
expect(() => collapsed.after("three")).toThrow(
|
|
562
|
-
"Node three not found in tree. Valid ids: one,two,four",
|
|
563
|
-
);
|
|
564
|
-
});
|
|
565
|
-
|
|
566
136
|
it("handles before correctly", () => {
|
|
567
137
|
// Normal case - get previous node
|
|
568
138
|
expect(tree.before("two")).toBe("one");
|
|
@@ -578,20 +148,6 @@ describe("CollapsibleTree", () => {
|
|
|
578
148
|
);
|
|
579
149
|
});
|
|
580
150
|
|
|
581
|
-
it("handles before with collapsed nodes", () => {
|
|
582
|
-
const collapsed = tree.collapse("two", "three");
|
|
583
|
-
|
|
584
|
-
// Should return previous top-level node
|
|
585
|
-
expect(collapsed.before("two")).toBe("one");
|
|
586
|
-
expect(collapsed.before("four")).toBe("two");
|
|
587
|
-
expect(collapsed.before("one")).toBeUndefined();
|
|
588
|
-
|
|
589
|
-
// Should throw for collapsed children that aren't top-level
|
|
590
|
-
expect(() => collapsed.before("three")).toThrow(
|
|
591
|
-
"Node three not found in tree. Valid ids: one,two,four",
|
|
592
|
-
);
|
|
593
|
-
});
|
|
594
|
-
|
|
595
151
|
it("handles slice on empty tree", () => {
|
|
596
152
|
const emptyTree = CollapsibleTree.from([]);
|
|
597
153
|
expect(emptyTree.slice(0, 1)).toEqual([]);
|
|
@@ -665,45 +221,6 @@ describe("CollapsibleTree edge cases", () => {
|
|
|
665
221
|
expect(tree.topLevelIds).toEqual(["Z", "A", "B", "C", "D", "Y"]);
|
|
666
222
|
});
|
|
667
223
|
|
|
668
|
-
it("handles delete with expand", () => {
|
|
669
|
-
tree = tree.collapse("B", "D");
|
|
670
|
-
tree = tree.deleteAtIndex(1);
|
|
671
|
-
expect(tree.topLevelIds).toEqual(["A", "C", "D"]);
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
it("finds nodes correctly", () => {
|
|
675
|
-
tree = tree.collapse("B", "D");
|
|
676
|
-
expect(tree.find("C")).toEqual(["B", "C"]);
|
|
677
|
-
expect(tree.find("E")).toEqual([]);
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
it("handles equality check", () => {
|
|
681
|
-
const tree2 = CollapsibleTree.from(["A", "B", "C", "D"]);
|
|
682
|
-
expect(tree.equals(tree2)).toBe(true);
|
|
683
|
-
tree2.collapse("B", "C");
|
|
684
|
-
expect(tree.equals(tree2)).toBe(true);
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
it("handles getCount correctly", () => {
|
|
688
|
-
tree = tree.collapse("B", "D");
|
|
689
|
-
expect(tree.getCount("A")).toBe(0);
|
|
690
|
-
expect(tree.getCount("B")).toBe(2);
|
|
691
|
-
expect(tree.getCount("C")).toBe(0);
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
it("handles findAndExpandDeep", () => {
|
|
695
|
-
tree = tree.collapse("B", "D");
|
|
696
|
-
tree = tree.findAndExpandDeep("C");
|
|
697
|
-
expect(tree.topLevelIds).toEqual(["A", "B", "C", "D"]);
|
|
698
|
-
});
|
|
699
|
-
|
|
700
|
-
it("handles multiple collapses and expands", () => {
|
|
701
|
-
tree = tree.collapse("B", "C").collapse("A", "D");
|
|
702
|
-
expect(tree.topLevelIds).toEqual(["A"]);
|
|
703
|
-
tree = tree.expand("A").expand("B");
|
|
704
|
-
expect(tree.topLevelIds).toEqual(["A", "B", "C", "D"]);
|
|
705
|
-
});
|
|
706
|
-
|
|
707
224
|
it("handles edge cases for first and last", () => {
|
|
708
225
|
expect(tree.first()).toBe("A");
|
|
709
226
|
expect(tree.last()).toBe("D");
|
|
@@ -711,21 +228,6 @@ describe("CollapsibleTree edge cases", () => {
|
|
|
711
228
|
expect(() => tree.first()).toThrow("Node at index 0 not found in tree");
|
|
712
229
|
expect(() => tree.last()).toThrow("Node at index -1 not found in tree");
|
|
713
230
|
});
|
|
714
|
-
|
|
715
|
-
it("handles inOrderIds with nested structure", () => {
|
|
716
|
-
tree = tree.collapse("B", "C");
|
|
717
|
-
expect(tree.inOrderIds).toEqual(["A", "B", "C", "D"]);
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
it("handles moving within bounds", () => {
|
|
721
|
-
tree = tree.move(0, 2);
|
|
722
|
-
expect(tree.topLevelIds).toEqual(["B", "C", "A", "D"]);
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
it("handles moving out of bounds", () => {
|
|
726
|
-
tree = tree.move(0, 10);
|
|
727
|
-
expect(tree.topLevelIds).toEqual(["B", "C", "D", "A"]);
|
|
728
|
-
});
|
|
729
231
|
});
|
|
730
232
|
|
|
731
233
|
describe("MultiColumn", () => {
|
|
@@ -862,29 +364,6 @@ describe("MultiColumn", () => {
|
|
|
862
364
|
]);
|
|
863
365
|
});
|
|
864
366
|
|
|
865
|
-
it("moves within a column", () => {
|
|
866
|
-
const moved = multiColumn.moveWithinColumn(
|
|
867
|
-
columnIds[0],
|
|
868
|
-
0 as CellIndex,
|
|
869
|
-
2 as CellIndex,
|
|
870
|
-
);
|
|
871
|
-
expect(moved.topLevelIds[0]).toEqual(["A2", "A3", "A1"]);
|
|
872
|
-
});
|
|
873
|
-
|
|
874
|
-
it("moves across columns", () => {
|
|
875
|
-
const moved = multiColumn.moveAcrossColumns(
|
|
876
|
-
columnIds[0],
|
|
877
|
-
"A1",
|
|
878
|
-
columnIds[1],
|
|
879
|
-
"B1",
|
|
880
|
-
);
|
|
881
|
-
expect(moved.topLevelIds).toEqual([
|
|
882
|
-
["A2", "A3"],
|
|
883
|
-
["A1", "B1", "B2"],
|
|
884
|
-
["C1", "C2", "C3", "C4"],
|
|
885
|
-
]);
|
|
886
|
-
});
|
|
887
|
-
|
|
888
367
|
it("moves a column", () => {
|
|
889
368
|
const moved = multiColumn.moveColumn(columnIds[0], columnIds[2]);
|
|
890
369
|
expect(moved.topLevelIds).toEqual([
|
|
@@ -921,17 +400,6 @@ describe("MultiColumn", () => {
|
|
|
921
400
|
]);
|
|
922
401
|
});
|
|
923
402
|
|
|
924
|
-
it("moves to a new column", () => {
|
|
925
|
-
const newColumn = multiColumn.moveToNewColumn("B1");
|
|
926
|
-
expect(newColumn.colLength).toBe(4);
|
|
927
|
-
expect(newColumn.topLevelIds).toEqual([
|
|
928
|
-
["A1", "A2", "A3"],
|
|
929
|
-
["B2"],
|
|
930
|
-
["C1", "C2", "C3", "C4"],
|
|
931
|
-
["B1"],
|
|
932
|
-
]);
|
|
933
|
-
});
|
|
934
|
-
|
|
935
403
|
it("gets column with id", () => {
|
|
936
404
|
const column = multiColumn.findWithId("B2");
|
|
937
405
|
expect(multiColumn.indexOf(column)).toBe(1);
|
|
@@ -940,9 +408,9 @@ describe("MultiColumn", () => {
|
|
|
940
408
|
|
|
941
409
|
it("transforms by id", () => {
|
|
942
410
|
const transformed = multiColumn.transformWithCellId("B1", (tree) =>
|
|
943
|
-
tree.
|
|
411
|
+
tree.delete("B1"),
|
|
944
412
|
);
|
|
945
|
-
expect(transformed.topLevelIds[1]).toEqual(["B2"
|
|
413
|
+
expect(transformed.topLevelIds[1]).toEqual(["B2"]);
|
|
946
414
|
});
|
|
947
415
|
|
|
948
416
|
it("transforms all columns", () => {
|
|
@@ -961,82 +429,6 @@ describe("MultiColumn", () => {
|
|
|
961
429
|
expect(inserted.topLevelIds[1]).toEqual(["B1", "D1", "B2"]);
|
|
962
430
|
});
|
|
963
431
|
|
|
964
|
-
describe("moveCellsRelativeTo", () => {
|
|
965
|
-
it("moves a single cell before target in same column", () => {
|
|
966
|
-
const moved = multiColumn.moveCellsRelativeTo(["A3"], "A1", "before");
|
|
967
|
-
expect(moved.topLevelIds).toEqual([
|
|
968
|
-
["A3", "A1", "A2"],
|
|
969
|
-
["B1", "B2"],
|
|
970
|
-
["C1", "C2", "C3", "C4"],
|
|
971
|
-
]);
|
|
972
|
-
});
|
|
973
|
-
|
|
974
|
-
it("moves a single cell after target in same column", () => {
|
|
975
|
-
const moved = multiColumn.moveCellsRelativeTo(["A1"], "A3", "after");
|
|
976
|
-
expect(moved.topLevelIds).toEqual([
|
|
977
|
-
["A2", "A3", "A1"],
|
|
978
|
-
["B1", "B2"],
|
|
979
|
-
["C1", "C2", "C3", "C4"],
|
|
980
|
-
]);
|
|
981
|
-
});
|
|
982
|
-
|
|
983
|
-
it("moves multiple cells before target", () => {
|
|
984
|
-
const moved = multiColumn.moveCellsRelativeTo(
|
|
985
|
-
["A1", "A2"],
|
|
986
|
-
"B2",
|
|
987
|
-
"before",
|
|
988
|
-
);
|
|
989
|
-
expect(moved.topLevelIds).toEqual([
|
|
990
|
-
["A3"],
|
|
991
|
-
["B1", "A1", "A2", "B2"],
|
|
992
|
-
["C1", "C2", "C3", "C4"],
|
|
993
|
-
]);
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
it("moves multiple cells after target", () => {
|
|
997
|
-
const moved = multiColumn.moveCellsRelativeTo(
|
|
998
|
-
["A2", "A3"],
|
|
999
|
-
"B1",
|
|
1000
|
-
"after",
|
|
1001
|
-
);
|
|
1002
|
-
expect(moved.topLevelIds).toEqual([
|
|
1003
|
-
["A1"],
|
|
1004
|
-
["B1", "A2", "A3", "B2"],
|
|
1005
|
-
["C1", "C2", "C3", "C4"],
|
|
1006
|
-
]);
|
|
1007
|
-
});
|
|
1008
|
-
|
|
1009
|
-
it("returns same MultiColumn when cellIds is empty", () => {
|
|
1010
|
-
const moved = multiColumn.moveCellsRelativeTo([], "A1", "before");
|
|
1011
|
-
expect(moved).toBe(multiColumn);
|
|
1012
|
-
});
|
|
1013
|
-
|
|
1014
|
-
it("inserts at end when target is among moved cells", () => {
|
|
1015
|
-
const moved = multiColumn.moveCellsRelativeTo(
|
|
1016
|
-
["A1", "A2"],
|
|
1017
|
-
"A2",
|
|
1018
|
-
"after",
|
|
1019
|
-
);
|
|
1020
|
-
// Target A2 was removed; insert at end of column 0
|
|
1021
|
-
expect(moved.topLevelIds).toEqual([
|
|
1022
|
-
["A3", "A1", "A2"],
|
|
1023
|
-
["B1", "B2"],
|
|
1024
|
-
["C1", "C2", "C3", "C4"],
|
|
1025
|
-
]);
|
|
1026
|
-
});
|
|
1027
|
-
|
|
1028
|
-
it("throws when node not found", () => {
|
|
1029
|
-
expect(() =>
|
|
1030
|
-
multiColumn.moveCellsRelativeTo(["Z1"], "A1", "before"),
|
|
1031
|
-
).toThrow("Cell Z1 not found in any column");
|
|
1032
|
-
});
|
|
1033
|
-
});
|
|
1034
|
-
|
|
1035
|
-
it("deletes by id", () => {
|
|
1036
|
-
const deleted = multiColumn.deleteById("B1");
|
|
1037
|
-
expect(deleted.topLevelIds[1]).toEqual(["B2"]);
|
|
1038
|
-
});
|
|
1039
|
-
|
|
1040
432
|
it("compacts", () => {
|
|
1041
433
|
const withEmpty = MultiColumn.from([["A1"], [], ["C1"], []]);
|
|
1042
434
|
const compacted = withEmpty.compact();
|
|
@@ -1079,36 +471,6 @@ describe("MultiColumn", () => {
|
|
|
1079
471
|
expect(() => multiColumn.atOrThrow(5)).toThrow("Column 5 not found");
|
|
1080
472
|
});
|
|
1081
473
|
|
|
1082
|
-
it("handles moving the last item in a column", () => {
|
|
1083
|
-
const multiColumn = MultiColumn.from([["A1", "A2"], ["B1"]]);
|
|
1084
|
-
const columnIds = multiColumn.getColumns().map((c) => c.id);
|
|
1085
|
-
const moved = multiColumn.moveAcrossColumns(
|
|
1086
|
-
columnIds[1],
|
|
1087
|
-
"B1",
|
|
1088
|
-
columnIds[0],
|
|
1089
|
-
"A2",
|
|
1090
|
-
);
|
|
1091
|
-
expect(moved.topLevelIds).toEqual([["A1", "B1", "A2"], []]);
|
|
1092
|
-
expect(moved.colLength).toBe(2);
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
it("handles moving all items from a column", () => {
|
|
1096
|
-
const multiColumn = MultiColumn.from([
|
|
1097
|
-
["A1", "A2"],
|
|
1098
|
-
["B1", "B2"],
|
|
1099
|
-
]);
|
|
1100
|
-
const columnIds = multiColumn.getColumns().map((c) => c.id);
|
|
1101
|
-
let moved = multiColumn.moveAcrossColumns(
|
|
1102
|
-
columnIds[1],
|
|
1103
|
-
"B1",
|
|
1104
|
-
columnIds[0],
|
|
1105
|
-
"A2",
|
|
1106
|
-
);
|
|
1107
|
-
moved = moved.moveAcrossColumns(columnIds[1], "B2", columnIds[0], "A2");
|
|
1108
|
-
expect(moved.topLevelIds).toEqual([["A1", "B1", "B2", "A2"], []]);
|
|
1109
|
-
expect(moved.colLength).toBe(2);
|
|
1110
|
-
});
|
|
1111
|
-
|
|
1112
474
|
it("handles inserting at out-of-bounds indices", () => {
|
|
1113
475
|
const multiColumn = MultiColumn.from([["A1"], ["B1"]]);
|
|
1114
476
|
const columnId = multiColumn.atOrThrow(1).id;
|
|
@@ -1116,24 +478,6 @@ describe("MultiColumn", () => {
|
|
|
1116
478
|
expect(inserted.topLevelIds).toEqual([["A1"], ["B1", "C1"]]);
|
|
1117
479
|
});
|
|
1118
480
|
|
|
1119
|
-
it("handles collapsing and expanding in multi-column setup", () => {
|
|
1120
|
-
let multiColumn = MultiColumn.from([
|
|
1121
|
-
["A1", "A2", "A3"],
|
|
1122
|
-
["B1", "B2"],
|
|
1123
|
-
]);
|
|
1124
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1125
|
-
tree.collapse("A1", "A3"),
|
|
1126
|
-
);
|
|
1127
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1", "B2"]]);
|
|
1128
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1129
|
-
tree.expand("A1"),
|
|
1130
|
-
);
|
|
1131
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1132
|
-
["A1", "A2", "A3"],
|
|
1133
|
-
["B1", "B2"],
|
|
1134
|
-
]);
|
|
1135
|
-
});
|
|
1136
|
-
|
|
1137
481
|
it("handles moving a column to its own position", () => {
|
|
1138
482
|
const multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
|
|
1139
483
|
const moved = multiColumn.moveColumn(columnIds[1], columnIds[1]);
|
|
@@ -1155,39 +499,6 @@ describe("MultiColumn", () => {
|
|
|
1155
499
|
expect(transformed).toBe(multiColumn);
|
|
1156
500
|
});
|
|
1157
501
|
|
|
1158
|
-
it("handles nested collapses and expands", () => {
|
|
1159
|
-
let multiColumn = MultiColumn.from([["A1", "A2", "A3", "A4", "A5"]]);
|
|
1160
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1161
|
-
tree.collapse("A2", "A4"),
|
|
1162
|
-
);
|
|
1163
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1164
|
-
tree.collapse("A1", undefined),
|
|
1165
|
-
);
|
|
1166
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"]]);
|
|
1167
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1168
|
-
tree.expand("A1"),
|
|
1169
|
-
);
|
|
1170
|
-
expect(multiColumn.topLevelIds).toEqual([["A1", "A2", "A5"]]);
|
|
1171
|
-
multiColumn = multiColumn.transformWithCellId("A1", (tree) =>
|
|
1172
|
-
tree.expand("A2"),
|
|
1173
|
-
);
|
|
1174
|
-
expect(multiColumn.topLevelIds).toEqual([["A1", "A2", "A3", "A4", "A5"]]);
|
|
1175
|
-
});
|
|
1176
|
-
|
|
1177
|
-
it("handles moving to a new column when it's the last item", () => {
|
|
1178
|
-
let multiColumn = MultiColumn.from([["A1"], ["B1"]]);
|
|
1179
|
-
multiColumn = multiColumn.moveToNewColumn("B1");
|
|
1180
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1181
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["B1"]]);
|
|
1182
|
-
});
|
|
1183
|
-
|
|
1184
|
-
it("handles deleting the last item in a column", () => {
|
|
1185
|
-
let multiColumn = MultiColumn.from([["A1"], ["B1"], ["C1"]]);
|
|
1186
|
-
multiColumn = multiColumn.deleteById("B1");
|
|
1187
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1188
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["C1"]]);
|
|
1189
|
-
});
|
|
1190
|
-
|
|
1191
502
|
it("handles multiple operations in sequence", () => {
|
|
1192
503
|
let multiColumn = MultiColumn.from([
|
|
1193
504
|
["A1", "A2"],
|
|
@@ -1195,40 +506,31 @@ describe("MultiColumn", () => {
|
|
|
1195
506
|
["C1", "C2"],
|
|
1196
507
|
]);
|
|
1197
508
|
const columnIds = multiColumn.getColumns().map((c) => c.id);
|
|
1198
|
-
multiColumn = multiColumn.moveAcrossColumns(
|
|
1199
|
-
columnIds[0],
|
|
1200
|
-
"A2",
|
|
1201
|
-
columnIds[1],
|
|
1202
|
-
"B1",
|
|
1203
|
-
);
|
|
1204
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1205
|
-
["A1"],
|
|
1206
|
-
["A2", "B1", "B2"],
|
|
1207
|
-
["C1", "C2"],
|
|
1208
|
-
]);
|
|
1209
509
|
multiColumn = multiColumn.insertId("D1", columnIds[2], 1 as CellIndex);
|
|
1210
510
|
expect(multiColumn.topLevelIds).toEqual([
|
|
1211
|
-
["A1"],
|
|
1212
|
-
["
|
|
511
|
+
["A1", "A2"],
|
|
512
|
+
["B1", "B2"],
|
|
1213
513
|
["C1", "D1", "C2"],
|
|
1214
514
|
]);
|
|
1215
|
-
multiColumn = multiColumn.
|
|
515
|
+
multiColumn = multiColumn.transformWithCellId("B1", (tree) =>
|
|
516
|
+
tree.delete("B1"),
|
|
517
|
+
);
|
|
1216
518
|
expect(multiColumn.topLevelIds).toEqual([
|
|
1217
|
-
["A1"],
|
|
1218
|
-
["
|
|
519
|
+
["A1", "A2"],
|
|
520
|
+
["B2"],
|
|
1219
521
|
["C1", "D1", "C2"],
|
|
1220
522
|
]);
|
|
1221
523
|
multiColumn = multiColumn.moveColumn(columnIds[0], columnIds[2]);
|
|
1222
524
|
expect(multiColumn.topLevelIds).toEqual([
|
|
1223
|
-
["
|
|
525
|
+
["B2"],
|
|
1224
526
|
["C1", "D1", "C2"],
|
|
1225
|
-
["A1"],
|
|
527
|
+
["A1", "A2"],
|
|
1226
528
|
]);
|
|
1227
529
|
multiColumn = multiColumn.compact();
|
|
1228
530
|
expect(multiColumn.topLevelIds).toEqual([
|
|
1229
|
-
["
|
|
531
|
+
["B2"],
|
|
1230
532
|
["C1", "D1", "C2"],
|
|
1231
|
-
["A1"],
|
|
533
|
+
["A1", "A2"],
|
|
1232
534
|
]);
|
|
1233
535
|
});
|
|
1234
536
|
|
|
@@ -1238,7 +540,10 @@ describe("MultiColumn", () => {
|
|
|
1238
540
|
expect(multiColumn.setupCellExists()).toBe(false);
|
|
1239
541
|
const multiColumn2 = multiColumn.insertId(SETUP_CELL_ID, columnIds[0], 0);
|
|
1240
542
|
expect(multiColumn2.setupCellExists()).toBe(true);
|
|
1241
|
-
const multiColumn3 = multiColumn2.
|
|
543
|
+
const multiColumn3 = multiColumn2.transformWithCellId(
|
|
544
|
+
SETUP_CELL_ID,
|
|
545
|
+
(tree) => tree.delete(SETUP_CELL_ID),
|
|
546
|
+
);
|
|
1242
547
|
expect(multiColumn3.setupCellExists()).toBe(false);
|
|
1243
548
|
});
|
|
1244
549
|
|
|
@@ -1264,15 +569,15 @@ describe("MultiColumn", () => {
|
|
|
1264
569
|
|
|
1265
570
|
it("handles transform method", () => {
|
|
1266
571
|
const transformed = multiColumn.transform(columnIds[1], (tree) =>
|
|
1267
|
-
tree.
|
|
572
|
+
tree.delete("B1"),
|
|
1268
573
|
);
|
|
1269
|
-
expect(transformed.topLevelIds[1]).toEqual(["B2"
|
|
574
|
+
expect(transformed.topLevelIds[1]).toEqual(["B2"]);
|
|
1270
575
|
});
|
|
1271
576
|
|
|
1272
577
|
it("handles transform method with non-existent column id", () => {
|
|
1273
578
|
const transformed = multiColumn.transform(
|
|
1274
579
|
"non-existent-id" as CellColumnId,
|
|
1275
|
-
(tree) => tree.
|
|
580
|
+
(tree) => tree.delete("B2"),
|
|
1276
581
|
);
|
|
1277
582
|
const columns1 = multiColumn.getColumns();
|
|
1278
583
|
const columns2 = transformed.getColumns();
|
|
@@ -1281,37 +586,6 @@ describe("MultiColumn", () => {
|
|
|
1281
586
|
expect(transformed).toBe(multiColumn);
|
|
1282
587
|
});
|
|
1283
588
|
|
|
1284
|
-
it("handles moving across columns with undefined toId", () => {
|
|
1285
|
-
const moved = multiColumn.moveAcrossColumns(
|
|
1286
|
-
columnIds[0],
|
|
1287
|
-
"A1",
|
|
1288
|
-
columnIds[1],
|
|
1289
|
-
undefined,
|
|
1290
|
-
);
|
|
1291
|
-
expect(moved.topLevelIds).toEqual([
|
|
1292
|
-
["A2", "A3"],
|
|
1293
|
-
["A1", "B1", "B2"],
|
|
1294
|
-
["C1", "C2", "C3", "C4"],
|
|
1295
|
-
]);
|
|
1296
|
-
});
|
|
1297
|
-
|
|
1298
|
-
it("handles moving across columns to an empty column", () => {
|
|
1299
|
-
const emptyColumnMultiColumn = multiColumn
|
|
1300
|
-
.deleteById("B1")
|
|
1301
|
-
.deleteById("B2");
|
|
1302
|
-
const moved = emptyColumnMultiColumn.moveAcrossColumns(
|
|
1303
|
-
columnIds[0],
|
|
1304
|
-
"A1",
|
|
1305
|
-
columnIds[1],
|
|
1306
|
-
undefined,
|
|
1307
|
-
);
|
|
1308
|
-
expect(moved.topLevelIds).toEqual([
|
|
1309
|
-
["A2", "A3"],
|
|
1310
|
-
["A1"],
|
|
1311
|
-
["C1", "C2", "C3", "C4"],
|
|
1312
|
-
]);
|
|
1313
|
-
});
|
|
1314
|
-
|
|
1315
589
|
it("handles inserting a breakpoint at the start of a column", () => {
|
|
1316
590
|
const withBreakpoint = multiColumn.insertBreakpoint("A1");
|
|
1317
591
|
expect(withBreakpoint.colLength).toBe(4);
|
|
@@ -1341,805 +615,3 @@ describe("MultiColumn", () => {
|
|
|
1341
615
|
expect(withBreakpoint.topLevelIds).toEqual([["A1"], [], ["B1"], ["C1"]]);
|
|
1342
616
|
});
|
|
1343
617
|
});
|
|
1344
|
-
|
|
1345
|
-
describe("MultiColumn.fromWithPreviousShape", () => {
|
|
1346
|
-
it("creates a new MultiColumn with a single column when no previous shape is provided", () => {
|
|
1347
|
-
const ids = ["A1", "A2", "A3"];
|
|
1348
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1349
|
-
ids,
|
|
1350
|
-
MultiColumn.from([]),
|
|
1351
|
-
);
|
|
1352
|
-
|
|
1353
|
-
expect(multiColumn.colLength).toBe(1);
|
|
1354
|
-
expect(multiColumn.topLevelIds).toEqual([ids]);
|
|
1355
|
-
expect(multiColumn.inOrderIds).toEqual(ids);
|
|
1356
|
-
});
|
|
1357
|
-
|
|
1358
|
-
it("preserves column structure when ids exist in previous columns", () => {
|
|
1359
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1360
|
-
["A1", "A2"],
|
|
1361
|
-
["B1", "B2"],
|
|
1362
|
-
["C1", "C2"],
|
|
1363
|
-
]);
|
|
1364
|
-
|
|
1365
|
-
// Subset of ids from different columns
|
|
1366
|
-
const ids = ["A1", "B2", "C1"];
|
|
1367
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1368
|
-
ids,
|
|
1369
|
-
previousMultiColumn,
|
|
1370
|
-
);
|
|
1371
|
-
|
|
1372
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1373
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], ["B2"], ["C1"]]);
|
|
1374
|
-
});
|
|
1375
|
-
|
|
1376
|
-
it("preserves column structure with different ordering", () => {
|
|
1377
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1378
|
-
["A1", "A2", "A3"],
|
|
1379
|
-
["B1", "B2", "B3"],
|
|
1380
|
-
]);
|
|
1381
|
-
|
|
1382
|
-
// Same ids but different order
|
|
1383
|
-
const ids = ["A3", "B1", "A1", "B3"];
|
|
1384
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1385
|
-
ids,
|
|
1386
|
-
previousMultiColumn,
|
|
1387
|
-
);
|
|
1388
|
-
|
|
1389
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1390
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1391
|
-
["A3", "A1"],
|
|
1392
|
-
["B1", "B3"],
|
|
1393
|
-
]);
|
|
1394
|
-
});
|
|
1395
|
-
|
|
1396
|
-
it("handles ids not present in previous shape", () => {
|
|
1397
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1398
|
-
["A1", "A2"],
|
|
1399
|
-
["B1", "B2"],
|
|
1400
|
-
]);
|
|
1401
|
-
|
|
1402
|
-
// Include new ids not in previous shape
|
|
1403
|
-
const ids = ["A1", "B1", "C1", "D1"];
|
|
1404
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1405
|
-
ids,
|
|
1406
|
-
previousMultiColumn,
|
|
1407
|
-
);
|
|
1408
|
-
|
|
1409
|
-
// New ids should be added to the last column
|
|
1410
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1411
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1", "C1", "D1"]]);
|
|
1412
|
-
expect(multiColumn.inOrderIds).toEqual(["A1", "B1", "C1", "D1"]);
|
|
1413
|
-
});
|
|
1414
|
-
|
|
1415
|
-
it("preserves collapsed state from previous shape", () => {
|
|
1416
|
-
// Create a previous shape with collapsed nodes
|
|
1417
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1418
|
-
["A1", "A2", "A3"],
|
|
1419
|
-
["B1", "B2", "B3"],
|
|
1420
|
-
]);
|
|
1421
|
-
|
|
1422
|
-
// Collapse A1 to include A2
|
|
1423
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1424
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1425
|
-
tree.collapse("A1", "A2"),
|
|
1426
|
-
);
|
|
1427
|
-
|
|
1428
|
-
// Create new shape with same ids
|
|
1429
|
-
const ids = ["A1", "A2", "A3", "B1", "B2", "B3"];
|
|
1430
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1431
|
-
ids,
|
|
1432
|
-
previousMultiColumn,
|
|
1433
|
-
);
|
|
1434
|
-
|
|
1435
|
-
// Check that A1 is still collapsed
|
|
1436
|
-
const column = multiColumn.atOrThrow(0);
|
|
1437
|
-
expect(column.isCollapsed("A1")).toBe(true);
|
|
1438
|
-
|
|
1439
|
-
// Check that the structure is preserved
|
|
1440
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1441
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1442
|
-
["A1", "A3"],
|
|
1443
|
-
["B1", "B2", "B3"],
|
|
1444
|
-
]);
|
|
1445
|
-
});
|
|
1446
|
-
|
|
1447
|
-
it("handles empty columns in previous shape", () => {
|
|
1448
|
-
// Create a previous shape with an empty column
|
|
1449
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1450
|
-
["A1", "A2"],
|
|
1451
|
-
[],
|
|
1452
|
-
["C1", "C2"],
|
|
1453
|
-
]);
|
|
1454
|
-
|
|
1455
|
-
const ids = ["A1", "C2"];
|
|
1456
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1457
|
-
ids,
|
|
1458
|
-
previousMultiColumn,
|
|
1459
|
-
);
|
|
1460
|
-
|
|
1461
|
-
// Should preserve the column structure
|
|
1462
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1463
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], [], ["C2"]]);
|
|
1464
|
-
});
|
|
1465
|
-
|
|
1466
|
-
it("handles subset of ids with nested collapsed structure", () => {
|
|
1467
|
-
// Create a previous shape with nested collapsed structure
|
|
1468
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1469
|
-
["A1", "A2", "A3", "A4", "A5"],
|
|
1470
|
-
["B1", "B2", "B3"],
|
|
1471
|
-
]);
|
|
1472
|
-
|
|
1473
|
-
// Collapse A1 to include A2, A3
|
|
1474
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1475
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1476
|
-
tree.collapse("A1", "A3"),
|
|
1477
|
-
);
|
|
1478
|
-
|
|
1479
|
-
// Create new shape with subset of ids
|
|
1480
|
-
const ids = ["A1", "A2", "A3", "A4", "B1"];
|
|
1481
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1482
|
-
ids,
|
|
1483
|
-
previousMultiColumn,
|
|
1484
|
-
);
|
|
1485
|
-
|
|
1486
|
-
// Check that collapsed state is preserved
|
|
1487
|
-
const column = multiColumn.atOrThrow(0);
|
|
1488
|
-
expect(column.isCollapsed("A1")).toBe(true);
|
|
1489
|
-
|
|
1490
|
-
// Check that the structure is preserved
|
|
1491
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1492
|
-
expect(multiColumn.topLevelIds).toEqual([["A1", "A4"], ["B1"]]);
|
|
1493
|
-
expect(multiColumn.inOrderIds).toEqual(["A1", "A2", "A3", "A4", "B1"]);
|
|
1494
|
-
});
|
|
1495
|
-
|
|
1496
|
-
it("handles reordering of columns", () => {
|
|
1497
|
-
// Create a previous shape with specific column order
|
|
1498
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1499
|
-
["A1", "A2"],
|
|
1500
|
-
["B1", "B2"],
|
|
1501
|
-
["C1", "C2"],
|
|
1502
|
-
]);
|
|
1503
|
-
|
|
1504
|
-
// Create new shape with ids in different order
|
|
1505
|
-
const ids = ["C1", "A1", "B1"];
|
|
1506
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1507
|
-
ids,
|
|
1508
|
-
previousMultiColumn,
|
|
1509
|
-
);
|
|
1510
|
-
|
|
1511
|
-
// Column order should be preserved
|
|
1512
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1513
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], ["B1"], ["C1"]]);
|
|
1514
|
-
});
|
|
1515
|
-
|
|
1516
|
-
it("handles completely different set of ids", () => {
|
|
1517
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1518
|
-
["A1", "A2"],
|
|
1519
|
-
["B1", "B2"],
|
|
1520
|
-
]);
|
|
1521
|
-
|
|
1522
|
-
// Completely different set of ids
|
|
1523
|
-
const ids = ["X1", "X2", "X3"];
|
|
1524
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1525
|
-
ids,
|
|
1526
|
-
previousMultiColumn,
|
|
1527
|
-
);
|
|
1528
|
-
|
|
1529
|
-
// New ids should be added to the last column
|
|
1530
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1531
|
-
expect(multiColumn.topLevelIds).toEqual([["X1", "X2", "X3"], []]);
|
|
1532
|
-
expect(multiColumn.inOrderIds).toEqual(["X1", "X2", "X3"]);
|
|
1533
|
-
});
|
|
1534
|
-
|
|
1535
|
-
it("preserves tree structure within columns", () => {
|
|
1536
|
-
// Create a previous shape with complex tree structure
|
|
1537
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1538
|
-
["A1", "A2", "A3", "A4"],
|
|
1539
|
-
["B1", "B2", "B3"],
|
|
1540
|
-
]);
|
|
1541
|
-
|
|
1542
|
-
// Create complex tree structure by collapsing nodes
|
|
1543
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1544
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1545
|
-
tree.collapse("A1", "A2"),
|
|
1546
|
-
);
|
|
1547
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
|
|
1548
|
-
tree.collapse("B1", "B2"),
|
|
1549
|
-
);
|
|
1550
|
-
|
|
1551
|
-
// Create new shape with same ids
|
|
1552
|
-
const ids = ["A1", "A2", "A3", "A4", "B1", "B2", "B3"];
|
|
1553
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1554
|
-
ids,
|
|
1555
|
-
previousMultiColumn,
|
|
1556
|
-
);
|
|
1557
|
-
|
|
1558
|
-
// Check that collapsed state is preserved in both columns
|
|
1559
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
|
|
1560
|
-
expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(true);
|
|
1561
|
-
|
|
1562
|
-
// Check that the structure is preserved
|
|
1563
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1564
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1565
|
-
["A1", "A3", "A4"],
|
|
1566
|
-
["B1", "B3"],
|
|
1567
|
-
]);
|
|
1568
|
-
});
|
|
1569
|
-
|
|
1570
|
-
it("handles empty array of ids", () => {
|
|
1571
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1572
|
-
["A1", "A2"],
|
|
1573
|
-
["B1", "B2"],
|
|
1574
|
-
]);
|
|
1575
|
-
|
|
1576
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1577
|
-
[],
|
|
1578
|
-
previousMultiColumn,
|
|
1579
|
-
);
|
|
1580
|
-
|
|
1581
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1582
|
-
expect(multiColumn.topLevelIds).toEqual([[], []]);
|
|
1583
|
-
expect(multiColumn.inOrderIds).toEqual([]);
|
|
1584
|
-
});
|
|
1585
|
-
|
|
1586
|
-
it("handles single id", () => {
|
|
1587
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1588
|
-
["A1", "A2"],
|
|
1589
|
-
["B1", "B2"],
|
|
1590
|
-
]);
|
|
1591
|
-
|
|
1592
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1593
|
-
["A1"],
|
|
1594
|
-
previousMultiColumn,
|
|
1595
|
-
);
|
|
1596
|
-
|
|
1597
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1598
|
-
expect(multiColumn.topLevelIds).toEqual([["A1"], []]);
|
|
1599
|
-
expect(multiColumn.inOrderIds).toEqual(["A1"]);
|
|
1600
|
-
});
|
|
1601
|
-
|
|
1602
|
-
it("preserves complex nested structure across multiple columns", () => {
|
|
1603
|
-
// Create a complex structure with multiple columns and nested collapsed nodes
|
|
1604
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1605
|
-
["A1", "A2", "A3", "A4", "A5"],
|
|
1606
|
-
["B1", "B2", "B3", "B4"],
|
|
1607
|
-
["C1", "C2", "C3"],
|
|
1608
|
-
]);
|
|
1609
|
-
|
|
1610
|
-
// Create complex nested structure
|
|
1611
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1612
|
-
|
|
1613
|
-
// Collapse in first column
|
|
1614
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1615
|
-
tree.collapse("A1", "A2"),
|
|
1616
|
-
);
|
|
1617
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1618
|
-
tree.collapse("A3", "A4"),
|
|
1619
|
-
);
|
|
1620
|
-
|
|
1621
|
-
// Collapse in second column
|
|
1622
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
|
|
1623
|
-
tree.collapse("B1", "B2"),
|
|
1624
|
-
);
|
|
1625
|
-
|
|
1626
|
-
// Collapse in third column
|
|
1627
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[2], (tree) =>
|
|
1628
|
-
tree.collapse("C1", "C2"),
|
|
1629
|
-
);
|
|
1630
|
-
|
|
1631
|
-
// Create new shape with all ids
|
|
1632
|
-
const ids = [
|
|
1633
|
-
"A1",
|
|
1634
|
-
"A2",
|
|
1635
|
-
"A3",
|
|
1636
|
-
"A4",
|
|
1637
|
-
"A5",
|
|
1638
|
-
"B1",
|
|
1639
|
-
"B2",
|
|
1640
|
-
"B3",
|
|
1641
|
-
"B4",
|
|
1642
|
-
"C1",
|
|
1643
|
-
"C2",
|
|
1644
|
-
"C3",
|
|
1645
|
-
];
|
|
1646
|
-
|
|
1647
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1648
|
-
ids,
|
|
1649
|
-
previousMultiColumn,
|
|
1650
|
-
);
|
|
1651
|
-
|
|
1652
|
-
// Check that all collapsed states are preserved
|
|
1653
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
|
|
1654
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A3")).toBe(true);
|
|
1655
|
-
expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(true);
|
|
1656
|
-
expect(multiColumn.atOrThrow(2).isCollapsed("C1")).toBe(true);
|
|
1657
|
-
|
|
1658
|
-
// Check that the structure is preserved
|
|
1659
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1660
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1661
|
-
["A1", "A3", "A5"],
|
|
1662
|
-
["B1", "B3", "B4"],
|
|
1663
|
-
["C1", "C3"],
|
|
1664
|
-
]);
|
|
1665
|
-
});
|
|
1666
|
-
|
|
1667
|
-
it("handles case where ids are distributed differently than in previous shape", () => {
|
|
1668
|
-
const previousMultiColumn = MultiColumn.from([
|
|
1669
|
-
["A1", "A2"],
|
|
1670
|
-
["B1", "B2"],
|
|
1671
|
-
["C1", "C2"],
|
|
1672
|
-
]);
|
|
1673
|
-
|
|
1674
|
-
// Create new shape with ids from different columns grouped together
|
|
1675
|
-
const ids = ["A1", "B1", "C1", "A2", "B2", "C2"];
|
|
1676
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1677
|
-
ids,
|
|
1678
|
-
previousMultiColumn,
|
|
1679
|
-
);
|
|
1680
|
-
|
|
1681
|
-
// Should preserve the original column structure
|
|
1682
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1683
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1684
|
-
["A1", "A2"],
|
|
1685
|
-
["B1", "B2"],
|
|
1686
|
-
["C1", "C2"],
|
|
1687
|
-
]);
|
|
1688
|
-
});
|
|
1689
|
-
|
|
1690
|
-
it("handles case where previous shape has collapsed nodes but new ids don't include children", () => {
|
|
1691
|
-
// Create a previous shape with collapsed nodes
|
|
1692
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1693
|
-
["A1", "A2", "A3"],
|
|
1694
|
-
["B1", "B2", "B3"],
|
|
1695
|
-
]);
|
|
1696
|
-
|
|
1697
|
-
// Collapse nodes in both columns
|
|
1698
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1699
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1700
|
-
tree.collapse("A1", "A2"),
|
|
1701
|
-
);
|
|
1702
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[1], (tree) =>
|
|
1703
|
-
tree.collapse("B1", "B2"),
|
|
1704
|
-
);
|
|
1705
|
-
|
|
1706
|
-
// Create new shape without the collapsed children
|
|
1707
|
-
const ids = ["A1", "A3", "B1", "B3"];
|
|
1708
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1709
|
-
ids,
|
|
1710
|
-
previousMultiColumn,
|
|
1711
|
-
);
|
|
1712
|
-
|
|
1713
|
-
// Nodes should not be collapsed since children are missing
|
|
1714
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(false);
|
|
1715
|
-
expect(multiColumn.atOrThrow(1).isCollapsed("B1")).toBe(false);
|
|
1716
|
-
|
|
1717
|
-
// Check that the structure is preserved
|
|
1718
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1719
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1720
|
-
["A1", "A3"],
|
|
1721
|
-
["B1", "B3"],
|
|
1722
|
-
]);
|
|
1723
|
-
});
|
|
1724
|
-
|
|
1725
|
-
it("handles deeply nested collapsed structure", () => {
|
|
1726
|
-
// Create a tree with deeply nested collapsed structure
|
|
1727
|
-
let previousTree = CollapsibleTree.from([
|
|
1728
|
-
"one",
|
|
1729
|
-
"two",
|
|
1730
|
-
"three",
|
|
1731
|
-
"four",
|
|
1732
|
-
"five",
|
|
1733
|
-
"six",
|
|
1734
|
-
"seven",
|
|
1735
|
-
"eight",
|
|
1736
|
-
]);
|
|
1737
|
-
|
|
1738
|
-
// Create nested collapses
|
|
1739
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1740
|
-
|
|
1741
|
-
// Get the collapsed node and collapse its children
|
|
1742
|
-
const oneNode = previousTree._nodeMap.get("one");
|
|
1743
|
-
expect(oneNode).toBeDefined();
|
|
1744
|
-
|
|
1745
|
-
// Create a new tree with the same structure
|
|
1746
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1747
|
-
["one", "two", "three", "four", "five", "six", "seven", "eight"],
|
|
1748
|
-
previousTree,
|
|
1749
|
-
);
|
|
1750
|
-
|
|
1751
|
-
// Check that collapsed state is preserved
|
|
1752
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
1753
|
-
expect(tree.topLevelIds).toEqual([
|
|
1754
|
-
"one",
|
|
1755
|
-
"three",
|
|
1756
|
-
"four",
|
|
1757
|
-
"five",
|
|
1758
|
-
"six",
|
|
1759
|
-
"seven",
|
|
1760
|
-
"eight",
|
|
1761
|
-
]);
|
|
1762
|
-
});
|
|
1763
|
-
|
|
1764
|
-
it("handles case where collapsed node is at the end", () => {
|
|
1765
|
-
// Create a tree with collapsed node at the end
|
|
1766
|
-
let previousTree = CollapsibleTree.from([
|
|
1767
|
-
"one",
|
|
1768
|
-
"two",
|
|
1769
|
-
"three",
|
|
1770
|
-
"four",
|
|
1771
|
-
"five",
|
|
1772
|
-
]);
|
|
1773
|
-
previousTree = previousTree.collapse("four", "five");
|
|
1774
|
-
|
|
1775
|
-
// Create new tree with same ids
|
|
1776
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1777
|
-
["one", "two", "three", "four", "five"],
|
|
1778
|
-
previousTree,
|
|
1779
|
-
);
|
|
1780
|
-
|
|
1781
|
-
// Check that collapsed state is preserved
|
|
1782
|
-
expect(tree.isCollapsed("four")).toBe(true);
|
|
1783
|
-
expect(tree.topLevelIds).toEqual(["one", "two", "three", "four"]);
|
|
1784
|
-
});
|
|
1785
|
-
|
|
1786
|
-
it("handles case with multiple collapsed nodes in the same column", () => {
|
|
1787
|
-
// Create a previous shape with multiple collapsed nodes in the same column
|
|
1788
|
-
let previousMultiColumn = MultiColumn.from([
|
|
1789
|
-
["A1", "A2", "A3", "A4", "A5", "A6"],
|
|
1790
|
-
["B1", "B2"],
|
|
1791
|
-
]);
|
|
1792
|
-
|
|
1793
|
-
// Collapse multiple nodes in the first column
|
|
1794
|
-
const columnIds = previousMultiColumn.getColumnIds();
|
|
1795
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1796
|
-
tree.collapse("A1", "A2"),
|
|
1797
|
-
);
|
|
1798
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1799
|
-
tree.collapse("A3", "A4"),
|
|
1800
|
-
);
|
|
1801
|
-
previousMultiColumn = previousMultiColumn.transform(columnIds[0], (tree) =>
|
|
1802
|
-
tree.collapse("A5", "A6"),
|
|
1803
|
-
);
|
|
1804
|
-
|
|
1805
|
-
// Create new shape with same ids
|
|
1806
|
-
const ids = ["A1", "A2", "A3", "A4", "A5", "A6", "B1", "B2"];
|
|
1807
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1808
|
-
ids,
|
|
1809
|
-
previousMultiColumn,
|
|
1810
|
-
);
|
|
1811
|
-
|
|
1812
|
-
// Check that all collapsed states are preserved
|
|
1813
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A1")).toBe(true);
|
|
1814
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A3")).toBe(true);
|
|
1815
|
-
expect(multiColumn.atOrThrow(0).isCollapsed("A5")).toBe(true);
|
|
1816
|
-
|
|
1817
|
-
// Check that the structure is preserved
|
|
1818
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1819
|
-
expect(multiColumn.topLevelIds).toEqual([
|
|
1820
|
-
["A1", "A3", "A5"],
|
|
1821
|
-
["B1", "B2"],
|
|
1822
|
-
]);
|
|
1823
|
-
});
|
|
1824
|
-
|
|
1825
|
-
it("handles case where all columns are empty in previous shape", () => {
|
|
1826
|
-
// Create a previous shape with all empty columns
|
|
1827
|
-
const previousMultiColumn = MultiColumn.from([[], [], []]);
|
|
1828
|
-
|
|
1829
|
-
// Create new shape with new ids
|
|
1830
|
-
const ids = ["A1", "B1", "C1"];
|
|
1831
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1832
|
-
ids,
|
|
1833
|
-
previousMultiColumn,
|
|
1834
|
-
);
|
|
1835
|
-
|
|
1836
|
-
// New ids should be added to the last column
|
|
1837
|
-
expect(multiColumn.colLength).toBe(3);
|
|
1838
|
-
expect(multiColumn.topLevelIds).toEqual([["A1", "B1", "C1"], [], []]);
|
|
1839
|
-
expect(multiColumn.inOrderIds).toEqual(["A1", "B1", "C1"]);
|
|
1840
|
-
});
|
|
1841
|
-
|
|
1842
|
-
it("handles case with very large number of ids", () => {
|
|
1843
|
-
// Create a previous shape with a reasonable number of ids
|
|
1844
|
-
const previousIds1 = Array.from({ length: 50 }, (_, i) => `A${i}`);
|
|
1845
|
-
const previousIds2 = Array.from({ length: 50 }, (_, i) => `B${i}`);
|
|
1846
|
-
const previousMultiColumn = MultiColumn.from([previousIds1, previousIds2]);
|
|
1847
|
-
|
|
1848
|
-
// Create a large set of ids
|
|
1849
|
-
const ids = [
|
|
1850
|
-
...Array.from({ length: 50 }, (_, i) => `A${i}`),
|
|
1851
|
-
...Array.from({ length: 50 }, (_, i) => `B${i}`),
|
|
1852
|
-
...Array.from({ length: 50 }, (_, i) => `C${i}`),
|
|
1853
|
-
];
|
|
1854
|
-
|
|
1855
|
-
const multiColumn = MultiColumn.fromWithPreviousShape(
|
|
1856
|
-
ids,
|
|
1857
|
-
previousMultiColumn,
|
|
1858
|
-
);
|
|
1859
|
-
|
|
1860
|
-
// Should preserve the column structure for existing ids and add new ids to last column
|
|
1861
|
-
expect(multiColumn.colLength).toBe(2);
|
|
1862
|
-
expect(multiColumn.topLevelIds[0].length).toBe(50);
|
|
1863
|
-
expect(multiColumn.topLevelIds[1].length).toBe(100); // 50 B ids + 50 C ids
|
|
1864
|
-
expect(multiColumn.inOrderIds.length).toBe(150); // All ids should be included
|
|
1865
|
-
});
|
|
1866
|
-
});
|
|
1867
|
-
|
|
1868
|
-
describe("CollapsibleTree.fromWithPreviousShape", () => {
|
|
1869
|
-
it("creates a new tree when no previous tree is provided", () => {
|
|
1870
|
-
const ids = ["one", "two", "three"];
|
|
1871
|
-
const tree = CollapsibleTree.fromWithPreviousShape(ids);
|
|
1872
|
-
|
|
1873
|
-
expect(tree.topLevelIds).toEqual(ids);
|
|
1874
|
-
expect(tree.inOrderIds).toEqual(ids);
|
|
1875
|
-
expect(tree.nodes.length).toBe(3);
|
|
1876
|
-
expect(tree.nodes.every((node) => !node.isCollapsed)).toBe(true);
|
|
1877
|
-
});
|
|
1878
|
-
|
|
1879
|
-
it("preserves the tree ID when previous tree is provided", () => {
|
|
1880
|
-
const previousTree = CollapsibleTree.from(["one", "two", "three"]);
|
|
1881
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1882
|
-
["one", "two"],
|
|
1883
|
-
previousTree,
|
|
1884
|
-
);
|
|
1885
|
-
|
|
1886
|
-
expect(tree.id).toBe(previousTree.id);
|
|
1887
|
-
});
|
|
1888
|
-
|
|
1889
|
-
it("preserves collapsed state from previous tree", () => {
|
|
1890
|
-
// Create a tree with collapsed nodes
|
|
1891
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
|
|
1892
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1893
|
-
|
|
1894
|
-
// Create new tree with same ids
|
|
1895
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1896
|
-
["one", "two", "three", "four"],
|
|
1897
|
-
previousTree,
|
|
1898
|
-
);
|
|
1899
|
-
|
|
1900
|
-
// Check that one is still collapsed
|
|
1901
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
1902
|
-
expect(tree.topLevelIds).toEqual(["one", "three", "four"]);
|
|
1903
|
-
});
|
|
1904
|
-
|
|
1905
|
-
it("handles subset of ids from previous tree", () => {
|
|
1906
|
-
// Create a tree with collapsed nodes
|
|
1907
|
-
let previousTree = CollapsibleTree.from([
|
|
1908
|
-
"one",
|
|
1909
|
-
"two",
|
|
1910
|
-
"three",
|
|
1911
|
-
"four",
|
|
1912
|
-
"five",
|
|
1913
|
-
]);
|
|
1914
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1915
|
-
previousTree = previousTree.collapse("three", "four");
|
|
1916
|
-
|
|
1917
|
-
// Create new tree with subset of ids
|
|
1918
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1919
|
-
["one", "two", "three"],
|
|
1920
|
-
previousTree,
|
|
1921
|
-
);
|
|
1922
|
-
|
|
1923
|
-
// Check that collapsed state is preserved for existing nodes
|
|
1924
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
1925
|
-
expect(tree.topLevelIds).toEqual(["one", "three"]);
|
|
1926
|
-
});
|
|
1927
|
-
|
|
1928
|
-
it("handles different ordering of ids", () => {
|
|
1929
|
-
// Create a tree with collapsed nodes
|
|
1930
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
|
|
1931
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1932
|
-
|
|
1933
|
-
// Create new tree with different order
|
|
1934
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1935
|
-
["three", "one", "two", "four"],
|
|
1936
|
-
previousTree,
|
|
1937
|
-
);
|
|
1938
|
-
|
|
1939
|
-
// Check that collapsed state is preserved
|
|
1940
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
1941
|
-
expect(tree.topLevelIds).toEqual(["three", "one", "four"]);
|
|
1942
|
-
});
|
|
1943
|
-
|
|
1944
|
-
it("handles new ids not in previous tree", () => {
|
|
1945
|
-
// Create a tree with collapsed nodes
|
|
1946
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three"]);
|
|
1947
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1948
|
-
|
|
1949
|
-
// Create new tree with new ids
|
|
1950
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1951
|
-
["one", "two", "three", "four", "five"],
|
|
1952
|
-
previousTree,
|
|
1953
|
-
);
|
|
1954
|
-
|
|
1955
|
-
// Check that collapsed state is preserved for existing nodes
|
|
1956
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
1957
|
-
expect(tree.topLevelIds).toEqual(["one", "three", "four", "five"]);
|
|
1958
|
-
});
|
|
1959
|
-
|
|
1960
|
-
it("handles completely different set of ids", () => {
|
|
1961
|
-
// Create a tree with collapsed nodes
|
|
1962
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three"]);
|
|
1963
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1964
|
-
|
|
1965
|
-
// Create new tree with completely different ids
|
|
1966
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1967
|
-
["four", "five", "six"],
|
|
1968
|
-
previousTree,
|
|
1969
|
-
);
|
|
1970
|
-
|
|
1971
|
-
// Should have no collapsed nodes
|
|
1972
|
-
expect(tree.nodes.every((node) => !node.isCollapsed)).toBe(true);
|
|
1973
|
-
expect(tree.topLevelIds).toEqual(["four", "five", "six"]);
|
|
1974
|
-
});
|
|
1975
|
-
|
|
1976
|
-
it("preserves nested collapsed structure", () => {
|
|
1977
|
-
// Create a tree with nested collapsed structure
|
|
1978
|
-
let previousTree = CollapsibleTree.from([
|
|
1979
|
-
"one",
|
|
1980
|
-
"two",
|
|
1981
|
-
"three",
|
|
1982
|
-
"four",
|
|
1983
|
-
"five",
|
|
1984
|
-
"six",
|
|
1985
|
-
]);
|
|
1986
|
-
previousTree = previousTree.collapse("one", "two");
|
|
1987
|
-
|
|
1988
|
-
// Collapse the node that contains the collapsed children
|
|
1989
|
-
const oneNode = previousTree.nodes.find((n) => n.value === "one");
|
|
1990
|
-
expect(oneNode).toBeDefined();
|
|
1991
|
-
expect(oneNode?.children.length).toBeGreaterThan(0);
|
|
1992
|
-
|
|
1993
|
-
// Create a new tree with the same structure
|
|
1994
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
1995
|
-
["one", "two", "three", "four", "five", "six"],
|
|
1996
|
-
previousTree,
|
|
1997
|
-
);
|
|
1998
|
-
|
|
1999
|
-
// Check that collapsed state is preserved
|
|
2000
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
2001
|
-
expect(tree.topLevelIds).toEqual(["one", "three", "four", "five", "six"]);
|
|
2002
|
-
});
|
|
2003
|
-
|
|
2004
|
-
it("collapses using the last available child when some children are missing", () => {
|
|
2005
|
-
// Create a tree with collapsed nodes
|
|
2006
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
|
|
2007
|
-
previousTree = previousTree.collapse("one", "three");
|
|
2008
|
-
|
|
2009
|
-
// Create new tree without "two" but with "three"
|
|
2010
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
2011
|
-
["one", "three", "four"],
|
|
2012
|
-
previousTree,
|
|
2013
|
-
);
|
|
2014
|
-
|
|
2015
|
-
// Should still collapse "one" with "three" as the child
|
|
2016
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
2017
|
-
expect(tree.topLevelIds).toEqual(["one", "four"]);
|
|
2018
|
-
});
|
|
2019
|
-
|
|
2020
|
-
it("preserves collapse state when children order changes", () => {
|
|
2021
|
-
// Create a tree with collapsed nodes
|
|
2022
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
|
|
2023
|
-
previousTree = previousTree.collapse("one", "two");
|
|
2024
|
-
|
|
2025
|
-
// Create new tree with children in different order
|
|
2026
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
2027
|
-
["one", "three", "two", "four"],
|
|
2028
|
-
previousTree,
|
|
2029
|
-
);
|
|
2030
|
-
|
|
2031
|
-
// Should still be collapsed
|
|
2032
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
2033
|
-
// But the topLevelIds will be different because the children order changed
|
|
2034
|
-
expect(tree.topLevelIds).toEqual(["one", "four"]);
|
|
2035
|
-
});
|
|
2036
|
-
|
|
2037
|
-
it("handles empty arrays correctly", () => {
|
|
2038
|
-
const previousTree = CollapsibleTree.from(["one", "two", "three"]);
|
|
2039
|
-
const tree = CollapsibleTree.fromWithPreviousShape([], previousTree);
|
|
2040
|
-
|
|
2041
|
-
expect(tree.nodes.length).toBe(0);
|
|
2042
|
-
expect(tree.topLevelIds).toEqual([]);
|
|
2043
|
-
expect(tree.inOrderIds).toEqual([]);
|
|
2044
|
-
});
|
|
2045
|
-
|
|
2046
|
-
it("handles single item arrays correctly", () => {
|
|
2047
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three"]);
|
|
2048
|
-
previousTree = previousTree.collapse("one", "two");
|
|
2049
|
-
|
|
2050
|
-
const tree = CollapsibleTree.fromWithPreviousShape(["one"], previousTree);
|
|
2051
|
-
|
|
2052
|
-
expect(tree.nodes.length).toBe(1);
|
|
2053
|
-
expect(tree.topLevelIds).toEqual(["one"]);
|
|
2054
|
-
expect(tree.inOrderIds).toEqual(["one"]);
|
|
2055
|
-
// Should not be collapsed since there are no children
|
|
2056
|
-
expect(tree.isCollapsed("one")).toBe(false);
|
|
2057
|
-
});
|
|
2058
|
-
|
|
2059
|
-
it("handles multiple collapsed nodes in sequence", () => {
|
|
2060
|
-
let previousTree = CollapsibleTree.from([
|
|
2061
|
-
"one",
|
|
2062
|
-
"two",
|
|
2063
|
-
"three",
|
|
2064
|
-
"four",
|
|
2065
|
-
"five",
|
|
2066
|
-
"six",
|
|
2067
|
-
]);
|
|
2068
|
-
previousTree = previousTree.collapse("one", "two");
|
|
2069
|
-
previousTree = previousTree.collapse("three", "four");
|
|
2070
|
-
previousTree = previousTree.collapse("five", "six");
|
|
2071
|
-
|
|
2072
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
2073
|
-
["one", "two", "three", "four", "five", "six"],
|
|
2074
|
-
previousTree,
|
|
2075
|
-
);
|
|
2076
|
-
|
|
2077
|
-
expect(tree.isCollapsed("one")).toBe(true);
|
|
2078
|
-
expect(tree.isCollapsed("three")).toBe(true);
|
|
2079
|
-
expect(tree.isCollapsed("five")).toBe(true);
|
|
2080
|
-
expect(tree.topLevelIds).toEqual(["one", "three", "five"]);
|
|
2081
|
-
});
|
|
2082
|
-
|
|
2083
|
-
it("handles case where collapsed node's children are not in new ids", () => {
|
|
2084
|
-
let previousTree = CollapsibleTree.from(["one", "two", "three", "four"]);
|
|
2085
|
-
previousTree = previousTree.collapse("one", "two");
|
|
2086
|
-
|
|
2087
|
-
// Create new tree without the collapsed child
|
|
2088
|
-
const tree = CollapsibleTree.fromWithPreviousShape(
|
|
2089
|
-
["one", "three", "four"],
|
|
2090
|
-
previousTree,
|
|
2091
|
-
);
|
|
2092
|
-
|
|
2093
|
-
// Should not be collapsed since the child is missing
|
|
2094
|
-
expect(tree.isCollapsed("one")).toBe(false);
|
|
2095
|
-
expect(tree.topLevelIds).toEqual(["one", "three", "four"]);
|
|
2096
|
-
});
|
|
2097
|
-
|
|
2098
|
-
it("reproduces GitHub issue #6188: inOrderIds with nested collapses", () => {
|
|
2099
|
-
// Simplified reproduction case:
|
|
2100
|
-
// Cell A (markdown): # Section 1 Header
|
|
2101
|
-
// Cell B (markdown): ## Subsection 1.1 Header
|
|
2102
|
-
// Cell C (python): print("This cell should be in Subsection 1.1")
|
|
2103
|
-
// Cell D (python): print("This cell should also be in Subsection 1.1")
|
|
2104
|
-
// Cell E (markdown): ## Subsection 1.2 Header
|
|
2105
|
-
// Cell F (python): print("This cell should be in Subsection 1.2")
|
|
2106
|
-
|
|
2107
|
-
const originalOrder = [
|
|
2108
|
-
"CellA", // # Section 1 Header
|
|
2109
|
-
"CellB", // ## Subsection 1.1 Header
|
|
2110
|
-
"CellC", // print("This cell should be in Subsection 1.1")
|
|
2111
|
-
"CellD", // print("This cell should also be in Subsection 1.1")
|
|
2112
|
-
"CellE", // ## Subsection 1.2 Header
|
|
2113
|
-
"CellF", // print("This cell should be in Subsection 1.2")
|
|
2114
|
-
];
|
|
2115
|
-
|
|
2116
|
-
// Create notebook with one column
|
|
2117
|
-
let notebook = MultiColumn.from([originalOrder]);
|
|
2118
|
-
|
|
2119
|
-
// Before collapsing, order should be correct
|
|
2120
|
-
expect(notebook.inOrderIds).toEqual(originalOrder);
|
|
2121
|
-
|
|
2122
|
-
const columnId = notebook.getColumnIds()[0];
|
|
2123
|
-
|
|
2124
|
-
// Follow the exact reproduction steps from the GitHub issue:
|
|
2125
|
-
// 1. Collapse B (subsection 1.1) - includes C, D (stops before E)
|
|
2126
|
-
notebook = notebook.transform(columnId, (tree) =>
|
|
2127
|
-
tree.collapse("CellB", "CellD"),
|
|
2128
|
-
);
|
|
2129
|
-
|
|
2130
|
-
// 2. Collapse E (subsection 1.2) - includes F (to end)
|
|
2131
|
-
notebook = notebook.transform(columnId, (tree) =>
|
|
2132
|
-
tree.collapse("CellE", undefined),
|
|
2133
|
-
);
|
|
2134
|
-
|
|
2135
|
-
// 3. Collapse A (section 1) - includes all the rest (B, E and their children)
|
|
2136
|
-
notebook = notebook.transform(columnId, (tree) =>
|
|
2137
|
-
tree.collapse("CellA", undefined),
|
|
2138
|
-
);
|
|
2139
|
-
|
|
2140
|
-
const finalOrder = notebook.inOrderIds;
|
|
2141
|
-
|
|
2142
|
-
// inOrderIds now correctly preserves logical order even with nested collapses
|
|
2143
|
-
expect(finalOrder).toEqual(originalOrder);
|
|
2144
|
-
});
|
|
2145
|
-
});
|