@weng-lab/genomebrowser-ui 0.1.11 → 0.2.0-beta.0
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 -0
- package/dist/TrackSelect/DataGrid/DefaultGroupingCell.d.ts +6 -0
- package/dist/TrackSelect/FolderList/Breadcrumb.d.ts +6 -0
- package/dist/TrackSelect/FolderList/FolderCard.d.ts +6 -0
- package/dist/TrackSelect/FolderList/FolderList.d.ts +6 -0
- package/dist/TrackSelect/{Data/humanBiosamples.json.d.ts → Folders/biosamples/data/human.json.d.ts} +1940 -1919
- package/dist/TrackSelect/{Data/mouseBiosamples.json.d.ts → Folders/biosamples/data/mouse.json.d.ts} +408 -357
- package/dist/TrackSelect/Folders/biosamples/human.d.ts +7 -0
- package/dist/TrackSelect/Folders/biosamples/mouse.d.ts +7 -0
- package/dist/TrackSelect/Folders/biosamples/shared/AssayToggle.d.ts +14 -0
- package/dist/TrackSelect/Folders/biosamples/shared/BiosampleGroupingCell.d.ts +6 -0
- package/dist/TrackSelect/Folders/biosamples/shared/BiosampleTreeItem.d.ts +7 -0
- package/dist/TrackSelect/Folders/biosamples/shared/columns.d.ts +14 -0
- package/dist/TrackSelect/Folders/biosamples/shared/constants.d.ts +19 -0
- package/dist/TrackSelect/Folders/biosamples/shared/createFolder.d.ts +24 -0
- package/dist/TrackSelect/Folders/biosamples/shared/treeBuilder.d.ts +25 -0
- package/dist/TrackSelect/Folders/biosamples/shared/types.d.ts +44 -0
- package/dist/TrackSelect/Folders/genes/data/human.json.d.ts +10 -0
- package/dist/TrackSelect/Folders/genes/data/mouse.json.d.ts +10 -0
- package/dist/TrackSelect/Folders/genes/human.d.ts +7 -0
- package/dist/TrackSelect/Folders/genes/mouse.d.ts +7 -0
- package/dist/TrackSelect/Folders/genes/shared/columns.d.ts +14 -0
- package/dist/TrackSelect/Folders/genes/shared/createFolder.d.ts +12 -0
- package/dist/TrackSelect/Folders/genes/shared/treeBuilder.d.ts +13 -0
- package/dist/TrackSelect/Folders/genes/shared/types.d.ts +26 -0
- package/dist/TrackSelect/Folders/index.d.ts +14 -0
- package/dist/TrackSelect/Folders/types.d.ts +76 -0
- package/dist/TrackSelect/TrackSelect.d.ts +12 -5
- package/dist/TrackSelect/TreeView/CustomTreeItem.d.ts +3 -0
- package/dist/TrackSelect/TreeView/TreeViewWrapper.d.ts +1 -1
- package/dist/TrackSelect/store.d.ts +1 -2
- package/dist/TrackSelect/types.d.ts +24 -62
- package/dist/genomebrowser-ui.es.js +1373 -2117
- package/dist/genomebrowser-ui.es.js.map +1 -1
- package/dist/lib.d.ts +2 -2
- package/package.json +3 -3
- package/src/TrackSelect/DataGrid/DataGridWrapper.tsx +36 -20
- package/src/TrackSelect/DataGrid/DefaultGroupingCell.tsx +64 -0
- package/src/TrackSelect/FolderList/Breadcrumb.tsx +38 -0
- package/src/TrackSelect/FolderList/FolderCard.tsx +51 -0
- package/src/TrackSelect/FolderList/FolderList.tsx +47 -0
- package/src/TrackSelect/Folders/NEW.md +929 -0
- package/src/TrackSelect/{Data → Folders/biosamples/data}/formatBiosamples.go +2 -2
- package/src/TrackSelect/{Data/humanBiosamples.json → Folders/biosamples/data/human.json} +1940 -1919
- package/src/TrackSelect/{Data/mouseBiosamples.json → Folders/biosamples/data/mouse.json} +408 -357
- package/src/TrackSelect/Folders/biosamples/human.ts +17 -0
- package/src/TrackSelect/Folders/biosamples/mouse.ts +17 -0
- package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +65 -0
- package/src/TrackSelect/{DataGrid/GroupingCell.tsx → Folders/biosamples/shared/BiosampleGroupingCell.tsx} +7 -5
- package/src/TrackSelect/Folders/biosamples/shared/BiosampleTreeItem.tsx +15 -0
- package/src/TrackSelect/{DataGrid → Folders/biosamples/shared}/columns.tsx +31 -17
- package/src/TrackSelect/Folders/biosamples/shared/constants.tsx +116 -0
- package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +116 -0
- package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +227 -0
- package/src/TrackSelect/Folders/biosamples/shared/types.ts +48 -0
- package/src/TrackSelect/Folders/genes/data/human.json +7 -0
- package/src/TrackSelect/Folders/genes/data/mouse.json +7 -0
- package/src/TrackSelect/Folders/genes/human.ts +16 -0
- package/src/TrackSelect/Folders/genes/mouse.ts +16 -0
- package/src/TrackSelect/Folders/genes/shared/columns.tsx +42 -0
- package/src/TrackSelect/Folders/genes/shared/createFolder.ts +68 -0
- package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +45 -0
- package/src/TrackSelect/Folders/genes/shared/types.ts +29 -0
- package/src/TrackSelect/Folders/index.ts +27 -0
- package/src/TrackSelect/Folders/types.ts +95 -0
- package/src/TrackSelect/TrackSelect.tsx +409 -311
- package/src/TrackSelect/TreeView/CustomTreeItem.tsx +217 -0
- package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +47 -42
- package/src/TrackSelect/store.ts +103 -46
- package/src/TrackSelect/types.ts +28 -74
- package/src/lib.ts +2 -2
- package/test/main.tsx +113 -169
- package/.claude/settings.local.json +0 -7
- package/dist/TrackSelect/DataGrid/CustomToolbar.d.ts +0 -12
- package/dist/TrackSelect/DataGrid/GroupingCell.d.ts +0 -2
- package/dist/TrackSelect/DataGrid/columns.d.ts +0 -4
- package/dist/TrackSelect/DataGrid/dataGridHelpers.d.ts +0 -49
- package/dist/TrackSelect/TreeView/treeViewHelpers.d.ts +0 -49
- package/dist/TrackSelect/consts.d.ts +0 -11
- package/src/TrackSelect/DataGrid/CustomToolbar.tsx +0 -152
- package/src/TrackSelect/DataGrid/dataGridHelpers.tsx +0 -155
- package/src/TrackSelect/TreeView/treeViewHelpers.tsx +0 -475
- package/src/TrackSelect/consts.ts +0 -92
- package/src/TrackSelect/issues.md +0 -404
package/test/main.tsx
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
2
|
+
|
|
1
3
|
// react
|
|
2
4
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
5
|
import { createRoot } from "react-dom/client";
|
|
4
6
|
|
|
7
|
+
// license
|
|
8
|
+
import { LicenseInfo } from "@mui/x-license";
|
|
9
|
+
const muiLicenseKey = import.meta.env.VITE_MUI_X_LICENSE_KEY;
|
|
10
|
+
if (muiLicenseKey) {
|
|
11
|
+
LicenseInfo.setLicenseKey(muiLicenseKey);
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
// mui
|
|
6
15
|
import EditIcon from "@mui/icons-material/Edit";
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
Box,
|
|
10
|
-
Button,
|
|
11
|
-
Dialog,
|
|
12
|
-
DialogContent,
|
|
13
|
-
DialogTitle,
|
|
14
|
-
IconButton,
|
|
15
|
-
Typography,
|
|
16
|
-
} from "@mui/material";
|
|
16
|
+
import { Button } from "@mui/material";
|
|
17
17
|
|
|
18
18
|
// weng lab
|
|
19
19
|
import {
|
|
@@ -32,7 +32,9 @@ import {
|
|
|
32
32
|
} from "@weng-lab/genomebrowser";
|
|
33
33
|
|
|
34
34
|
// local
|
|
35
|
-
import {
|
|
35
|
+
import { foldersByAssembly, TrackSelect } from "../src/lib";
|
|
36
|
+
import type { BiosampleRowInfo } from "../src/TrackSelect/Folders/biosamples/shared/types";
|
|
37
|
+
import type { GeneRowInfo } from "../src/TrackSelect/Folders/genes/shared/types";
|
|
36
38
|
import { Exon } from "@weng-lab/genomebrowser/dist/components/tracks/transcript/types";
|
|
37
39
|
|
|
38
40
|
interface Transcript {
|
|
@@ -44,10 +46,7 @@ interface Transcript {
|
|
|
44
46
|
color?: string;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
human = "GRCh38",
|
|
49
|
-
mouse = "mm10",
|
|
50
|
-
}
|
|
49
|
+
type Assembly = "GRCh38" | "mm10";
|
|
51
50
|
|
|
52
51
|
// Callback types for track interactions (using any to avoid type conflicts with library types)
|
|
53
52
|
interface TrackCallbacks {
|
|
@@ -78,25 +77,9 @@ function injectCallbacks(track: Track, callbacks: TrackCallbacks): Track {
|
|
|
78
77
|
return track;
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
function getLocalStorage(assembly: Assembly): Set<string> | null {
|
|
82
|
-
if (typeof window === "undefined" || !window.sessionStorage) return null;
|
|
83
|
-
|
|
84
|
-
const selectedIds = sessionStorage.getItem(assembly + "-selected-tracks");
|
|
85
|
-
if (!selectedIds) return null;
|
|
86
|
-
const idsArray = JSON.parse(selectedIds) as string[];
|
|
87
|
-
return new Set(idsArray);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function setLocalStorage(trackIds: Set<string>, assembly: Assembly) {
|
|
91
|
-
sessionStorage.setItem(
|
|
92
|
-
assembly + "-selected-tracks",
|
|
93
|
-
JSON.stringify([...trackIds]),
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
80
|
function Main() {
|
|
98
81
|
const [open, setOpen] = useState(false);
|
|
99
|
-
const currentAssembly =
|
|
82
|
+
const currentAssembly: Assembly = "mm10";
|
|
100
83
|
|
|
101
84
|
const browserStore = createBrowserStoreMemo({
|
|
102
85
|
// chr12:53,380,176-53,416,446
|
|
@@ -151,67 +134,78 @@ function Main() {
|
|
|
151
134
|
const insertTrack = trackStore((s) => s.insertTrack);
|
|
152
135
|
const removeTrack = trackStore((s) => s.removeTrack);
|
|
153
136
|
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
}, [currentAssembly]);
|
|
137
|
+
const folders = useMemo(
|
|
138
|
+
() => foldersByAssembly[currentAssembly],
|
|
139
|
+
[currentAssembly],
|
|
140
|
+
);
|
|
159
141
|
|
|
160
|
-
const
|
|
142
|
+
const storageKey = `${currentAssembly}-selected-tracks`;
|
|
161
143
|
|
|
162
|
-
|
|
144
|
+
const initialSelection = useMemo(
|
|
145
|
+
() =>
|
|
146
|
+
(currentAssembly as Assembly) === "GRCh38"
|
|
147
|
+
? defaultHumanSelections
|
|
148
|
+
: defaultMouseSelections,
|
|
149
|
+
[currentAssembly],
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// sync tracks to browser and save to localStorage
|
|
163
153
|
const handleSubmit = useCallback(
|
|
164
|
-
(
|
|
154
|
+
(selectedByFolder: Map<string, Set<string>>) => {
|
|
165
155
|
const currentIds = new Set(tracks.map((t) => t.id));
|
|
156
|
+
const selectedIds = new Set<string>();
|
|
157
|
+
const tracksToAdd: Array<{ row: unknown; folderId: string }> = [];
|
|
158
|
+
|
|
159
|
+
for (const folder of folders) {
|
|
160
|
+
const folderSelection =
|
|
161
|
+
selectedByFolder.get(folder.id) ?? new Set<string>();
|
|
162
|
+
folderSelection.forEach((id) => {
|
|
163
|
+
selectedIds.add(id);
|
|
164
|
+
if (currentIds.has(id)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const row = folder.rowById.get(id);
|
|
168
|
+
if (row) {
|
|
169
|
+
tracksToAdd.push({ row, folderId: folder.id });
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
166
173
|
|
|
167
|
-
|
|
168
|
-
const tracksToAdd = Array.from(newTrackIds)
|
|
169
|
-
.filter((id) => !currentIds.has(id)) // not in current track list
|
|
170
|
-
.map((id) => rowById.get(id)) // get RowInfo object
|
|
171
|
-
.filter((track): track is RowInfo => track !== undefined); // filter out undefined
|
|
172
|
-
|
|
173
|
-
const tracksToRemove = tracks.filter((t) => {
|
|
174
|
-
return !t.id.includes("ignore") && !newTrackIds.has(t.id);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
console.log("removing", tracksToRemove);
|
|
174
|
+
const tracksToRemove = tracks.filter((t) => !selectedIds.has(t.id));
|
|
178
175
|
for (const t of tracksToRemove) {
|
|
179
176
|
removeTrack(t.id);
|
|
180
177
|
}
|
|
181
178
|
|
|
182
|
-
for (const
|
|
183
|
-
const track = generateTrack(
|
|
179
|
+
for (const { row, folderId } of tracksToAdd) {
|
|
180
|
+
const track = generateTrack(
|
|
181
|
+
row as BiosampleRowInfo | GeneRowInfo,
|
|
182
|
+
folderId,
|
|
183
|
+
currentAssembly,
|
|
184
|
+
callbacks,
|
|
185
|
+
);
|
|
184
186
|
if (track === null) continue;
|
|
185
187
|
insertTrack(track);
|
|
186
188
|
}
|
|
187
|
-
|
|
188
|
-
// Save the track IDs (not the auto-generated group IDs)
|
|
189
|
-
setLocalStorage(newTrackIds, currentAssembly);
|
|
190
|
-
// Close the dialog
|
|
191
|
-
setOpen(false);
|
|
192
189
|
},
|
|
193
|
-
[tracks, removeTrack, insertTrack, callbacks],
|
|
190
|
+
[tracks, removeTrack, insertTrack, callbacks, folders, currentAssembly],
|
|
194
191
|
);
|
|
195
192
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Handle reset: clear selections and remove non-default tracks
|
|
201
|
-
const handleReset = () => {
|
|
202
|
-
// Clear the selection store
|
|
203
|
-
selectionStore.getState().clear();
|
|
204
|
-
|
|
205
|
-
// Remove all non-default tracks from the browser
|
|
206
|
-
const tracksToRemove = tracks.filter((t) => !t.id.includes("ignore"));
|
|
207
|
-
for (const t of tracksToRemove) {
|
|
193
|
+
// clear selections and remove all tracks
|
|
194
|
+
const handleClear = () => {
|
|
195
|
+
for (const t of tracks) {
|
|
208
196
|
removeTrack(t.id);
|
|
209
197
|
}
|
|
210
|
-
|
|
211
|
-
// Clear localStorage for selected tracks
|
|
212
|
-
setLocalStorage(new Set(), currentAssembly);
|
|
213
198
|
};
|
|
214
199
|
|
|
200
|
+
// On first load, if no stored selection exists, apply initial selection
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
const stored = sessionStorage.getItem(storageKey);
|
|
203
|
+
if (!stored) {
|
|
204
|
+
handleSubmit(initialSelection);
|
|
205
|
+
}
|
|
206
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
207
|
+
}, []);
|
|
208
|
+
|
|
215
209
|
return (
|
|
216
210
|
<>
|
|
217
211
|
<Button
|
|
@@ -222,38 +216,17 @@ function Main() {
|
|
|
222
216
|
>
|
|
223
217
|
Select Tracks
|
|
224
218
|
</Button>
|
|
225
|
-
<
|
|
219
|
+
<TrackSelect
|
|
220
|
+
folders={folders}
|
|
221
|
+
storageKey={storageKey}
|
|
222
|
+
initialSelection={initialSelection}
|
|
223
|
+
onSubmit={handleSubmit}
|
|
224
|
+
onClear={handleClear}
|
|
225
|
+
maxTracks={30}
|
|
226
226
|
open={open}
|
|
227
227
|
onClose={() => setOpen(false)}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
>
|
|
231
|
-
<DialogTitle
|
|
232
|
-
bgcolor="#0c184a"
|
|
233
|
-
color="white"
|
|
234
|
-
display={"flex"}
|
|
235
|
-
justifyContent={"space-between"}
|
|
236
|
-
alignItems={"center"}
|
|
237
|
-
fontWeight={"bold"}
|
|
238
|
-
>
|
|
239
|
-
Biosample Tracks
|
|
240
|
-
<IconButton
|
|
241
|
-
size="large"
|
|
242
|
-
onClick={() => setOpen(false)}
|
|
243
|
-
sx={{ color: "white", padding: 0 }}
|
|
244
|
-
>
|
|
245
|
-
<CloseIcon fontSize="large" />
|
|
246
|
-
</IconButton>
|
|
247
|
-
</DialogTitle>
|
|
248
|
-
<DialogContent sx={{ marginTop: "5px" }}>
|
|
249
|
-
<TrackSelect
|
|
250
|
-
store={selectionStore}
|
|
251
|
-
onSubmit={handleSubmit}
|
|
252
|
-
onCancel={handleCancel}
|
|
253
|
-
onReset={handleReset}
|
|
254
|
-
/>
|
|
255
|
-
</DialogContent>
|
|
256
|
-
</Dialog>
|
|
228
|
+
title="Biosample Tracks"
|
|
229
|
+
/>
|
|
257
230
|
<GQLWrapper>
|
|
258
231
|
<Browser browserStore={browserStore} trackStore={trackStore} />
|
|
259
232
|
</GQLWrapper>
|
|
@@ -271,29 +244,40 @@ const ASSAY_COLORS: Record<string, string> = {
|
|
|
271
244
|
atac: "#02c7b9",
|
|
272
245
|
rnaseq: "#00aa00",
|
|
273
246
|
chromhmm: "#00ff00",
|
|
274
|
-
ccre: "#
|
|
247
|
+
ccre: "#000000",
|
|
275
248
|
};
|
|
276
249
|
|
|
277
|
-
function generateTrack(
|
|
250
|
+
function generateTrack(
|
|
251
|
+
row: BiosampleRowInfo | GeneRowInfo,
|
|
252
|
+
folderId: string,
|
|
253
|
+
assembly: Assembly,
|
|
254
|
+
callbacks?: TrackCallbacks,
|
|
255
|
+
): Track | null {
|
|
256
|
+
// Handle gene folders
|
|
257
|
+
if (folderId.includes("genes")) {
|
|
258
|
+
const geneRow = row as GeneRowInfo;
|
|
259
|
+
const track: Track = {
|
|
260
|
+
...defaultTranscript,
|
|
261
|
+
id: geneRow.id,
|
|
262
|
+
assembly,
|
|
263
|
+
version: geneRow.versions[geneRow.versions.length - 1], // latest version
|
|
264
|
+
};
|
|
265
|
+
return callbacks ? injectCallbacks(track, callbacks) : track;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Handle biosample folders
|
|
269
|
+
const sel = row as BiosampleRowInfo;
|
|
278
270
|
const color = ASSAY_COLORS[sel.assay.toLowerCase()] || "#000000";
|
|
279
271
|
let track: Track;
|
|
280
272
|
|
|
281
273
|
switch (sel.assay.toLowerCase()) {
|
|
282
274
|
case "chromhmm":
|
|
283
|
-
track = {
|
|
284
|
-
...defaultBigBed,
|
|
285
|
-
id: sel.id,
|
|
286
|
-
url: sel.url,
|
|
287
|
-
title: sel.displayname,
|
|
288
|
-
color,
|
|
289
|
-
};
|
|
290
|
-
break;
|
|
291
275
|
case "ccre":
|
|
292
276
|
track = {
|
|
293
277
|
...defaultBigBed,
|
|
294
278
|
id: sel.id,
|
|
295
279
|
url: sel.url,
|
|
296
|
-
title: sel.
|
|
280
|
+
title: sel.displayName,
|
|
297
281
|
color,
|
|
298
282
|
};
|
|
299
283
|
break;
|
|
@@ -302,7 +286,7 @@ function generateTrack(sel: RowInfo, callbacks?: TrackCallbacks): Track {
|
|
|
302
286
|
...defaultBigWig,
|
|
303
287
|
id: sel.id,
|
|
304
288
|
url: sel.url,
|
|
305
|
-
title: sel.
|
|
289
|
+
title: sel.displayName,
|
|
306
290
|
color,
|
|
307
291
|
};
|
|
308
292
|
}
|
|
@@ -341,11 +325,8 @@ export const defaultTranscript: Omit<
|
|
|
341
325
|
export function useLocalTracks(assembly: string, callbacks?: TrackCallbacks) {
|
|
342
326
|
const localTracks = getLocalTracks(assembly);
|
|
343
327
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
// Get base tracks (from storage or defaults)
|
|
348
|
-
let initialTracks = localTracks || defaultTracks;
|
|
328
|
+
// Start empty if no stored tracks - TrackSelect will populate defaults
|
|
329
|
+
let initialTracks: Track[] = localTracks || [];
|
|
349
330
|
|
|
350
331
|
// Inject callbacks if provided (callbacks are lost on JSON serialization)
|
|
351
332
|
if (callbacks) {
|
|
@@ -366,7 +347,7 @@ export function useLocalTracks(assembly: string, callbacks?: TrackCallbacks) {
|
|
|
366
347
|
export function getLocalTracks(assembly: string): Track[] | null {
|
|
367
348
|
if (typeof window === "undefined" || !window.sessionStorage) return null;
|
|
368
349
|
|
|
369
|
-
const localTracks = sessionStorage.getItem(assembly + "-
|
|
350
|
+
const localTracks = sessionStorage.getItem(assembly + "-tracks");
|
|
370
351
|
if (!localTracks) return null;
|
|
371
352
|
const localTracksJson = JSON.parse(localTracks) as Track[];
|
|
372
353
|
return localTracksJson;
|
|
@@ -376,50 +357,13 @@ export function setLocalTracks(tracks: Track[], assembly: string) {
|
|
|
376
357
|
sessionStorage.setItem(assembly + "-tracks", JSON.stringify(tracks));
|
|
377
358
|
}
|
|
378
359
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
color: ASSAY_COLORS.ccre,
|
|
390
|
-
id: "human-ccre-ignore",
|
|
391
|
-
title: "All cCREs colored by group",
|
|
392
|
-
url: "https://downloads.wenglab.org/GRCh38-cCREs.DCC.bigBed",
|
|
393
|
-
},
|
|
394
|
-
{
|
|
395
|
-
...defaultBigWig,
|
|
396
|
-
color: ASSAY_COLORS.dnase,
|
|
397
|
-
id: "human-dnase-aggregate-ignore",
|
|
398
|
-
title: "Aggregated DNase signal, all ENCODE biosamples",
|
|
399
|
-
url: "https://downloads.wenglab.org/DNAse_All_ENCODE_MAR20_2024_merged.bw",
|
|
400
|
-
},
|
|
401
|
-
];
|
|
402
|
-
|
|
403
|
-
const defaultMouseTracks = [
|
|
404
|
-
{
|
|
405
|
-
...defaultTranscript,
|
|
406
|
-
color: ASSAY_COLORS.ccre,
|
|
407
|
-
id: "mouse-genes-ignore",
|
|
408
|
-
assembly: "mm10",
|
|
409
|
-
version: 21,
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
...defaultBigBed,
|
|
413
|
-
color: ASSAY_COLORS.ccre,
|
|
414
|
-
id: "mouse-ccre-ignore",
|
|
415
|
-
title: "All cCREs colored by group",
|
|
416
|
-
url: "https://downloads.wenglab.org/mm10-cCREs.DCC.bigBed",
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
...defaultBigWig,
|
|
420
|
-
color: ASSAY_COLORS.dnase,
|
|
421
|
-
id: "mouse-dnase-aggregate-ignore",
|
|
422
|
-
title: "Aggregated DNase signal, all ENCODE biosamples",
|
|
423
|
-
url: "https://downloads.wenglab.org/DNase_MM10_ENCODE_DEC2024_merged_nanrm.bigWig",
|
|
424
|
-
},
|
|
425
|
-
];
|
|
360
|
+
// Default selections for TrackSelect UI (uses folder row IDs)
|
|
361
|
+
const defaultHumanSelections = new Map<string, Set<string>>([
|
|
362
|
+
["human-genes", new Set(["genocode-basic"])],
|
|
363
|
+
["human-biosamples", new Set(["ccre-aggregate", "dnase-aggregate"])],
|
|
364
|
+
]);
|
|
365
|
+
|
|
366
|
+
const defaultMouseSelections = new Map<string, Set<string>>([
|
|
367
|
+
["mouse-genes", new Set(["genocode-basic"])],
|
|
368
|
+
["mouse-biosamples", new Set(["ccre-aggregate", "dnase-aggregate"])],
|
|
369
|
+
]);
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { GridToolbarProps, ToolbarPropsOverrides } from '@mui/x-data-grid-premium';
|
|
2
|
-
import { DataGridProps } from '../types';
|
|
3
|
-
type CustomToolbarProps = {
|
|
4
|
-
label: DataGridProps["label"];
|
|
5
|
-
downloadFileName: DataGridProps["downloadFileName"];
|
|
6
|
-
labelTooltip: DataGridProps["labelTooltip"];
|
|
7
|
-
toolbarSlot?: DataGridProps["toolbarSlot"];
|
|
8
|
-
toolbarStyle?: DataGridProps["toolbarStyle"];
|
|
9
|
-
toolbarIconColor?: DataGridProps["toolbarIconColor"];
|
|
10
|
-
} & GridToolbarProps & ToolbarPropsOverrides;
|
|
11
|
-
export declare function CustomToolbar({ label, downloadFileName, labelTooltip, toolbarSlot, toolbarStyle, toolbarIconColor, ...restToolbarProps }: CustomToolbarProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
-
export {};
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { FuseResult } from 'fuse.js';
|
|
2
|
-
import { RowInfo, SearchTracksProps, TrackInfo } from '../types';
|
|
3
|
-
import { Assembly } from '../consts';
|
|
4
|
-
export declare function getTracksData(assembly: Assembly): {
|
|
5
|
-
tracks: {
|
|
6
|
-
name: string;
|
|
7
|
-
ontology: string;
|
|
8
|
-
lifeStage: string;
|
|
9
|
-
sampleType: string;
|
|
10
|
-
displayname: string;
|
|
11
|
-
assays: {
|
|
12
|
-
id: string;
|
|
13
|
-
assay: string;
|
|
14
|
-
url: string;
|
|
15
|
-
experimentAccession: string;
|
|
16
|
-
fileAccession: string;
|
|
17
|
-
}[];
|
|
18
|
-
}[];
|
|
19
|
-
};
|
|
20
|
-
export declare function getTracksByAssayAndOntology(assay: string, ontology: string, tracksData: ReturnType<typeof getTracksData>): TrackInfo[];
|
|
21
|
-
/** Flatten TrackInfo into RowInfo objects for DataGrid display.
|
|
22
|
-
* @param track TrackInfo object containing information from JSON file
|
|
23
|
-
* @returns Array of flattened RowInfo objects, one per assay
|
|
24
|
-
*/
|
|
25
|
-
export declare function flattenIntoRows(track: TrackInfo): RowInfo[];
|
|
26
|
-
/**
|
|
27
|
-
* Fuzzy search in tracks stored in a JSON file.
|
|
28
|
-
*
|
|
29
|
-
* @param jsonStructure - Dot-separated path to the data array in the JSON structure.
|
|
30
|
-
* @param query - The search query string.
|
|
31
|
-
* @param keyWeightMap - Array of keys to search within each track object.
|
|
32
|
-
* Can look like ["name", "author"] or if weighted, [
|
|
33
|
-
{
|
|
34
|
-
name: 'title',
|
|
35
|
-
weight: 0.3
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
name: 'author',
|
|
39
|
-
weight: 0.7
|
|
40
|
-
}
|
|
41
|
-
].
|
|
42
|
-
* @param threshold - (Optional) Threshold for the fuzzy search (default is 0.5).
|
|
43
|
-
* Smaller = stricter match, larger = fuzzier since 0 is perfect match and 1 is worst match.
|
|
44
|
-
* @param limit - (Optional) Maximum number of results to return (default is 10).
|
|
45
|
-
* @returns FuseResult object containing the search results.
|
|
46
|
-
*/
|
|
47
|
-
export declare function searchTracks({ jsonStructure, query, keyWeightMap, threshold, tracksData, }: SearchTracksProps & {
|
|
48
|
-
tracksData: ReturnType<typeof getTracksData>;
|
|
49
|
-
}): FuseResult<TrackInfo>[];
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { TreeViewBaseItem } from '@mui/x-tree-view';
|
|
2
|
-
import { default as React } from 'react';
|
|
3
|
-
import { CustomTreeItemProps, ExtendedTreeItemProps, RowInfo, SearchTracksProps } from '../types';
|
|
4
|
-
import { FuseResult } from 'fuse.js';
|
|
5
|
-
/**
|
|
6
|
-
* Builds tree in the sorted by assay view
|
|
7
|
-
* @param selectedIds: list of ids (from useSelectionStore)
|
|
8
|
-
* @param root: Root TreeViewBaseItem
|
|
9
|
-
* @param rowById: Mapping between an id (experimentAccession) and its RowInfo object
|
|
10
|
-
* @returns all of the items for the RichTreeView in TreeViewWrapper
|
|
11
|
-
*/
|
|
12
|
-
export declare function buildSortedAssayTreeView(selectedIds: string[], root: TreeViewBaseItem<ExtendedTreeItemProps>, rowById: Map<string, RowInfo>): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
13
|
-
/**
|
|
14
|
-
* Builds tree in the sorted by assay view
|
|
15
|
-
* @param selectedIds: list of ids (from useSelectionStore)
|
|
16
|
-
* @param root: Root TreeViewBaseItem
|
|
17
|
-
* @param rowById: Mapping between an id (experimentAccession) and its RowInfo object
|
|
18
|
-
* @returns all of the items for the RichTreeView in TreeViewWrapper
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildTreeView(selectedIds: string[], root: TreeViewBaseItem<ExtendedTreeItemProps>, rowById: Map<string, RowInfo>): TreeViewBaseItem<ExtendedTreeItemProps>[];
|
|
21
|
-
/**
|
|
22
|
-
* Fuzzy search of active tracks.
|
|
23
|
-
*
|
|
24
|
-
* @param treeItems - TreeBaseViewItems from the tree.
|
|
25
|
-
* @param query - The search query string.
|
|
26
|
-
* @param keyWeightMap - Array of keys to search within each track object.
|
|
27
|
-
* Can look like ["name", "author"] or if weighted, [
|
|
28
|
-
{
|
|
29
|
-
name: 'title',
|
|
30
|
-
weight: 0.3
|
|
31
|
-
},
|
|
32
|
-
{
|
|
33
|
-
name: 'author',
|
|
34
|
-
weight: 0.7
|
|
35
|
-
}
|
|
36
|
-
].
|
|
37
|
-
* @param threshold - (Optional) Threshold for the fuzzy search (default is 0.5).
|
|
38
|
-
* Smaller = stricter match, larger = fuzzier since 0 is perfect match and 1 is worst match.
|
|
39
|
-
* @param limit - (Optional) Maximum number of results to return (default is 10).
|
|
40
|
-
* @returns FuseResult object containing the search results.
|
|
41
|
-
*/
|
|
42
|
-
export declare function searchTreeItems({ treeItems, query, keyWeightMap, threshold, limit, }: SearchTracksProps): FuseResult<RowInfo>[];
|
|
43
|
-
/**
|
|
44
|
-
* Creates the assay icon for DataGrid and RichTreeView
|
|
45
|
-
* @param type: assay type
|
|
46
|
-
* @returns an icon of the assay's respective color
|
|
47
|
-
*/
|
|
48
|
-
export declare function AssayIcon(type: string): import("react/jsx-runtime").JSX.Element;
|
|
49
|
-
export declare const CustomTreeItem: React.ForwardRefExoticComponent<CustomTreeItemProps & React.RefAttributes<HTMLLIElement>>;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { RowInfo } from './types';
|
|
2
|
-
export type Assembly = "GRCh38" | "mm10";
|
|
3
|
-
export declare const assayTypes: string[];
|
|
4
|
-
export declare const ontologyTypes: string[];
|
|
5
|
-
/**
|
|
6
|
-
* Build rows and rowById for a specific assembly
|
|
7
|
-
*/
|
|
8
|
-
export declare function buildRowsForAssembly(assembly: Assembly): {
|
|
9
|
-
rows: RowInfo[];
|
|
10
|
-
rowById: Map<string, RowInfo>;
|
|
11
|
-
};
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
|
-
import {
|
|
3
|
-
Toolbar,
|
|
4
|
-
ToolbarButton,
|
|
5
|
-
FilterPanelTrigger,
|
|
6
|
-
ExportCsv,
|
|
7
|
-
ExportPrint,
|
|
8
|
-
GridToolbarProps,
|
|
9
|
-
ToolbarPropsOverrides,
|
|
10
|
-
ExportExcel,
|
|
11
|
-
} from "@mui/x-data-grid-premium";
|
|
12
|
-
import Tooltip from "@mui/material/Tooltip";
|
|
13
|
-
import Menu from "@mui/material/Menu";
|
|
14
|
-
import Badge from "@mui/material/Badge";
|
|
15
|
-
import FilterListIcon from "@mui/icons-material/FilterList";
|
|
16
|
-
import FileDownloadIcon from "@mui/icons-material/FileDownload";
|
|
17
|
-
import MenuItem from "@mui/material/MenuItem";
|
|
18
|
-
import Divider from "@mui/material/Divider";
|
|
19
|
-
import Typography from "@mui/material/Typography";
|
|
20
|
-
import { DataGridProps } from "../types";
|
|
21
|
-
import { InfoOutline } from "@mui/icons-material";
|
|
22
|
-
|
|
23
|
-
type CustomToolbarProps = {
|
|
24
|
-
label: DataGridProps["label"];
|
|
25
|
-
downloadFileName: DataGridProps["downloadFileName"];
|
|
26
|
-
labelTooltip: DataGridProps["labelTooltip"];
|
|
27
|
-
toolbarSlot?: DataGridProps["toolbarSlot"];
|
|
28
|
-
toolbarStyle?: DataGridProps["toolbarStyle"];
|
|
29
|
-
toolbarIconColor?: DataGridProps["toolbarIconColor"];
|
|
30
|
-
} & GridToolbarProps &
|
|
31
|
-
ToolbarPropsOverrides;
|
|
32
|
-
|
|
33
|
-
export function CustomToolbar({
|
|
34
|
-
label,
|
|
35
|
-
downloadFileName,
|
|
36
|
-
labelTooltip,
|
|
37
|
-
toolbarSlot,
|
|
38
|
-
toolbarStyle,
|
|
39
|
-
toolbarIconColor,
|
|
40
|
-
...restToolbarProps
|
|
41
|
-
}: CustomToolbarProps) {
|
|
42
|
-
const [exportMenuOpen, setExportMenuOpen] = React.useState(false);
|
|
43
|
-
const exportMenuTriggerRef = React.useRef<HTMLButtonElement>(null);
|
|
44
|
-
|
|
45
|
-
const iconColor = toolbarIconColor ?? "inherit";
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<Toolbar style={{ ...toolbarStyle }}>
|
|
49
|
-
{typeof label !== "string" && label}
|
|
50
|
-
<Typography
|
|
51
|
-
fontWeight="medium"
|
|
52
|
-
sx={{ flex: 1, mx: 0.5, display: "flex", alignItems: "center", gap: 1 }}
|
|
53
|
-
>
|
|
54
|
-
{typeof label === "string" && label}
|
|
55
|
-
{/* ReactNode can be more than just an element, string, or number but not accounting for that for simplicity */}
|
|
56
|
-
{labelTooltip &&
|
|
57
|
-
(typeof labelTooltip === "string" ||
|
|
58
|
-
typeof labelTooltip === "number") ? (
|
|
59
|
-
<Tooltip title={labelTooltip}>
|
|
60
|
-
<InfoOutline fontSize="inherit" color="primary" />
|
|
61
|
-
</Tooltip>
|
|
62
|
-
) : (
|
|
63
|
-
labelTooltip
|
|
64
|
-
)}
|
|
65
|
-
</Typography>
|
|
66
|
-
{toolbarSlot && (
|
|
67
|
-
<>
|
|
68
|
-
{toolbarSlot}
|
|
69
|
-
<Divider
|
|
70
|
-
orientation="vertical"
|
|
71
|
-
variant="middle"
|
|
72
|
-
flexItem
|
|
73
|
-
sx={{ mx: 0.5 }}
|
|
74
|
-
/>
|
|
75
|
-
</>
|
|
76
|
-
)}
|
|
77
|
-
|
|
78
|
-
<Tooltip title="Filters">
|
|
79
|
-
<FilterPanelTrigger
|
|
80
|
-
render={(props, state) => (
|
|
81
|
-
<ToolbarButton {...props} color="default">
|
|
82
|
-
<Badge
|
|
83
|
-
badgeContent={state.filterCount}
|
|
84
|
-
color="primary"
|
|
85
|
-
variant="dot"
|
|
86
|
-
>
|
|
87
|
-
<FilterListIcon fontSize="small" htmlColor={iconColor} />
|
|
88
|
-
</Badge>
|
|
89
|
-
</ToolbarButton>
|
|
90
|
-
)}
|
|
91
|
-
/>
|
|
92
|
-
</Tooltip>
|
|
93
|
-
<Divider
|
|
94
|
-
orientation="vertical"
|
|
95
|
-
variant="middle"
|
|
96
|
-
flexItem
|
|
97
|
-
sx={{ mx: 0.5 }}
|
|
98
|
-
/>
|
|
99
|
-
<Tooltip title="Export">
|
|
100
|
-
<ToolbarButton
|
|
101
|
-
ref={exportMenuTriggerRef}
|
|
102
|
-
id="export-menu-trigger"
|
|
103
|
-
aria-controls="export-menu"
|
|
104
|
-
aria-haspopup="true"
|
|
105
|
-
aria-expanded={exportMenuOpen ? "true" : undefined}
|
|
106
|
-
onClick={() => setExportMenuOpen(true)}
|
|
107
|
-
>
|
|
108
|
-
<FileDownloadIcon fontSize="small" htmlColor={iconColor} />
|
|
109
|
-
</ToolbarButton>
|
|
110
|
-
</Tooltip>
|
|
111
|
-
|
|
112
|
-
<Menu
|
|
113
|
-
id="export-menu"
|
|
114
|
-
anchorEl={exportMenuTriggerRef.current}
|
|
115
|
-
open={exportMenuOpen}
|
|
116
|
-
onClose={() => setExportMenuOpen(false)}
|
|
117
|
-
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
|
|
118
|
-
transformOrigin={{ vertical: "top", horizontal: "right" }}
|
|
119
|
-
slotProps={{
|
|
120
|
-
list: {
|
|
121
|
-
"aria-labelledby": "export-menu-trigger",
|
|
122
|
-
},
|
|
123
|
-
}}
|
|
124
|
-
>
|
|
125
|
-
<ExportPrint
|
|
126
|
-
options={{ ...restToolbarProps.printOptions }}
|
|
127
|
-
render={<MenuItem />}
|
|
128
|
-
onClick={() => setExportMenuOpen(false)}
|
|
129
|
-
>
|
|
130
|
-
Print
|
|
131
|
-
</ExportPrint>
|
|
132
|
-
<ExportCsv
|
|
133
|
-
options={{
|
|
134
|
-
fileName: typeof label === "string" ? label : downloadFileName,
|
|
135
|
-
...restToolbarProps.csvOptions,
|
|
136
|
-
}}
|
|
137
|
-
render={<MenuItem />}
|
|
138
|
-
onClick={() => setExportMenuOpen(false)}
|
|
139
|
-
>
|
|
140
|
-
Download as CSV
|
|
141
|
-
</ExportCsv>
|
|
142
|
-
<ExportExcel
|
|
143
|
-
options={{ ...restToolbarProps.excelOptions }}
|
|
144
|
-
render={<MenuItem />}
|
|
145
|
-
onClick={() => setExportMenuOpen(false)}
|
|
146
|
-
>
|
|
147
|
-
Download as Excel
|
|
148
|
-
</ExportExcel>
|
|
149
|
-
</Menu>
|
|
150
|
-
</Toolbar>
|
|
151
|
-
);
|
|
152
|
-
}
|