@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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createBiosampleFolder } from "./shared/createFolder";
|
|
2
|
+
import humanData from "./data/human.json";
|
|
3
|
+
import { BiosampleDataFile } from "./shared/types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Human biosamples folder configuration for GRCh38 assembly.
|
|
7
|
+
*
|
|
8
|
+
* Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
|
|
9
|
+
* from human tissue samples, primary cells, cell lines, and organoids.
|
|
10
|
+
*/
|
|
11
|
+
export const humanBiosamplesFolder = createBiosampleFolder({
|
|
12
|
+
id: "human-biosamples",
|
|
13
|
+
label: "Human Biosamples",
|
|
14
|
+
description:
|
|
15
|
+
"Epigenomic data from human tissue samples, primary cells, cell lines, and organoids.",
|
|
16
|
+
data: humanData as BiosampleDataFile,
|
|
17
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createBiosampleFolder } from "./shared/createFolder";
|
|
2
|
+
import mouseData from "./data/mouse.json";
|
|
3
|
+
import { BiosampleDataFile } from "./shared/types";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Mouse biosamples folder configuration for mm10 assembly.
|
|
7
|
+
*
|
|
8
|
+
* Contains epigenomic data (DNase, ATAC, H3K4me3, H3K27ac, CTCF, cCRE, RNA-seq, ChromHMM)
|
|
9
|
+
* from mouse tissue samples, primary cells, cell lines, and organoids.
|
|
10
|
+
*/
|
|
11
|
+
export const mouseBiosamplesFolder = createBiosampleFolder({
|
|
12
|
+
id: "mouse-biosamples",
|
|
13
|
+
label: "Mouse Biosamples",
|
|
14
|
+
description:
|
|
15
|
+
"Epigenomic data from mouse tissue samples, primary cells, cell lines, and organoids.",
|
|
16
|
+
data: mouseData as BiosampleDataFile,
|
|
17
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { FormControlLabel, Switch } from "@mui/material";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { FolderRuntimeConfig } from "../../types";
|
|
4
|
+
import {
|
|
5
|
+
defaultColumns,
|
|
6
|
+
defaultGroupingModel,
|
|
7
|
+
defaultLeafField,
|
|
8
|
+
sortedByAssayColumns,
|
|
9
|
+
sortedByAssayGroupingModel,
|
|
10
|
+
sortedByAssayLeafField,
|
|
11
|
+
} from "./columns";
|
|
12
|
+
|
|
13
|
+
export interface AssayToggleProps {
|
|
14
|
+
updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Biosample-specific toolbar component that toggles between
|
|
19
|
+
* sample-grouped and assay-grouped views.
|
|
20
|
+
*
|
|
21
|
+
* When toggled, it updates the folder's runtime config to switch:
|
|
22
|
+
* - columns: Different column definitions for each view
|
|
23
|
+
* - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology", "displayName"]
|
|
24
|
+
* - leafField: "assay" vs "id"
|
|
25
|
+
*/
|
|
26
|
+
export function AssayToggle({ updateConfig }: AssayToggleProps) {
|
|
27
|
+
const [sortedByAssay, setSortedByAssay] = useState(false);
|
|
28
|
+
|
|
29
|
+
const handleToggle = () => {
|
|
30
|
+
const newValue = !sortedByAssay;
|
|
31
|
+
setSortedByAssay(newValue);
|
|
32
|
+
|
|
33
|
+
if (newValue) {
|
|
34
|
+
// Switch to assay-grouped view
|
|
35
|
+
updateConfig({
|
|
36
|
+
columns: sortedByAssayColumns,
|
|
37
|
+
groupingModel: sortedByAssayGroupingModel,
|
|
38
|
+
leafField: sortedByAssayLeafField,
|
|
39
|
+
});
|
|
40
|
+
} else {
|
|
41
|
+
// Switch back to default (sample-grouped) view
|
|
42
|
+
updateConfig({
|
|
43
|
+
columns: defaultColumns,
|
|
44
|
+
groupingModel: defaultGroupingModel,
|
|
45
|
+
leafField: defaultLeafField,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<FormControlLabel
|
|
52
|
+
sx={{ display: "flex", justifyContent: "flex-end" }}
|
|
53
|
+
value="Sort by assay"
|
|
54
|
+
control={
|
|
55
|
+
<Switch
|
|
56
|
+
color="primary"
|
|
57
|
+
checked={sortedByAssay}
|
|
58
|
+
onChange={handleToggle}
|
|
59
|
+
/>
|
|
60
|
+
}
|
|
61
|
+
label="Sort by assay"
|
|
62
|
+
labelPlacement="end"
|
|
63
|
+
/>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -4,13 +4,15 @@ import {
|
|
|
4
4
|
useGridApiContext,
|
|
5
5
|
GridGroupNode,
|
|
6
6
|
} from "@mui/x-data-grid-premium";
|
|
7
|
-
import { assayTypes } from "
|
|
8
|
-
import { AssayIcon } from "../TreeView/treeViewHelpers";
|
|
7
|
+
import { assayTypes, AssayIcon } from "./constants";
|
|
9
8
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
|
10
9
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Biosample-specific grouping cell that renders AssayIcon for assay groups/values.
|
|
13
|
+
* Handles expand/collapse, truncation, and tooltips.
|
|
14
|
+
*/
|
|
15
|
+
export default function BiosampleGroupingCell(params: GridRenderCellParams) {
|
|
14
16
|
const apiRef = useGridApiContext();
|
|
15
17
|
const isGroup = params.rowNode.type === "group";
|
|
16
18
|
const groupNode = params.rowNode as GridGroupNode;
|
|
@@ -53,7 +55,7 @@ export default function GroupingCell(params: GridRenderCellParams) {
|
|
|
53
55
|
);
|
|
54
56
|
}
|
|
55
57
|
|
|
56
|
-
// For other groups (ontology,
|
|
58
|
+
// For other groups (ontology, displayName), show bold text
|
|
57
59
|
if (isGroup) {
|
|
58
60
|
return (
|
|
59
61
|
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { CustomTreeItem } from "../../../TreeView/CustomTreeItem";
|
|
3
|
+
import { CustomTreeItemProps } from "../../../types";
|
|
4
|
+
import { AssayIcon } from "./constants";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Biosample-specific TreeItem that renders AssayIcon for assay items.
|
|
8
|
+
* Wraps the generic CustomTreeItem with the AssayIcon renderer.
|
|
9
|
+
*/
|
|
10
|
+
export const BiosampleTreeItem = React.forwardRef<
|
|
11
|
+
HTMLLIElement,
|
|
12
|
+
CustomTreeItemProps
|
|
13
|
+
>(function BiosampleTreeItem(props, ref) {
|
|
14
|
+
return <CustomTreeItem {...props} ref={ref} renderIcon={AssayIcon} />;
|
|
15
|
+
});
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import { GridColDef } from "@mui/x-data-grid-premium";
|
|
2
|
-
import { RowInfo } from "../types";
|
|
3
2
|
import { Stack, capitalize } from "@mui/material";
|
|
4
|
-
import { AssayIcon } from "
|
|
5
|
-
import {
|
|
3
|
+
import { AssayIcon, ontologyTypes, assayTypes } from "./constants";
|
|
4
|
+
import { BiosampleRowInfo } from "./types";
|
|
6
5
|
|
|
7
|
-
const displayNameCol: GridColDef<
|
|
8
|
-
field: "
|
|
6
|
+
const displayNameCol: GridColDef<BiosampleRowInfo> = {
|
|
7
|
+
field: "displayName",
|
|
9
8
|
headerName: "Name",
|
|
10
9
|
valueFormatter: (value) => value && capitalize(value),
|
|
11
10
|
maxWidth: 300,
|
|
12
11
|
};
|
|
13
12
|
|
|
14
|
-
const sortedByAssayOntologyCol: GridColDef<
|
|
13
|
+
const sortedByAssayOntologyCol: GridColDef<BiosampleRowInfo> = {
|
|
15
14
|
field: "ontology",
|
|
16
15
|
headerName: "Ontology",
|
|
17
16
|
type: "singleSelect",
|
|
@@ -31,7 +30,7 @@ const sortedByAssayOntologyCol: GridColDef<RowInfo> = {
|
|
|
31
30
|
},
|
|
32
31
|
};
|
|
33
32
|
|
|
34
|
-
const sortedByAssayAssayCol: GridColDef<
|
|
33
|
+
const sortedByAssayAssayCol: GridColDef<BiosampleRowInfo> = {
|
|
35
34
|
field: "assay",
|
|
36
35
|
headerName: "Assay",
|
|
37
36
|
valueOptions: assayTypes,
|
|
@@ -53,7 +52,7 @@ const sortedByAssayAssayCol: GridColDef<RowInfo> = {
|
|
|
53
52
|
},
|
|
54
53
|
};
|
|
55
54
|
|
|
56
|
-
const defaultOntologyCol: GridColDef<
|
|
55
|
+
const defaultOntologyCol: GridColDef<BiosampleRowInfo> = {
|
|
57
56
|
field: "ontology",
|
|
58
57
|
headerName: "Ontology",
|
|
59
58
|
type: "singleSelect",
|
|
@@ -73,7 +72,7 @@ const defaultOntologyCol: GridColDef<RowInfo> = {
|
|
|
73
72
|
},
|
|
74
73
|
};
|
|
75
74
|
|
|
76
|
-
const defaultAssayCol: GridColDef<
|
|
75
|
+
const defaultAssayCol: GridColDef<BiosampleRowInfo> = {
|
|
77
76
|
field: "assay",
|
|
78
77
|
headerName: "Assay",
|
|
79
78
|
valueOptions: assayTypes,
|
|
@@ -91,11 +90,12 @@ const defaultAssayCol: GridColDef<RowInfo> = {
|
|
|
91
90
|
},
|
|
92
91
|
};
|
|
93
92
|
|
|
94
|
-
const sampleTypeCol: GridColDef<
|
|
93
|
+
const sampleTypeCol: GridColDef<BiosampleRowInfo> = {
|
|
95
94
|
field: "sampleType",
|
|
96
95
|
headerName: "Sample Type",
|
|
97
96
|
type: "singleSelect",
|
|
98
97
|
valueOptions: [
|
|
98
|
+
"aggregate",
|
|
99
99
|
"tissue",
|
|
100
100
|
"primary cell",
|
|
101
101
|
"cell line",
|
|
@@ -105,30 +105,31 @@ const sampleTypeCol: GridColDef<RowInfo> = {
|
|
|
105
105
|
valueFormatter: (value) => value && capitalize(value),
|
|
106
106
|
};
|
|
107
107
|
|
|
108
|
-
const lifeStageCol: GridColDef<
|
|
108
|
+
const lifeStageCol: GridColDef<BiosampleRowInfo> = {
|
|
109
109
|
field: "lifeStage",
|
|
110
110
|
headerName: "Life Stage",
|
|
111
111
|
type: "singleSelect",
|
|
112
|
-
valueOptions: ["adult", "embryonic"],
|
|
112
|
+
valueOptions: ["adult", "embryonic", "N/A"],
|
|
113
113
|
valueFormatter: (value) => value && capitalize(value),
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
const experimentCol: GridColDef<
|
|
116
|
+
const experimentCol: GridColDef<BiosampleRowInfo> = {
|
|
117
117
|
field: "experimentAccession",
|
|
118
118
|
headerName: "Experiment Accession",
|
|
119
119
|
};
|
|
120
120
|
|
|
121
|
-
const fileCol: GridColDef<
|
|
121
|
+
const fileCol: GridColDef<BiosampleRowInfo> = {
|
|
122
122
|
field: "fileAccession",
|
|
123
123
|
headerName: "File Accession",
|
|
124
124
|
};
|
|
125
125
|
|
|
126
|
-
const idCol: GridColDef<
|
|
126
|
+
const idCol: GridColDef<BiosampleRowInfo> = {
|
|
127
127
|
field: "id",
|
|
128
128
|
headerName: "ID",
|
|
129
129
|
};
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
/** Columns for sorted-by-assay view (assay as top-level grouping) */
|
|
132
|
+
export const sortedByAssayColumns: GridColDef<BiosampleRowInfo>[] = [
|
|
132
133
|
displayNameCol,
|
|
133
134
|
sortedByAssayOntologyCol,
|
|
134
135
|
sampleTypeCol,
|
|
@@ -139,7 +140,8 @@ export const sortedByAssayColumns: GridColDef<RowInfo>[] = [
|
|
|
139
140
|
idCol,
|
|
140
141
|
];
|
|
141
142
|
|
|
142
|
-
|
|
143
|
+
/** Default columns (ontology as top-level grouping) */
|
|
144
|
+
export const defaultColumns: GridColDef<BiosampleRowInfo>[] = [
|
|
143
145
|
defaultAssayCol,
|
|
144
146
|
sampleTypeCol,
|
|
145
147
|
lifeStageCol,
|
|
@@ -149,3 +151,15 @@ export const defaultColumns: GridColDef<RowInfo>[] = [
|
|
|
149
151
|
fileCol,
|
|
150
152
|
idCol,
|
|
151
153
|
];
|
|
154
|
+
|
|
155
|
+
/** Grouping model for sorted-by-assay view */
|
|
156
|
+
export const sortedByAssayGroupingModel = ["assay", "ontology", "displayName"];
|
|
157
|
+
|
|
158
|
+
/** Default grouping model (ontology-based) */
|
|
159
|
+
export const defaultGroupingModel = ["ontology", "displayName"];
|
|
160
|
+
|
|
161
|
+
/** Leaf field for sorted-by-assay view */
|
|
162
|
+
export const sortedByAssayLeafField = "id";
|
|
163
|
+
|
|
164
|
+
/** Default leaf field */
|
|
165
|
+
export const defaultLeafField = "assay";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Box } from "@mui/material";
|
|
2
|
+
import type { Assembly } from "../../types";
|
|
3
|
+
|
|
4
|
+
export type { Assembly };
|
|
5
|
+
|
|
6
|
+
export const assayTypes = [
|
|
7
|
+
"cCRE",
|
|
8
|
+
"DNase",
|
|
9
|
+
"H3K4me3",
|
|
10
|
+
"H3K27ac",
|
|
11
|
+
"ATAC",
|
|
12
|
+
"CTCF",
|
|
13
|
+
"RNA-seq",
|
|
14
|
+
"ChromHMM",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
export const ontologyTypes = [
|
|
18
|
+
"Aggregate",
|
|
19
|
+
"Adipose",
|
|
20
|
+
"Adrenal gland",
|
|
21
|
+
"Blood",
|
|
22
|
+
"Blood vessel",
|
|
23
|
+
"Bone",
|
|
24
|
+
"Bone marrow",
|
|
25
|
+
"Brain",
|
|
26
|
+
"Breast",
|
|
27
|
+
"Connective tissue",
|
|
28
|
+
"Embryo",
|
|
29
|
+
"Epithelium",
|
|
30
|
+
"Esophagus",
|
|
31
|
+
"Eye",
|
|
32
|
+
"Fallopian Tube",
|
|
33
|
+
"Gallbladder",
|
|
34
|
+
"Heart",
|
|
35
|
+
"Kidney",
|
|
36
|
+
"Large Intestine",
|
|
37
|
+
"Limb",
|
|
38
|
+
"Liver",
|
|
39
|
+
"Lung",
|
|
40
|
+
"Lymphoid Tissue",
|
|
41
|
+
"Muscle",
|
|
42
|
+
"Mouth",
|
|
43
|
+
"Nerve",
|
|
44
|
+
"Nose",
|
|
45
|
+
"Pancreas",
|
|
46
|
+
"Parathyroid Gland",
|
|
47
|
+
"Ovary",
|
|
48
|
+
"Penis",
|
|
49
|
+
"Placenta",
|
|
50
|
+
"Prostate",
|
|
51
|
+
"Skin",
|
|
52
|
+
"Small Intestine",
|
|
53
|
+
"Spinal Cord",
|
|
54
|
+
"Spleen",
|
|
55
|
+
"Stomach",
|
|
56
|
+
"Testis",
|
|
57
|
+
"Thymus",
|
|
58
|
+
"Thyroid",
|
|
59
|
+
"Urinary Bladder",
|
|
60
|
+
"Uterus",
|
|
61
|
+
"Vagina",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/** Color mapping for assay types */
|
|
65
|
+
export const assayColorMap: { [key: string]: string } = {
|
|
66
|
+
DNase: "#06da93",
|
|
67
|
+
ATAC: "#02c7b9",
|
|
68
|
+
H3K4me3: "#ff2020",
|
|
69
|
+
ChromHMM: "#0097a7",
|
|
70
|
+
H3K27ac: "#fdc401",
|
|
71
|
+
CTCF: "#01a6f1",
|
|
72
|
+
cCRE: "#000000",
|
|
73
|
+
"RNA-seq": "#00aa00",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Creates the assay icon for DataGrid and RichTreeView
|
|
78
|
+
* @param type - assay type
|
|
79
|
+
* @returns an icon of the assay's respective color
|
|
80
|
+
*/
|
|
81
|
+
export function AssayIcon(type: string) {
|
|
82
|
+
const color = assayColorMap[type];
|
|
83
|
+
return (
|
|
84
|
+
<Box
|
|
85
|
+
sx={{
|
|
86
|
+
width: 12,
|
|
87
|
+
height: 12,
|
|
88
|
+
borderRadius: "20%",
|
|
89
|
+
bgcolor: color,
|
|
90
|
+
}}
|
|
91
|
+
/>
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Mapping from JSON assay keys to display names.
|
|
97
|
+
* This is the single source of truth for assay name formatting.
|
|
98
|
+
*/
|
|
99
|
+
const assayJsonToDisplay: Record<string, string> = {
|
|
100
|
+
dnase: "DNase",
|
|
101
|
+
atac: "ATAC",
|
|
102
|
+
h3k4me3: "H3K4me3",
|
|
103
|
+
h3k27ac: "H3K27ac",
|
|
104
|
+
ctcf: "CTCF",
|
|
105
|
+
chromhmm: "ChromHMM",
|
|
106
|
+
ccre: "cCRE",
|
|
107
|
+
rnaseq: "RNA-seq",
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Convert JSON assay key to display name.
|
|
112
|
+
* Used only during data loading to normalize assay names.
|
|
113
|
+
*/
|
|
114
|
+
export function formatAssayType(jsonKey: string): string {
|
|
115
|
+
return assayJsonToDisplay[jsonKey.toLowerCase()] ?? jsonKey;
|
|
116
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { capitalize } from "@mui/material";
|
|
2
|
+
import { FolderDefinition } from "../../types";
|
|
3
|
+
import {
|
|
4
|
+
BiosampleDataFile,
|
|
5
|
+
BiosampleRowInfo,
|
|
6
|
+
BiosampleTrackInfo,
|
|
7
|
+
} from "./types";
|
|
8
|
+
import {
|
|
9
|
+
defaultColumns,
|
|
10
|
+
defaultGroupingModel,
|
|
11
|
+
defaultLeafField,
|
|
12
|
+
} from "./columns";
|
|
13
|
+
import { buildTreeView } from "./treeBuilder";
|
|
14
|
+
import { formatAssayType } from "./constants";
|
|
15
|
+
import { AssayToggle } from "./AssayToggle";
|
|
16
|
+
import BiosampleGroupingCell from "./BiosampleGroupingCell";
|
|
17
|
+
import { BiosampleTreeItem } from "./BiosampleTreeItem";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Flattens TrackInfo into RowInfo objects for DataGrid display.
|
|
21
|
+
* Each track can have multiple assays, so this creates one row per assay.
|
|
22
|
+
*
|
|
23
|
+
* @param track - TrackInfo object from JSON data
|
|
24
|
+
* @returns Array of flattened BiosampleRowInfo objects, one per assay
|
|
25
|
+
*/
|
|
26
|
+
function flattenTrackIntoRows(track: BiosampleTrackInfo): BiosampleRowInfo[] {
|
|
27
|
+
const { ontology, lifeStage, sampleType, displayName } = track;
|
|
28
|
+
|
|
29
|
+
return track.assays.map(
|
|
30
|
+
({ id, assay, experimentAccession, fileAccession, url }) => ({
|
|
31
|
+
id,
|
|
32
|
+
ontology: capitalize(ontology),
|
|
33
|
+
lifeStage: capitalize(lifeStage),
|
|
34
|
+
sampleType: capitalize(sampleType),
|
|
35
|
+
displayName: capitalize(displayName),
|
|
36
|
+
assay: formatAssayType(assay),
|
|
37
|
+
experimentAccession,
|
|
38
|
+
fileAccession,
|
|
39
|
+
url,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Transforms raw JSON data into flattened rows and a lookup map.
|
|
46
|
+
* Prefixes each row ID with the folder ID to ensure uniqueness across folders.
|
|
47
|
+
*
|
|
48
|
+
* @param data - Raw biosample data from JSON file
|
|
49
|
+
* @param folderId - Folder ID to prefix row IDs with
|
|
50
|
+
* @returns Object containing rows array and rowById map
|
|
51
|
+
*/
|
|
52
|
+
function transformData(data: BiosampleDataFile): {
|
|
53
|
+
rowById: Map<string, BiosampleRowInfo>;
|
|
54
|
+
} {
|
|
55
|
+
const rows = data.tracks.flatMap(flattenTrackIntoRows).map((row) => ({
|
|
56
|
+
...row,
|
|
57
|
+
id: row.id,
|
|
58
|
+
}));
|
|
59
|
+
const rowById = new Map<string, BiosampleRowInfo>(
|
|
60
|
+
rows.map((row) => [row.id, row]),
|
|
61
|
+
);
|
|
62
|
+
return { rowById };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface CreateBiosampleFolderOptions {
|
|
66
|
+
/** Unique identifier for this folder */
|
|
67
|
+
id: string;
|
|
68
|
+
/** Display label shown in the UI */
|
|
69
|
+
label: string;
|
|
70
|
+
/** Optional description shown in folder cards */
|
|
71
|
+
description?: string;
|
|
72
|
+
/** Raw biosample data from JSON file */
|
|
73
|
+
data: BiosampleDataFile;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Factory function that creates a FolderDefinition for biosample data.
|
|
78
|
+
*
|
|
79
|
+
* This handles all the common setup for biosample folders:
|
|
80
|
+
* - Transforms JSON data into flattened rows
|
|
81
|
+
* - Creates the rowById lookup map
|
|
82
|
+
* - Configures columns, grouping, and tree building
|
|
83
|
+
*
|
|
84
|
+
* @param options - Configuration options for the folder
|
|
85
|
+
* @returns A complete FolderDefinition for the biosample data
|
|
86
|
+
*/
|
|
87
|
+
export function createBiosampleFolder(
|
|
88
|
+
options: CreateBiosampleFolderOptions,
|
|
89
|
+
): FolderDefinition<BiosampleRowInfo> {
|
|
90
|
+
const { id, label, description, data } = options;
|
|
91
|
+
const { rowById } = transformData(data);
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
id,
|
|
95
|
+
label,
|
|
96
|
+
description,
|
|
97
|
+
rowById,
|
|
98
|
+
getRowId: (row) => row.id,
|
|
99
|
+
|
|
100
|
+
// Default view: ontology-based grouping
|
|
101
|
+
columns: defaultColumns,
|
|
102
|
+
groupingModel: defaultGroupingModel,
|
|
103
|
+
leafField: defaultLeafField,
|
|
104
|
+
|
|
105
|
+
// Build tree for selected items panel
|
|
106
|
+
buildTree: (selectedIds, rowById) =>
|
|
107
|
+
buildTreeView(selectedIds, rowById, label, id),
|
|
108
|
+
|
|
109
|
+
// Biosample-specific toolbar: toggle between sample-grouped and assay-grouped views
|
|
110
|
+
ToolbarExtras: AssayToggle,
|
|
111
|
+
|
|
112
|
+
// Biosample-specific custom components
|
|
113
|
+
GroupingCellComponent: BiosampleGroupingCell,
|
|
114
|
+
TreeItemComponent: BiosampleTreeItem,
|
|
115
|
+
};
|
|
116
|
+
}
|