@weng-lab/genomebrowser-ui 0.3.6 → 0.4.0-beta.1
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/.env.local +1 -1
- package/dist/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.d.ts +7 -0
- package/dist/TrackSelect/Folders/biosamples/shared/createFolder.d.ts +1 -13
- package/dist/TrackSelect/Folders/biosamples/shared/toTrack.d.ts +20 -0
- package/dist/TrackSelect/Folders/biosamples/shared/types.d.ts +4 -13
- package/dist/TrackSelect/Folders/genes/shared/columns.d.ts +2 -2
- package/dist/TrackSelect/Folders/genes/shared/createFolder.d.ts +1 -3
- package/dist/TrackSelect/Folders/genes/shared/toTrack.d.ts +18 -0
- package/dist/TrackSelect/Folders/genes/shared/types.d.ts +2 -0
- package/dist/TrackSelect/Folders/index.d.ts +6 -12
- package/dist/TrackSelect/Folders/mohd/data/human.json.d.ts +2948 -0
- package/dist/TrackSelect/Folders/mohd/human.d.ts +1 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdGroupingCell.d.ts +2 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdTreeItem.d.ts +3 -0
- package/dist/TrackSelect/Folders/mohd/shared/MohdViewSelector.d.ts +7 -0
- package/dist/TrackSelect/Folders/mohd/shared/columns.d.ts +5 -0
- package/dist/TrackSelect/Folders/mohd/shared/config.d.ts +42 -0
- package/dist/TrackSelect/Folders/mohd/shared/createFolder.d.ts +9 -0
- package/dist/TrackSelect/Folders/mohd/shared/toTrack.d.ts +9 -0
- package/dist/TrackSelect/Folders/mohd/shared/types.d.ts +40 -0
- package/dist/TrackSelect/Folders/other-tracks/shared/toTrack.d.ts +5 -0
- package/dist/TrackSelect/Folders/other-tracks/shared/types.d.ts +1 -0
- package/dist/TrackSelect/Folders/types.d.ts +23 -55
- package/dist/TrackSelect/TrackSelect.d.ts +10 -7
- package/dist/TrackSelect/TreeView/TreeViewWrapper.d.ts +1 -1
- package/dist/TrackSelect/buildSelectedTree.d.ts +15 -0
- package/dist/TrackSelect/managedTracks.d.ts +13 -0
- package/dist/TrackSelect/resolveFolderView.d.ts +2 -0
- package/dist/TrackSelect/trackContext.d.ts +5 -0
- package/dist/TrackSelect/types.d.ts +12 -33
- package/dist/genomebrowser-ui.es.js +2231 -1732
- package/dist/genomebrowser-ui.es.js.map +1 -1
- package/dist/lib.d.ts +4 -4
- package/dist/muiLicense.d.ts +1 -0
- package/package.json +6 -3
- package/src/TrackSelect/Dialogs/ClearDialog.tsx +3 -8
- package/src/TrackSelect/Dialogs/ResetDialog.tsx +5 -4
- package/src/TrackSelect/FolderList/FolderCard.tsx +1 -1
- package/src/TrackSelect/Folders/biosamples/shared/BiosampleViewSelector.tsx +33 -0
- package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +39 -58
- package/src/TrackSelect/Folders/biosamples/shared/toTrack.ts +138 -0
- package/src/TrackSelect/Folders/biosamples/shared/types.ts +4 -16
- package/src/TrackSelect/Folders/genes/shared/columns.tsx +2 -2
- package/src/TrackSelect/Folders/genes/shared/createFolder.ts +11 -31
- package/src/TrackSelect/Folders/genes/shared/toTrack.ts +59 -0
- package/src/TrackSelect/Folders/genes/shared/types.ts +2 -0
- package/src/TrackSelect/Folders/index.ts +14 -17
- package/src/TrackSelect/Folders/mohd/data/human.json +2945 -0
- package/src/TrackSelect/Folders/mohd/human.ts +10 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdGroupingCell.tsx +68 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdTreeItem.tsx +17 -0
- package/src/TrackSelect/Folders/mohd/shared/MohdViewSelector.tsx +33 -0
- package/src/TrackSelect/Folders/mohd/shared/columns.tsx +79 -0
- package/src/TrackSelect/Folders/mohd/shared/config.tsx +71 -0
- package/src/TrackSelect/Folders/mohd/shared/createFolder.ts +144 -0
- package/src/TrackSelect/Folders/mohd/shared/toTrack.ts +164 -0
- package/src/TrackSelect/Folders/mohd/shared/types.ts +46 -0
- package/src/TrackSelect/Folders/other-tracks/shared/createFolder.ts +13 -14
- package/src/TrackSelect/Folders/other-tracks/shared/toTrack.ts +17 -0
- package/src/TrackSelect/Folders/other-tracks/shared/types.ts +1 -0
- package/src/TrackSelect/Folders/types.ts +26 -69
- package/src/TrackSelect/TrackSelect.tsx +301 -257
- package/src/TrackSelect/TreeView/CustomTreeItem.tsx +9 -9
- package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +84 -6
- package/src/TrackSelect/buildSelectedTree.ts +145 -0
- package/src/TrackSelect/managedTracks.ts +92 -0
- package/src/TrackSelect/resolveFolderView.ts +20 -0
- package/src/TrackSelect/trackContext.ts +9 -0
- package/src/TrackSelect/types.ts +14 -39
- package/src/lib.ts +13 -7
- package/src/muiLicense.ts +9 -0
- package/src/vite-env.d.ts +9 -0
- package/test/TrackSelect.test.tsx +435 -0
- package/test/main.tsx +36 -352
- package/test/mocks/logo-test.tsx +11 -0
- package/test/mohdDisplay.test.tsx +45 -0
- package/test/startup.test.ts +206 -0
- package/test/trackSelectState.test.ts +176 -0
- package/vite.config.ts +1 -0
- package/vitest.config.ts +20 -0
- package/dist/TrackSelect/Folders/biosamples/shared/AssayToggle.d.ts +0 -18
- package/dist/TrackSelect/Folders/biosamples/shared/treeBuilder.d.ts +0 -28
- package/dist/TrackSelect/Folders/genes/shared/treeBuilder.d.ts +0 -13
- package/dist/TrackSelect/Folders/other-tracks/shared/treeBuilder.d.ts +0 -4
- package/dist/TrackSelect/store.d.ts +0 -4
- package/src/TrackSelect/Folders/NEW.md +0 -929
- package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +0 -78
- package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +0 -224
- package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +0 -45
- package/src/TrackSelect/Folders/other-tracks/shared/treeBuilder.ts +0 -34
- package/src/TrackSelect/store.ts +0 -117
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Track, TrackType, createTrackStore } from "@weng-lab/genomebrowser";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { FolderDefinition } from "../src/TrackSelect/Folders/types";
|
|
4
|
+
import { diffManagedTracks } from "../src/TrackSelect/managedTracks";
|
|
5
|
+
|
|
6
|
+
interface TestRow {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const makeTrack = (id: string, title: string): Track => {
|
|
12
|
+
return {
|
|
13
|
+
id,
|
|
14
|
+
title,
|
|
15
|
+
height: 40,
|
|
16
|
+
trackType: TrackType.Custom,
|
|
17
|
+
} as Track;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const createTestFolder = (): FolderDefinition<TestRow> => {
|
|
21
|
+
const rows = [
|
|
22
|
+
{ id: "test-folder/managed-a", label: "Managed A" },
|
|
23
|
+
{ id: "test-folder/managed-b", label: "Managed B" },
|
|
24
|
+
{ id: "test-folder/managed-c", label: "Managed C" },
|
|
25
|
+
{ id: "test-folder/managed-d", label: "Managed D" },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
id: "test-folder",
|
|
30
|
+
label: "Test Folder",
|
|
31
|
+
rows,
|
|
32
|
+
columns: [],
|
|
33
|
+
groupingModel: [],
|
|
34
|
+
leafField: "label",
|
|
35
|
+
createTrack: (row) => makeTrack(row.id, row.label),
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const applyManagedTrackDiff = (
|
|
40
|
+
trackStore: ReturnType<typeof createTrackStore>,
|
|
41
|
+
diff: ReturnType<typeof diffManagedTracks>,
|
|
42
|
+
) => {
|
|
43
|
+
const { insertTrack, removeTrack } = trackStore.getState();
|
|
44
|
+
diff.idsToRemove.forEach((id) => removeTrack(id));
|
|
45
|
+
diff.tracksToAdd.forEach((track) => insertTrack(track));
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
describe("TrackSelect managed track diff", () => {
|
|
49
|
+
it("preserves existing managed tracks on submit when selections do not change", () => {
|
|
50
|
+
const folder = createTestFolder();
|
|
51
|
+
const trackStore = createTrackStore([
|
|
52
|
+
makeTrack("external-track", "External"),
|
|
53
|
+
makeTrack("test-folder/managed-a", "Managed A"),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
trackStore.getState().editTrack("test-folder/managed-a", { height: 120 });
|
|
57
|
+
const editedManagedTrack = trackStore
|
|
58
|
+
.getState()
|
|
59
|
+
.getTrack("test-folder/managed-a");
|
|
60
|
+
|
|
61
|
+
applyManagedTrackDiff(
|
|
62
|
+
trackStore,
|
|
63
|
+
diffManagedTracks({
|
|
64
|
+
assembly: "GRCh38",
|
|
65
|
+
currentTracks: trackStore.getState().tracks,
|
|
66
|
+
folders: [folder],
|
|
67
|
+
selectedByFolder: new Map([
|
|
68
|
+
["test-folder", new Set(["test-folder/managed-a"])],
|
|
69
|
+
]),
|
|
70
|
+
}),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
expect(trackStore.getState().tracks.map((track) => track.id)).toEqual([
|
|
74
|
+
"external-track",
|
|
75
|
+
"test-folder/managed-a",
|
|
76
|
+
]);
|
|
77
|
+
expect(trackStore.getState().getTrack("test-folder/managed-a")).toBe(
|
|
78
|
+
editedManagedTrack,
|
|
79
|
+
);
|
|
80
|
+
expect(
|
|
81
|
+
trackStore.getState().getTrack("test-folder/managed-a")?.height,
|
|
82
|
+
).toBe(120);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("appends newly selected managed tracks to the bottom of the store", () => {
|
|
86
|
+
const folder = createTestFolder();
|
|
87
|
+
const trackStore = createTrackStore([
|
|
88
|
+
makeTrack("external-track", "External"),
|
|
89
|
+
makeTrack("test-folder/managed-a", "Managed A"),
|
|
90
|
+
]);
|
|
91
|
+
|
|
92
|
+
applyManagedTrackDiff(
|
|
93
|
+
trackStore,
|
|
94
|
+
diffManagedTracks({
|
|
95
|
+
assembly: "GRCh38",
|
|
96
|
+
currentTracks: trackStore.getState().tracks,
|
|
97
|
+
folders: [folder],
|
|
98
|
+
selectedByFolder: new Map([
|
|
99
|
+
[
|
|
100
|
+
"test-folder",
|
|
101
|
+
new Set(["test-folder/managed-a", "test-folder/managed-b"]),
|
|
102
|
+
],
|
|
103
|
+
]),
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(trackStore.getState().tracks.map((track) => track.id)).toEqual([
|
|
108
|
+
"external-track",
|
|
109
|
+
"test-folder/managed-a",
|
|
110
|
+
"test-folder/managed-b",
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("removes only deselected managed tracks while preserving unmanaged tracks", () => {
|
|
115
|
+
const folder = createTestFolder();
|
|
116
|
+
const trackStore = createTrackStore([
|
|
117
|
+
makeTrack("external-track", "External"),
|
|
118
|
+
makeTrack("test-folder/managed-a", "Managed A"),
|
|
119
|
+
makeTrack("test-folder/managed-b", "Managed B"),
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
applyManagedTrackDiff(
|
|
123
|
+
trackStore,
|
|
124
|
+
diffManagedTracks({
|
|
125
|
+
assembly: "GRCh38",
|
|
126
|
+
currentTracks: trackStore.getState().tracks,
|
|
127
|
+
folders: [folder],
|
|
128
|
+
selectedByFolder: new Map([
|
|
129
|
+
["test-folder", new Set(["test-folder/managed-b"])],
|
|
130
|
+
]),
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
expect(trackStore.getState().tracks.map((track) => track.id)).toEqual([
|
|
135
|
+
"external-track",
|
|
136
|
+
"test-folder/managed-b",
|
|
137
|
+
]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("applies multiple managed additions and removals in one submit flow", () => {
|
|
141
|
+
const folder = createTestFolder();
|
|
142
|
+
const trackStore = createTrackStore([
|
|
143
|
+
makeTrack("external-track", "External"),
|
|
144
|
+
makeTrack("test-folder/managed-a", "Managed A"),
|
|
145
|
+
makeTrack("test-folder/managed-c", "Managed C"),
|
|
146
|
+
]);
|
|
147
|
+
|
|
148
|
+
applyManagedTrackDiff(
|
|
149
|
+
trackStore,
|
|
150
|
+
diffManagedTracks({
|
|
151
|
+
assembly: "GRCh38",
|
|
152
|
+
currentTracks: trackStore.getState().tracks,
|
|
153
|
+
folders: [folder],
|
|
154
|
+
selectedByFolder: new Map([
|
|
155
|
+
[
|
|
156
|
+
"test-folder",
|
|
157
|
+
new Set(["test-folder/managed-b", "test-folder/managed-d"]),
|
|
158
|
+
],
|
|
159
|
+
]),
|
|
160
|
+
}),
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
expect(trackStore.getState().tracks.map((track) => track.id)).toEqual([
|
|
164
|
+
"external-track",
|
|
165
|
+
"test-folder/managed-b",
|
|
166
|
+
"test-folder/managed-d",
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("uses folder-owned track creation when adding managed tracks", () => {
|
|
171
|
+
const folder: FolderDefinition<TestRow> = {
|
|
172
|
+
...createTestFolder(),
|
|
173
|
+
createTrack: (row) => ({
|
|
174
|
+
...makeTrack(row.id, `test-folder:${row.label}`),
|
|
175
|
+
onClick: () => `${row.id}-clicked`,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
178
|
+
const trackStore = createTrackStore([
|
|
179
|
+
makeTrack("external-track", "External"),
|
|
180
|
+
]);
|
|
181
|
+
|
|
182
|
+
applyManagedTrackDiff(
|
|
183
|
+
trackStore,
|
|
184
|
+
diffManagedTracks({
|
|
185
|
+
assembly: "GRCh38",
|
|
186
|
+
currentTracks: trackStore.getState().tracks,
|
|
187
|
+
folders: [folder],
|
|
188
|
+
selectedByFolder: new Map([
|
|
189
|
+
["test-folder", new Set(["test-folder/managed-a"])],
|
|
190
|
+
]),
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
expect(trackStore.getState().tracks.map((track) => track.id)).toEqual([
|
|
195
|
+
"external-track",
|
|
196
|
+
"test-folder/managed-a",
|
|
197
|
+
]);
|
|
198
|
+
|
|
199
|
+
const managedTrack = trackStore
|
|
200
|
+
.getState()
|
|
201
|
+
.tracks.find((track) => track.id === "test-folder/managed-a");
|
|
202
|
+
|
|
203
|
+
expect(managedTrack?.title).toBe("test-folder:Managed A");
|
|
204
|
+
expect(typeof managedTrack?.onClick).toBe("function");
|
|
205
|
+
});
|
|
206
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { buildSelectedTree } from "../src/TrackSelect/buildSelectedTree";
|
|
3
|
+
vi.mock("../src/TrackSelect/Folders/mohd/shared/MohdGroupingCell", () => ({
|
|
4
|
+
MohdGroupingCell: () => null,
|
|
5
|
+
}));
|
|
6
|
+
vi.mock("../src/TrackSelect/Folders/mohd/shared/MohdTreeItem", () => ({
|
|
7
|
+
MohdTreeItem: () => null,
|
|
8
|
+
}));
|
|
9
|
+
vi.mock("../src/TrackSelect/Folders/mohd/shared/MohdViewSelector", () => ({
|
|
10
|
+
MohdViewSelector: () => null,
|
|
11
|
+
}));
|
|
12
|
+
import { humanMohdFolder } from "../src/TrackSelect/Folders/mohd/human";
|
|
13
|
+
import { FolderDefinition } from "../src/TrackSelect/Folders/types";
|
|
14
|
+
import { resolveFolderView } from "../src/TrackSelect/resolveFolderView";
|
|
15
|
+
|
|
16
|
+
interface TestRow {
|
|
17
|
+
id: string;
|
|
18
|
+
label: string;
|
|
19
|
+
group: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const createTestFolder = (
|
|
23
|
+
id: string,
|
|
24
|
+
overrides: Partial<FolderDefinition<TestRow>> = {},
|
|
25
|
+
): FolderDefinition<TestRow> => {
|
|
26
|
+
const rows = [
|
|
27
|
+
{ id: `${id}-a`, label: `${id} A`, group: "group-1" },
|
|
28
|
+
{ id: `${id}-b`, label: `${id} B`, group: "group-1" },
|
|
29
|
+
{ id: `${id}-c`, label: `${id} C`, group: "group-2" },
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
id,
|
|
34
|
+
label: id,
|
|
35
|
+
rows,
|
|
36
|
+
columns: [],
|
|
37
|
+
groupingModel: [],
|
|
38
|
+
leafField: "label",
|
|
39
|
+
createTrack: () => null,
|
|
40
|
+
...overrides,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
describe("TrackSelect direct view helpers", () => {
|
|
45
|
+
it("resolves the active folder view with sensible fallback behavior", () => {
|
|
46
|
+
const folder = createTestFolder("folder-a", {
|
|
47
|
+
views: [
|
|
48
|
+
{
|
|
49
|
+
id: "default",
|
|
50
|
+
label: "Default",
|
|
51
|
+
columns: [],
|
|
52
|
+
groupingModel: [],
|
|
53
|
+
leafField: "label",
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: "runtime",
|
|
57
|
+
label: "Runtime",
|
|
58
|
+
columns: [{ field: "runtime-label" } as never],
|
|
59
|
+
groupingModel: ["group"],
|
|
60
|
+
leafField: "id",
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
expect(resolveFolderView(folder, new Map()).id).toBe("default");
|
|
66
|
+
expect(
|
|
67
|
+
resolveFolderView(folder, new Map([[folder.id, "runtime"]])).id,
|
|
68
|
+
).toBe("runtime");
|
|
69
|
+
expect(
|
|
70
|
+
resolveFolderView(folder, new Map([[folder.id, "missing"]])).id,
|
|
71
|
+
).toBe("default");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("builds a flat selected tree from the leaf field when there is no grouping", () => {
|
|
75
|
+
const folder = createTestFolder("folder-a");
|
|
76
|
+
|
|
77
|
+
const tree = buildSelectedTree({
|
|
78
|
+
folderId: folder.id,
|
|
79
|
+
rootLabel: folder.label,
|
|
80
|
+
selectedRows: folder.rows.slice(0, 2),
|
|
81
|
+
groupingModel: [],
|
|
82
|
+
leafField: "label",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
expect(tree[0]?.label).toBe(folder.label);
|
|
86
|
+
expect(tree[0]?.children?.map((item) => item.label)).toEqual([
|
|
87
|
+
"folder-a A",
|
|
88
|
+
"folder-a B",
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("builds grouped selected trees that match the configured grouping model", () => {
|
|
93
|
+
const folder = createTestFolder("folder-a");
|
|
94
|
+
|
|
95
|
+
const tree = buildSelectedTree({
|
|
96
|
+
folderId: folder.id,
|
|
97
|
+
rootLabel: folder.label,
|
|
98
|
+
selectedRows: folder.rows,
|
|
99
|
+
groupingModel: ["group"],
|
|
100
|
+
leafField: "label",
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(tree[0]?.children?.map((item) => item.label)).toEqual([
|
|
104
|
+
"group-1",
|
|
105
|
+
"group-2",
|
|
106
|
+
]);
|
|
107
|
+
expect(tree[0]?.children?.[0]?.children?.map((item) => item.label)).toEqual(
|
|
108
|
+
["folder-a A", "folder-a B"],
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("uses the default MOHD view to group by ome, then site, then sample", () => {
|
|
113
|
+
const activeView = resolveFolderView(humanMohdFolder, new Map());
|
|
114
|
+
const selectedRows = humanMohdFolder.rows.filter(
|
|
115
|
+
(row) => row.sampleId === "MOHD_EA100001",
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
const tree = buildSelectedTree({
|
|
119
|
+
folderId: humanMohdFolder.id,
|
|
120
|
+
rootLabel: humanMohdFolder.label,
|
|
121
|
+
selectedRows,
|
|
122
|
+
groupingModel: activeView.groupingModel,
|
|
123
|
+
leafField: activeView.leafField,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
expect(activeView.id).toBe("ome");
|
|
127
|
+
expect(tree[0]?.children?.map((item) => item.label)).toEqual(["ATAC"]);
|
|
128
|
+
expect(tree[0]?.children?.[0]?.children?.map((item) => item.label)).toEqual(
|
|
129
|
+
["CCH"],
|
|
130
|
+
);
|
|
131
|
+
expect(
|
|
132
|
+
tree[0]?.children?.[0]?.children?.[0]?.children?.map(
|
|
133
|
+
(item) => item.label,
|
|
134
|
+
),
|
|
135
|
+
).toEqual(["MOHD_EA100001"]);
|
|
136
|
+
expect(
|
|
137
|
+
tree[0]?.children?.[0]?.children?.[0]?.children?.[0]?.children?.map(
|
|
138
|
+
(item) => item.label,
|
|
139
|
+
),
|
|
140
|
+
).toEqual([
|
|
141
|
+
"FDR 0.05 peaks",
|
|
142
|
+
"Fold change signal",
|
|
143
|
+
"Pseudorep peaks",
|
|
144
|
+
"p-value signal",
|
|
145
|
+
]);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("builds the selected MOHD tree from the site-first view when active", () => {
|
|
149
|
+
const activeView = resolveFolderView(
|
|
150
|
+
humanMohdFolder,
|
|
151
|
+
new Map([[humanMohdFolder.id, "site"]]),
|
|
152
|
+
);
|
|
153
|
+
const selectedRows = humanMohdFolder.rows.filter(
|
|
154
|
+
(row) => row.sampleId === "MOHD_EA100001",
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const tree = buildSelectedTree({
|
|
158
|
+
folderId: humanMohdFolder.id,
|
|
159
|
+
rootLabel: humanMohdFolder.label,
|
|
160
|
+
selectedRows,
|
|
161
|
+
groupingModel: activeView.groupingModel,
|
|
162
|
+
leafField: activeView.leafField,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(activeView.id).toBe("site");
|
|
166
|
+
expect(tree[0]?.children?.map((item) => item.label)).toEqual(["CCH"]);
|
|
167
|
+
expect(tree[0]?.children?.[0]?.children?.map((item) => item.label)).toEqual(
|
|
168
|
+
["ATAC"],
|
|
169
|
+
);
|
|
170
|
+
expect(
|
|
171
|
+
tree[0]?.children?.[0]?.children?.[0]?.children?.map(
|
|
172
|
+
(item) => item.label,
|
|
173
|
+
),
|
|
174
|
+
).toEqual(["MOHD_EA100001"]);
|
|
175
|
+
});
|
|
176
|
+
});
|
package/vite.config.ts
CHANGED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import react from "@vitejs/plugin-react";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { defineConfig } from "vitest/config";
|
|
5
|
+
|
|
6
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
plugins: [react()],
|
|
10
|
+
resolve: {
|
|
11
|
+
alias: {
|
|
12
|
+
buffer: "buffer",
|
|
13
|
+
"@weng-lab/genomebrowser": path.resolve(__dirname, "../core/src/lib.ts"),
|
|
14
|
+
"logo-test": path.resolve(__dirname, "./test/mocks/logo-test.tsx"),
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
test: {
|
|
18
|
+
environment: "node",
|
|
19
|
+
},
|
|
20
|
+
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { FolderRuntimeConfig } from '../../types';
|
|
2
|
-
export interface AssayToggleProps {
|
|
3
|
-
updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
|
|
4
|
-
folderId: string;
|
|
5
|
-
label: string;
|
|
6
|
-
config: FolderRuntimeConfig;
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Biosample-specific toolbar component that toggles between
|
|
10
|
-
* sample-grouped and assay-grouped views.
|
|
11
|
-
*
|
|
12
|
-
* When toggled, it updates the folder's runtime config to switch:
|
|
13
|
-
* - columns: Different column definitions for each view
|
|
14
|
-
* - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology"]
|
|
15
|
-
* - leafField: "assay" vs "displayName"
|
|
16
|
-
* - buildTree: Different tree builder function
|
|
17
|
-
*/
|
|
18
|
-
export declare function AssayToggle({ updateConfig, folderId, label, config, }: AssayToggleProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { TreeViewBaseItem } from '@mui/x-tree-view';
|
|
2
|
-
import { ExtendedTreeItemProps } from '../../../types';
|
|
3
|
-
import { BiosampleRowInfo } from './types';
|
|
4
|
-
/**
|
|
5
|
-
* Builds tree in the sorted by assay view
|
|
6
|
-
* Hierarchy: Assay -> Ontology -> DisplayName (leaf)
|
|
7
|
-
*
|
|
8
|
-
* This is the reverse of the default view - instead of grouping by sample first,
|
|
9
|
-
* we group by assay first, making displayName the leaf node.
|
|
10
|
-
*
|
|
11
|
-
* @param selectedIds - list of selected row IDs
|
|
12
|
-
* @param rowById - Mapping between an id and its BiosampleRowInfo object
|
|
13
|
-
* @param rootLabel - Label for the root node
|
|
14
|
-
* @param folderId - Folder ID to prefix tree item IDs with
|
|
15
|
-
* @returns tree items for the RichTreeView
|
|
16
|
-
*/
|
|
17
|
-
export declare function buildSortedAssayTreeView(selectedIds: string[], rowById: Map<string, BiosampleRowInfo>, rootLabel?: string, folderId?: string): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
18
|
-
/**
|
|
19
|
-
* Builds tree in the default view (sorted by ontology)
|
|
20
|
-
* Hierarchy: Ontology -> DisplayName -> Experiment
|
|
21
|
-
*
|
|
22
|
-
* @param selectedIds - list of selected row IDs
|
|
23
|
-
* @param rowById - Mapping between an id and its BiosampleRowInfo object
|
|
24
|
-
* @param rootLabel - Label for the root node
|
|
25
|
-
* @param folderId - Folder ID to prefix tree item IDs with
|
|
26
|
-
* @returns tree items for the RichTreeView
|
|
27
|
-
*/
|
|
28
|
-
export declare function buildTreeView(selectedIds: string[], rowById: Map<string, BiosampleRowInfo>, rootLabel?: string, folderId?: string): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { TreeViewBaseItem } from '@mui/x-tree-view';
|
|
2
|
-
import { ExtendedTreeItemProps } from '../../../types';
|
|
3
|
-
import { GeneRowInfo } from './types';
|
|
4
|
-
/**
|
|
5
|
-
* Builds a flat tree structure for the TreeView panel (selected items)
|
|
6
|
-
* Since genes have no grouping, this is a simple root -> leaf structure
|
|
7
|
-
*
|
|
8
|
-
* @param selectedIds - Array of selected row IDs
|
|
9
|
-
* @param rowById - Map of row ID to row data
|
|
10
|
-
* @param rootLabel - Label for the root node
|
|
11
|
-
* @returns Tree structure for RichTreeView
|
|
12
|
-
*/
|
|
13
|
-
export declare function buildTreeView(selectedIds: string[], rowById: Map<string, GeneRowInfo>, rootLabel?: string): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { TreeViewBaseItem } from '@mui/x-tree-view';
|
|
2
|
-
import { ExtendedTreeItemProps } from '../../../types';
|
|
3
|
-
import { OtherTrackInfo } from './types';
|
|
4
|
-
export declare function buildTreeView(selectedIds: string[], rowById: Map<string, OtherTrackInfo>, rootLabel?: string): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { StoreApi, UseBoundStore } from 'zustand';
|
|
2
|
-
import { SelectionAction, SelectionState } from './types';
|
|
3
|
-
export type SelectionStoreInstance = UseBoundStore<StoreApi<SelectionState & SelectionAction>>;
|
|
4
|
-
export declare function createSelectionStore(folderIds: string[], storageKey?: string, initialSelection?: Map<string, Set<string>>): UseBoundStore<StoreApi<SelectionState & SelectionAction>>;
|