@weng-lab/genomebrowser-ui 0.2.2 → 0.2.3
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/data/human.json.d.ts +57141 -57141
- package/dist/TrackSelect/Folders/biosamples/data/mouse.json.d.ts +10394 -10394
- package/dist/TrackSelect/Folders/genes/data/human.json.d.ts +7 -7
- package/dist/TrackSelect/Folders/genes/data/mouse.json.d.ts +7 -7
- package/dist/genomebrowser-ui.es.js +9 -5
- package/dist/genomebrowser-ui.es.js.map +1 -1
- package/eslint.config.js +30 -30
- package/index.html +14 -14
- package/package.json +1 -1
- package/src/TrackSelect/DataGrid/DataGridWrapper.tsx +137 -137
- package/src/TrackSelect/DataGrid/DefaultGroupingCell.tsx +64 -64
- package/src/TrackSelect/Dialogs/ClearDialog.tsx +63 -63
- package/src/TrackSelect/Dialogs/LimitDialog.tsx +33 -33
- package/src/TrackSelect/Dialogs/ResetDialog.tsx +43 -43
- package/src/TrackSelect/FolderList/Breadcrumb.tsx +38 -38
- package/src/TrackSelect/FolderList/FolderCard.tsx +51 -51
- package/src/TrackSelect/FolderList/FolderList.tsx +47 -47
- package/src/TrackSelect/Folders/NEW.md +929 -929
- package/src/TrackSelect/Folders/biosamples/data/formatBiosamples.go +254 -254
- package/src/TrackSelect/Folders/biosamples/data/human.json +57141 -57141
- package/src/TrackSelect/Folders/biosamples/data/mouse.json +10394 -10394
- package/src/TrackSelect/Folders/biosamples/human.ts +17 -17
- package/src/TrackSelect/Folders/biosamples/mouse.ts +17 -17
- package/src/TrackSelect/Folders/biosamples/shared/AssayToggle.tsx +78 -78
- package/src/TrackSelect/Folders/biosamples/shared/BiosampleGroupingCell.tsx +146 -146
- package/src/TrackSelect/Folders/biosamples/shared/BiosampleTreeItem.tsx +15 -15
- package/src/TrackSelect/Folders/biosamples/shared/columns.tsx +165 -165
- package/src/TrackSelect/Folders/biosamples/shared/constants.tsx +116 -116
- package/src/TrackSelect/Folders/biosamples/shared/createFolder.ts +116 -116
- package/src/TrackSelect/Folders/biosamples/shared/treeBuilder.ts +224 -224
- package/src/TrackSelect/Folders/biosamples/shared/types.ts +48 -48
- package/src/TrackSelect/Folders/genes/data/human.json +7 -7
- package/src/TrackSelect/Folders/genes/data/mouse.json +7 -7
- package/src/TrackSelect/Folders/genes/human.ts +16 -16
- package/src/TrackSelect/Folders/genes/mouse.ts +16 -16
- package/src/TrackSelect/Folders/genes/shared/columns.tsx +42 -42
- package/src/TrackSelect/Folders/genes/shared/createFolder.ts +68 -68
- package/src/TrackSelect/Folders/genes/shared/treeBuilder.ts +45 -45
- package/src/TrackSelect/Folders/genes/shared/types.ts +29 -29
- package/src/TrackSelect/Folders/index.ts +30 -30
- package/src/TrackSelect/Folders/types.ts +106 -106
- package/src/TrackSelect/TrackSelect.tsx +11 -7
- package/src/TrackSelect/TreeView/CustomTreeItem.tsx +214 -214
- package/src/TrackSelect/TreeView/TreeViewWrapper.tsx +145 -145
- package/src/TrackSelect/store.ts +117 -117
- package/src/TrackSelect/types.ts +121 -121
- package/src/lib.ts +13 -13
- package/src/vite-env.d.ts +1 -1
- package/test/main.tsx +369 -369
- package/tsconfig.app.json +25 -25
- package/tsconfig.json +7 -7
- package/tsconfig.node.json +25 -25
- package/vite.config.ts +66 -66
|
@@ -1,17 +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
|
-
});
|
|
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
|
+
});
|
|
@@ -1,17 +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
|
-
});
|
|
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
|
+
});
|
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
import { FormControlLabel, Switch } from "@mui/material";
|
|
2
|
-
import { FolderRuntimeConfig } from "../../types";
|
|
3
|
-
import {
|
|
4
|
-
defaultColumns,
|
|
5
|
-
defaultGroupingModel,
|
|
6
|
-
defaultLeafField,
|
|
7
|
-
sortedByAssayColumns,
|
|
8
|
-
sortedByAssayGroupingModel,
|
|
9
|
-
sortedByAssayLeafField,
|
|
10
|
-
} from "./columns";
|
|
11
|
-
import { buildTreeView, buildSortedAssayTreeView } from "./treeBuilder";
|
|
12
|
-
|
|
13
|
-
export interface AssayToggleProps {
|
|
14
|
-
updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
|
|
15
|
-
folderId: string;
|
|
16
|
-
label: string;
|
|
17
|
-
config: FolderRuntimeConfig;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Biosample-specific toolbar component that toggles between
|
|
22
|
-
* sample-grouped and assay-grouped views.
|
|
23
|
-
*
|
|
24
|
-
* When toggled, it updates the folder's runtime config to switch:
|
|
25
|
-
* - columns: Different column definitions for each view
|
|
26
|
-
* - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology"]
|
|
27
|
-
* - leafField: "assay" vs "displayName"
|
|
28
|
-
* - buildTree: Different tree builder function
|
|
29
|
-
*/
|
|
30
|
-
export function AssayToggle({
|
|
31
|
-
updateConfig,
|
|
32
|
-
folderId,
|
|
33
|
-
label,
|
|
34
|
-
config,
|
|
35
|
-
}: AssayToggleProps) {
|
|
36
|
-
// Derive toggle state from current config's leafField
|
|
37
|
-
const sortedByAssay = config.leafField === sortedByAssayLeafField;
|
|
38
|
-
|
|
39
|
-
const handleToggle = () => {
|
|
40
|
-
const newValue = !sortedByAssay;
|
|
41
|
-
|
|
42
|
-
if (newValue) {
|
|
43
|
-
// Switch to assay-grouped view
|
|
44
|
-
updateConfig({
|
|
45
|
-
columns: sortedByAssayColumns,
|
|
46
|
-
groupingModel: sortedByAssayGroupingModel,
|
|
47
|
-
leafField: sortedByAssayLeafField,
|
|
48
|
-
buildTree: (selectedIds, rowById) =>
|
|
49
|
-
buildSortedAssayTreeView(selectedIds, rowById, label, folderId),
|
|
50
|
-
});
|
|
51
|
-
} else {
|
|
52
|
-
// Switch back to default (sample-grouped) view
|
|
53
|
-
updateConfig({
|
|
54
|
-
columns: defaultColumns,
|
|
55
|
-
groupingModel: defaultGroupingModel,
|
|
56
|
-
leafField: defaultLeafField,
|
|
57
|
-
buildTree: (selectedIds, rowById) =>
|
|
58
|
-
buildTreeView(selectedIds, rowById, label, folderId),
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<FormControlLabel
|
|
65
|
-
sx={{ display: "flex", justifyContent: "flex-end" }}
|
|
66
|
-
value="Sort by assay"
|
|
67
|
-
control={
|
|
68
|
-
<Switch
|
|
69
|
-
color="primary"
|
|
70
|
-
checked={sortedByAssay}
|
|
71
|
-
onChange={handleToggle}
|
|
72
|
-
/>
|
|
73
|
-
}
|
|
74
|
-
label="Sort by assay"
|
|
75
|
-
labelPlacement="end"
|
|
76
|
-
/>
|
|
77
|
-
);
|
|
78
|
-
}
|
|
1
|
+
import { FormControlLabel, Switch } from "@mui/material";
|
|
2
|
+
import { FolderRuntimeConfig } from "../../types";
|
|
3
|
+
import {
|
|
4
|
+
defaultColumns,
|
|
5
|
+
defaultGroupingModel,
|
|
6
|
+
defaultLeafField,
|
|
7
|
+
sortedByAssayColumns,
|
|
8
|
+
sortedByAssayGroupingModel,
|
|
9
|
+
sortedByAssayLeafField,
|
|
10
|
+
} from "./columns";
|
|
11
|
+
import { buildTreeView, buildSortedAssayTreeView } from "./treeBuilder";
|
|
12
|
+
|
|
13
|
+
export interface AssayToggleProps {
|
|
14
|
+
updateConfig: (partial: Partial<FolderRuntimeConfig>) => void;
|
|
15
|
+
folderId: string;
|
|
16
|
+
label: string;
|
|
17
|
+
config: FolderRuntimeConfig;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Biosample-specific toolbar component that toggles between
|
|
22
|
+
* sample-grouped and assay-grouped views.
|
|
23
|
+
*
|
|
24
|
+
* When toggled, it updates the folder's runtime config to switch:
|
|
25
|
+
* - columns: Different column definitions for each view
|
|
26
|
+
* - groupingModel: ["ontology", "displayName"] vs ["assay", "ontology"]
|
|
27
|
+
* - leafField: "assay" vs "displayName"
|
|
28
|
+
* - buildTree: Different tree builder function
|
|
29
|
+
*/
|
|
30
|
+
export function AssayToggle({
|
|
31
|
+
updateConfig,
|
|
32
|
+
folderId,
|
|
33
|
+
label,
|
|
34
|
+
config,
|
|
35
|
+
}: AssayToggleProps) {
|
|
36
|
+
// Derive toggle state from current config's leafField
|
|
37
|
+
const sortedByAssay = config.leafField === sortedByAssayLeafField;
|
|
38
|
+
|
|
39
|
+
const handleToggle = () => {
|
|
40
|
+
const newValue = !sortedByAssay;
|
|
41
|
+
|
|
42
|
+
if (newValue) {
|
|
43
|
+
// Switch to assay-grouped view
|
|
44
|
+
updateConfig({
|
|
45
|
+
columns: sortedByAssayColumns,
|
|
46
|
+
groupingModel: sortedByAssayGroupingModel,
|
|
47
|
+
leafField: sortedByAssayLeafField,
|
|
48
|
+
buildTree: (selectedIds, rowById) =>
|
|
49
|
+
buildSortedAssayTreeView(selectedIds, rowById, label, folderId),
|
|
50
|
+
});
|
|
51
|
+
} else {
|
|
52
|
+
// Switch back to default (sample-grouped) view
|
|
53
|
+
updateConfig({
|
|
54
|
+
columns: defaultColumns,
|
|
55
|
+
groupingModel: defaultGroupingModel,
|
|
56
|
+
leafField: defaultLeafField,
|
|
57
|
+
buildTree: (selectedIds, rowById) =>
|
|
58
|
+
buildTreeView(selectedIds, rowById, label, folderId),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<FormControlLabel
|
|
65
|
+
sx={{ display: "flex", justifyContent: "flex-end" }}
|
|
66
|
+
value="Sort by assay"
|
|
67
|
+
control={
|
|
68
|
+
<Switch
|
|
69
|
+
color="primary"
|
|
70
|
+
checked={sortedByAssay}
|
|
71
|
+
onChange={handleToggle}
|
|
72
|
+
/>
|
|
73
|
+
}
|
|
74
|
+
label="Sort by assay"
|
|
75
|
+
labelPlacement="end"
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -1,146 +1,146 @@
|
|
|
1
|
-
import { Stack, Tooltip, Box, IconButton } from "@mui/material";
|
|
2
|
-
import {
|
|
3
|
-
GridRenderCellParams,
|
|
4
|
-
useGridApiContext,
|
|
5
|
-
GridGroupNode,
|
|
6
|
-
} from "@mui/x-data-grid-premium";
|
|
7
|
-
import { assayTypes, AssayIcon } from "./constants";
|
|
8
|
-
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
|
9
|
-
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
10
|
-
|
|
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) {
|
|
16
|
-
const apiRef = useGridApiContext();
|
|
17
|
-
const isGroup = params.rowNode.type === "group";
|
|
18
|
-
const groupNode = params.rowNode as GridGroupNode;
|
|
19
|
-
const isExpanded = isGroup ? groupNode.childrenExpanded : false;
|
|
20
|
-
const groupingField = isGroup ? groupNode.groupingField : null;
|
|
21
|
-
const depth = params.rowNode.depth ?? 0;
|
|
22
|
-
|
|
23
|
-
const handleExpandClick = (e: React.MouseEvent) => {
|
|
24
|
-
e.stopPropagation();
|
|
25
|
-
apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Render content based on grouping field
|
|
29
|
-
const renderContent = () => {
|
|
30
|
-
const value = String(params.value ?? "");
|
|
31
|
-
|
|
32
|
-
// For assay groups, show the colored icon
|
|
33
|
-
if (isGroup && groupingField === "assay") {
|
|
34
|
-
return (
|
|
35
|
-
<Stack
|
|
36
|
-
direction="row"
|
|
37
|
-
spacing={1}
|
|
38
|
-
alignItems="center"
|
|
39
|
-
sx={{ flex: 1, overflow: "hidden" }}
|
|
40
|
-
>
|
|
41
|
-
{AssayIcon(value)}
|
|
42
|
-
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
43
|
-
<Box
|
|
44
|
-
sx={{
|
|
45
|
-
overflow: "hidden",
|
|
46
|
-
textOverflow: "ellipsis",
|
|
47
|
-
whiteSpace: "nowrap",
|
|
48
|
-
fontWeight: "bold",
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
{params.formattedValue}
|
|
52
|
-
</Box>
|
|
53
|
-
</Tooltip>
|
|
54
|
-
</Stack>
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// For other groups (ontology, displayName), show bold text
|
|
59
|
-
if (isGroup) {
|
|
60
|
-
return (
|
|
61
|
-
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
62
|
-
<Box
|
|
63
|
-
sx={{
|
|
64
|
-
overflow: "hidden",
|
|
65
|
-
textOverflow: "ellipsis",
|
|
66
|
-
whiteSpace: "nowrap",
|
|
67
|
-
flex: 1,
|
|
68
|
-
fontWeight: "bold",
|
|
69
|
-
}}
|
|
70
|
-
>
|
|
71
|
-
{params.formattedValue}
|
|
72
|
-
</Box>
|
|
73
|
-
</Tooltip>
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// For leaf rows - check if it's an assay value
|
|
78
|
-
const isAssayValue = assayTypes
|
|
79
|
-
.map((a) => a.toLowerCase())
|
|
80
|
-
.includes(value.toLowerCase());
|
|
81
|
-
|
|
82
|
-
if (isAssayValue) {
|
|
83
|
-
return (
|
|
84
|
-
<Stack
|
|
85
|
-
direction="row"
|
|
86
|
-
spacing={1}
|
|
87
|
-
alignItems="center"
|
|
88
|
-
sx={{ flex: 1, overflow: "hidden" }}
|
|
89
|
-
>
|
|
90
|
-
{AssayIcon(value)}
|
|
91
|
-
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
92
|
-
<Box
|
|
93
|
-
sx={{
|
|
94
|
-
overflow: "hidden",
|
|
95
|
-
textOverflow: "ellipsis",
|
|
96
|
-
whiteSpace: "nowrap",
|
|
97
|
-
}}
|
|
98
|
-
>
|
|
99
|
-
{params.formattedValue}
|
|
100
|
-
</Box>
|
|
101
|
-
</Tooltip>
|
|
102
|
-
</Stack>
|
|
103
|
-
);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
108
|
-
<Box
|
|
109
|
-
sx={{
|
|
110
|
-
overflow: "hidden",
|
|
111
|
-
textOverflow: "ellipsis",
|
|
112
|
-
whiteSpace: "nowrap",
|
|
113
|
-
flex: 1,
|
|
114
|
-
}}
|
|
115
|
-
>
|
|
116
|
-
{params.formattedValue}
|
|
117
|
-
</Box>
|
|
118
|
-
</Tooltip>
|
|
119
|
-
);
|
|
120
|
-
};
|
|
121
|
-
|
|
122
|
-
// Indent based on depth (2 units per level)
|
|
123
|
-
const indentLevel = depth * 2;
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<Box
|
|
127
|
-
sx={{
|
|
128
|
-
display: "flex",
|
|
129
|
-
alignItems: "center",
|
|
130
|
-
width: "100%",
|
|
131
|
-
ml: indentLevel,
|
|
132
|
-
}}
|
|
133
|
-
>
|
|
134
|
-
{isGroup && (
|
|
135
|
-
<IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
|
|
136
|
-
{isExpanded ? (
|
|
137
|
-
<ExpandMoreIcon fontSize="small" />
|
|
138
|
-
) : (
|
|
139
|
-
<ChevronRightIcon fontSize="small" />
|
|
140
|
-
)}
|
|
141
|
-
</IconButton>
|
|
142
|
-
)}
|
|
143
|
-
{renderContent()}
|
|
144
|
-
</Box>
|
|
145
|
-
);
|
|
146
|
-
}
|
|
1
|
+
import { Stack, Tooltip, Box, IconButton } from "@mui/material";
|
|
2
|
+
import {
|
|
3
|
+
GridRenderCellParams,
|
|
4
|
+
useGridApiContext,
|
|
5
|
+
GridGroupNode,
|
|
6
|
+
} from "@mui/x-data-grid-premium";
|
|
7
|
+
import { assayTypes, AssayIcon } from "./constants";
|
|
8
|
+
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
|
9
|
+
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
10
|
+
|
|
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) {
|
|
16
|
+
const apiRef = useGridApiContext();
|
|
17
|
+
const isGroup = params.rowNode.type === "group";
|
|
18
|
+
const groupNode = params.rowNode as GridGroupNode;
|
|
19
|
+
const isExpanded = isGroup ? groupNode.childrenExpanded : false;
|
|
20
|
+
const groupingField = isGroup ? groupNode.groupingField : null;
|
|
21
|
+
const depth = params.rowNode.depth ?? 0;
|
|
22
|
+
|
|
23
|
+
const handleExpandClick = (e: React.MouseEvent) => {
|
|
24
|
+
e.stopPropagation();
|
|
25
|
+
apiRef.current.setRowChildrenExpansion(params.id, !isExpanded);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Render content based on grouping field
|
|
29
|
+
const renderContent = () => {
|
|
30
|
+
const value = String(params.value ?? "");
|
|
31
|
+
|
|
32
|
+
// For assay groups, show the colored icon
|
|
33
|
+
if (isGroup && groupingField === "assay") {
|
|
34
|
+
return (
|
|
35
|
+
<Stack
|
|
36
|
+
direction="row"
|
|
37
|
+
spacing={1}
|
|
38
|
+
alignItems="center"
|
|
39
|
+
sx={{ flex: 1, overflow: "hidden" }}
|
|
40
|
+
>
|
|
41
|
+
{AssayIcon(value)}
|
|
42
|
+
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
43
|
+
<Box
|
|
44
|
+
sx={{
|
|
45
|
+
overflow: "hidden",
|
|
46
|
+
textOverflow: "ellipsis",
|
|
47
|
+
whiteSpace: "nowrap",
|
|
48
|
+
fontWeight: "bold",
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{params.formattedValue}
|
|
52
|
+
</Box>
|
|
53
|
+
</Tooltip>
|
|
54
|
+
</Stack>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// For other groups (ontology, displayName), show bold text
|
|
59
|
+
if (isGroup) {
|
|
60
|
+
return (
|
|
61
|
+
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
62
|
+
<Box
|
|
63
|
+
sx={{
|
|
64
|
+
overflow: "hidden",
|
|
65
|
+
textOverflow: "ellipsis",
|
|
66
|
+
whiteSpace: "nowrap",
|
|
67
|
+
flex: 1,
|
|
68
|
+
fontWeight: "bold",
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
{params.formattedValue}
|
|
72
|
+
</Box>
|
|
73
|
+
</Tooltip>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// For leaf rows - check if it's an assay value
|
|
78
|
+
const isAssayValue = assayTypes
|
|
79
|
+
.map((a) => a.toLowerCase())
|
|
80
|
+
.includes(value.toLowerCase());
|
|
81
|
+
|
|
82
|
+
if (isAssayValue) {
|
|
83
|
+
return (
|
|
84
|
+
<Stack
|
|
85
|
+
direction="row"
|
|
86
|
+
spacing={1}
|
|
87
|
+
alignItems="center"
|
|
88
|
+
sx={{ flex: 1, overflow: "hidden" }}
|
|
89
|
+
>
|
|
90
|
+
{AssayIcon(value)}
|
|
91
|
+
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
92
|
+
<Box
|
|
93
|
+
sx={{
|
|
94
|
+
overflow: "hidden",
|
|
95
|
+
textOverflow: "ellipsis",
|
|
96
|
+
whiteSpace: "nowrap",
|
|
97
|
+
}}
|
|
98
|
+
>
|
|
99
|
+
{params.formattedValue}
|
|
100
|
+
</Box>
|
|
101
|
+
</Tooltip>
|
|
102
|
+
</Stack>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<Tooltip title={value} placement="top-start" enterDelay={500}>
|
|
108
|
+
<Box
|
|
109
|
+
sx={{
|
|
110
|
+
overflow: "hidden",
|
|
111
|
+
textOverflow: "ellipsis",
|
|
112
|
+
whiteSpace: "nowrap",
|
|
113
|
+
flex: 1,
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
{params.formattedValue}
|
|
117
|
+
</Box>
|
|
118
|
+
</Tooltip>
|
|
119
|
+
);
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
// Indent based on depth (2 units per level)
|
|
123
|
+
const indentLevel = depth * 2;
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<Box
|
|
127
|
+
sx={{
|
|
128
|
+
display: "flex",
|
|
129
|
+
alignItems: "center",
|
|
130
|
+
width: "100%",
|
|
131
|
+
ml: indentLevel,
|
|
132
|
+
}}
|
|
133
|
+
>
|
|
134
|
+
{isGroup && (
|
|
135
|
+
<IconButton size="small" onClick={handleExpandClick} sx={{ mr: 0.5 }}>
|
|
136
|
+
{isExpanded ? (
|
|
137
|
+
<ExpandMoreIcon fontSize="small" />
|
|
138
|
+
) : (
|
|
139
|
+
<ChevronRightIcon fontSize="small" />
|
|
140
|
+
)}
|
|
141
|
+
</IconButton>
|
|
142
|
+
)}
|
|
143
|
+
{renderContent()}
|
|
144
|
+
</Box>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
@@ -1,15 +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
|
+
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
|
+
});
|