@jbrowse/plugin-data-management 2.0.0 → 2.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AddConnectionWidget/components/AddConnectionWidget.js +23 -40
- package/dist/AddConnectionWidget/components/AddConnectionWidget.js.map +1 -1
- package/dist/AddConnectionWidget/components/ConfigureConnection.js +6 -6
- package/dist/AddConnectionWidget/components/ConfigureConnection.js.map +1 -1
- package/dist/AddConnectionWidget/components/ConnectionTypeSelect.js +7 -9
- package/dist/AddConnectionWidget/components/ConnectionTypeSelect.js.map +1 -1
- package/dist/AddConnectionWidget/index.js +1 -1
- package/dist/AddConnectionWidget/index.js.map +1 -1
- package/dist/AddConnectionWidget/model.js +2 -2
- package/dist/AddConnectionWidget/model.js.map +1 -1
- package/dist/AddTrackWidget/components/AddTrackWidget.d.ts +2 -2
- package/dist/AddTrackWidget/components/AddTrackWidget.js +24 -220
- package/dist/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
- package/dist/AddTrackWidget/components/ConfirmTrack.js +72 -99
- package/dist/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
- package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.d.ts +7 -0
- package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js +162 -0
- package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -0
- package/dist/AddTrackWidget/components/TrackSourceSelect.js +11 -12
- package/dist/AddTrackWidget/components/TrackSourceSelect.js.map +1 -1
- package/dist/AddTrackWidget/index.js +1 -1
- package/dist/AddTrackWidget/index.js.map +1 -1
- package/dist/AddTrackWidget/model.js +34 -30
- package/dist/AddTrackWidget/model.js.map +1 -1
- package/dist/AssemblyManager/AssemblyAddForm.js +42 -61
- package/dist/AssemblyManager/AssemblyAddForm.js.map +1 -1
- package/dist/AssemblyManager/AssemblyEditor.js +4 -5
- package/dist/AssemblyManager/AssemblyEditor.js.map +1 -1
- package/dist/AssemblyManager/AssemblyManager.js +24 -41
- package/dist/AssemblyManager/AssemblyManager.js.map +1 -1
- package/dist/AssemblyManager/AssemblyTable.js +17 -18
- package/dist/AssemblyManager/AssemblyTable.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/CloseConnectionDialog.js +9 -29
- package/dist/HierarchicalTrackSelectorWidget/components/CloseConnectionDialog.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/DeleteConnectionDialog.js +7 -8
- package/dist/HierarchicalTrackSelectorWidget/components/DeleteConnectionDialog.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/Header.d.ts +10 -0
- package/dist/HierarchicalTrackSelectorWidget/components/Header.js +177 -0
- package/dist/HierarchicalTrackSelectorWidget/components/Header.js.map +1 -0
- package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +79 -365
- package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js +17 -18
- package/dist/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/Node.d.ts +29 -0
- package/dist/HierarchicalTrackSelectorWidget/components/Node.js +173 -0
- package/dist/HierarchicalTrackSelectorWidget/components/Node.js.map +1 -0
- package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +19 -20
- package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/util.d.ts +3 -0
- package/dist/HierarchicalTrackSelectorWidget/components/util.js +9 -0
- package/dist/HierarchicalTrackSelectorWidget/components/util.js.map +1 -0
- package/dist/HierarchicalTrackSelectorWidget/configSchema.d.ts +2 -0
- package/dist/HierarchicalTrackSelectorWidget/configSchema.js +6 -0
- package/dist/HierarchicalTrackSelectorWidget/configSchema.js.map +1 -0
- package/dist/HierarchicalTrackSelectorWidget/index.d.ts +4 -2
- package/dist/HierarchicalTrackSelectorWidget/index.js +4 -4
- package/dist/HierarchicalTrackSelectorWidget/index.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/model.d.ts +10 -2
- package/dist/HierarchicalTrackSelectorWidget/model.js +102 -153
- package/dist/HierarchicalTrackSelectorWidget/model.js.map +1 -1
- package/dist/PluginStoreWidget/components/CustomPluginForm.js +25 -43
- package/dist/PluginStoreWidget/components/CustomPluginForm.js.map +1 -1
- package/dist/PluginStoreWidget/components/InstalledPlugin.js +29 -47
- package/dist/PluginStoreWidget/components/InstalledPlugin.js.map +1 -1
- package/dist/PluginStoreWidget/components/InstalledPluginsList.js +12 -15
- package/dist/PluginStoreWidget/components/InstalledPluginsList.js.map +1 -1
- package/dist/PluginStoreWidget/components/PluginCard.js +23 -40
- package/dist/PluginStoreWidget/components/PluginCard.js.map +1 -1
- package/dist/PluginStoreWidget/components/PluginStoreWidget.js +49 -117
- package/dist/PluginStoreWidget/components/PluginStoreWidget.js.map +1 -1
- package/dist/PluginStoreWidget/index.js +1 -1
- package/dist/PluginStoreWidget/index.js.map +1 -1
- package/dist/PluginStoreWidget/model.js +6 -6
- package/dist/PluginStoreWidget/model.js.map +1 -1
- package/dist/SetDefaultSession/SetDefaultSession.js +9 -10
- package/dist/SetDefaultSession/SetDefaultSession.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +38 -60
- package/dist/index.js.map +1 -1
- package/dist/ucsc-trackhub/configSchema.js +2 -2
- package/dist/ucsc-trackhub/configSchema.js.map +1 -1
- package/dist/ucsc-trackhub/model.js +33 -97
- package/dist/ucsc-trackhub/model.js.map +1 -1
- package/dist/ucsc-trackhub/ucscAssemblies.js +197 -1
- package/dist/ucsc-trackhub/ucscAssemblies.js.map +1 -1
- package/dist/ucsc-trackhub/ucscTrackHub.js +43 -132
- package/dist/ucsc-trackhub/ucscTrackHub.js.map +1 -1
- package/esm/AddTrackWidget/components/AddTrackWidget.d.ts +2 -2
- package/esm/AddTrackWidget/components/AddTrackWidget.js +22 -135
- package/esm/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
- package/esm/AddTrackWidget/components/ConfirmTrack.js +5 -6
- package/esm/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
- package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.d.ts +7 -0
- package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js +134 -0
- package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/components/Header.d.ts +10 -0
- package/esm/HierarchicalTrackSelectorWidget/components/Header.js +149 -0
- package/esm/HierarchicalTrackSelectorWidget/components/Header.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +24 -223
- package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
- package/esm/HierarchicalTrackSelectorWidget/components/Node.d.ts +29 -0
- package/esm/HierarchicalTrackSelectorWidget/components/Node.js +144 -0
- package/esm/HierarchicalTrackSelectorWidget/components/Node.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/components/util.d.ts +3 -0
- package/esm/HierarchicalTrackSelectorWidget/components/util.js +5 -0
- package/esm/HierarchicalTrackSelectorWidget/components/util.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/configSchema.d.ts +2 -0
- package/esm/HierarchicalTrackSelectorWidget/configSchema.js +4 -0
- package/esm/HierarchicalTrackSelectorWidget/configSchema.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/index.d.ts +4 -2
- package/esm/HierarchicalTrackSelectorWidget/index.js +3 -3
- package/esm/HierarchicalTrackSelectorWidget/index.js.map +1 -1
- package/esm/HierarchicalTrackSelectorWidget/model.d.ts +10 -2
- package/esm/HierarchicalTrackSelectorWidget/model.js +36 -32
- package/esm/HierarchicalTrackSelectorWidget/model.js.map +1 -1
- package/esm/PluginStoreWidget/components/PluginStoreWidget.js +1 -2
- package/esm/PluginStoreWidget/components/PluginStoreWidget.js.map +1 -1
- package/esm/index.d.ts +4 -1
- package/esm/index.js +1 -1
- package/esm/index.js.map +1 -1
- package/package.json +4 -5
- package/src/AddConnectionWidget/components/__snapshots__/AddConnectionWidget.test.js.snap +7 -7
- package/src/AddTrackWidget/components/{AddTrackWidget.test.js → AddTrackWidget.test.tsx} +17 -32
- package/src/AddTrackWidget/components/AddTrackWidget.tsx +36 -200
- package/src/AddTrackWidget/components/ConfirmTrack.tsx +10 -10
- package/src/AddTrackWidget/components/DefaultAddTrackWorkflow.tsx +205 -0
- package/src/HierarchicalTrackSelectorWidget/components/Header.tsx +287 -0
- package/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.test.js +5 -4
- package/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.tsx +19 -438
- package/src/HierarchicalTrackSelectorWidget/components/Node.tsx +282 -0
- package/src/HierarchicalTrackSelectorWidget/components/__snapshots__/HierarchicalTrackSelector.test.js.snap +24 -48
- package/src/HierarchicalTrackSelectorWidget/components/util.ts +11 -0
- package/src/HierarchicalTrackSelectorWidget/configSchema.ts +3 -0
- package/src/HierarchicalTrackSelectorWidget/index.ts +4 -6
- package/src/HierarchicalTrackSelectorWidget/model.ts +45 -41
- package/src/PluginStoreWidget/components/PluginStoreWidget.test.js +16 -4
- package/src/PluginStoreWidget/components/PluginStoreWidget.tsx +1 -2
- package/src/PluginStoreWidget/components/__snapshots__/PluginStoreWidget.test.js.snap +111 -123
- package/src/index.ts +4 -1
- package/src/AddTrackWidget/components/__snapshots__/AddTrackWidget.test.js.snap +0 -331
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import React, { useState } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Checkbox,
|
|
4
|
+
FormControlLabel,
|
|
5
|
+
IconButton,
|
|
6
|
+
Tooltip,
|
|
7
|
+
Typography,
|
|
8
|
+
} from '@mui/material'
|
|
9
|
+
import { makeStyles } from 'tss-react/mui'
|
|
10
|
+
|
|
11
|
+
// icons
|
|
12
|
+
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown'
|
|
13
|
+
import ArrowRightIcon from '@mui/icons-material/ArrowRight'
|
|
14
|
+
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'
|
|
15
|
+
|
|
16
|
+
// other
|
|
17
|
+
import { HierarchicalTrackSelectorModel, TreeNode } from '../model'
|
|
18
|
+
import JBrowseMenu from '@jbrowse/core/ui/Menu'
|
|
19
|
+
import { getSession } from '@jbrowse/core/util'
|
|
20
|
+
|
|
21
|
+
import {
|
|
22
|
+
AnyConfigurationModel,
|
|
23
|
+
readConfObject,
|
|
24
|
+
} from '@jbrowse/core/configuration'
|
|
25
|
+
import { getAllChildren } from './util'
|
|
26
|
+
|
|
27
|
+
const useStyles = makeStyles()(theme => ({
|
|
28
|
+
compactCheckbox: {
|
|
29
|
+
padding: 0,
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
checkboxLabel: {
|
|
33
|
+
marginRight: 0,
|
|
34
|
+
'&:hover': {
|
|
35
|
+
backgroundColor: '#eee',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
contrastColor: {
|
|
40
|
+
color: theme.palette.secondary.contrastText,
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
// this accordionBase element's small padding is used to give a margin to
|
|
44
|
+
// accordionColor it a "margin" because the virtualized elements can't really
|
|
45
|
+
// use margin in a conventional way (it doesn't affect layout)
|
|
46
|
+
accordionBase: {
|
|
47
|
+
display: 'flex',
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
accordionCard: {
|
|
51
|
+
padding: 3,
|
|
52
|
+
cursor: 'pointer',
|
|
53
|
+
display: 'flex',
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
nestingLevelMarker: {
|
|
57
|
+
position: 'absolute',
|
|
58
|
+
borderLeft: '1.5px solid #555',
|
|
59
|
+
},
|
|
60
|
+
// accordionColor set's display:flex so that the child accordionText use
|
|
61
|
+
// vertically centered text
|
|
62
|
+
accordionColor: {
|
|
63
|
+
background: theme.palette.tertiary.main,
|
|
64
|
+
color: theme.palette.tertiary.contrastText,
|
|
65
|
+
width: '100%',
|
|
66
|
+
display: 'flex',
|
|
67
|
+
paddingLeft: 5,
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// margin:auto 0 to center text vertically
|
|
71
|
+
accordionText: {
|
|
72
|
+
margin: 'auto 0',
|
|
73
|
+
},
|
|
74
|
+
}))
|
|
75
|
+
|
|
76
|
+
export interface InfoArgs {
|
|
77
|
+
target: HTMLElement
|
|
78
|
+
id: string
|
|
79
|
+
conf: AnyConfigurationModel
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function treeToMap(tree: TreeNode, map = new Map<string, TreeNode>()) {
|
|
83
|
+
if (tree.id && tree.children.length) {
|
|
84
|
+
map.set(tree.id, tree)
|
|
85
|
+
}
|
|
86
|
+
for (let i = 0; i < tree.children.length; i++) {
|
|
87
|
+
const node = tree.children[i]
|
|
88
|
+
treeToMap(node, map)
|
|
89
|
+
}
|
|
90
|
+
return map
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function isUnsupported(name = '') {
|
|
94
|
+
return name.endsWith('(Unsupported)') || name.endsWith('(Unknown)')
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// An individual node in the track selector. Note: manually sets cursor:
|
|
98
|
+
// pointer improves usability for what can be clicked
|
|
99
|
+
export default function Node(props: {
|
|
100
|
+
data: {
|
|
101
|
+
nestingLevel: number
|
|
102
|
+
checked: boolean
|
|
103
|
+
conf: AnyConfigurationModel
|
|
104
|
+
drawerPosition: unknown
|
|
105
|
+
id: string
|
|
106
|
+
isLeaf: boolean
|
|
107
|
+
name: string
|
|
108
|
+
onChange: Function
|
|
109
|
+
toggleCollapse: (arg: string) => void
|
|
110
|
+
tree: TreeNode
|
|
111
|
+
selected: boolean
|
|
112
|
+
model: HierarchicalTrackSelectorModel
|
|
113
|
+
}
|
|
114
|
+
isOpen: boolean
|
|
115
|
+
style?: { height: number }
|
|
116
|
+
setOpen: (arg: boolean) => void
|
|
117
|
+
}) {
|
|
118
|
+
const { data, isOpen, style, setOpen } = props
|
|
119
|
+
const {
|
|
120
|
+
checked,
|
|
121
|
+
conf,
|
|
122
|
+
drawerPosition,
|
|
123
|
+
id,
|
|
124
|
+
isLeaf,
|
|
125
|
+
model,
|
|
126
|
+
name,
|
|
127
|
+
nestingLevel,
|
|
128
|
+
onChange,
|
|
129
|
+
selected,
|
|
130
|
+
toggleCollapse,
|
|
131
|
+
tree,
|
|
132
|
+
} = data
|
|
133
|
+
|
|
134
|
+
const { classes } = useStyles()
|
|
135
|
+
const width = 10
|
|
136
|
+
const [menuEl, setMenuEl] = useState<HTMLElement | null>(null)
|
|
137
|
+
const [info, setInfo] = useState<InfoArgs>()
|
|
138
|
+
const marginLeft = nestingLevel * width + (isLeaf ? width : 0)
|
|
139
|
+
const description = (conf && readConfObject(conf, ['description'])) || ''
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<div style={style} className={!isLeaf ? classes.accordionBase : undefined}>
|
|
143
|
+
{new Array(nestingLevel).fill(0).map((_, idx) => (
|
|
144
|
+
<div
|
|
145
|
+
key={`mark-${idx}`}
|
|
146
|
+
style={{ left: idx * width + 4, height: style?.height }}
|
|
147
|
+
className={classes.nestingLevelMarker}
|
|
148
|
+
/>
|
|
149
|
+
))}
|
|
150
|
+
<div
|
|
151
|
+
className={!isLeaf ? classes.accordionCard : undefined}
|
|
152
|
+
onClick={() => {
|
|
153
|
+
if (!menuEl) {
|
|
154
|
+
toggleCollapse(id)
|
|
155
|
+
setOpen(!isOpen)
|
|
156
|
+
}
|
|
157
|
+
}}
|
|
158
|
+
style={{
|
|
159
|
+
marginLeft,
|
|
160
|
+
whiteSpace: 'nowrap',
|
|
161
|
+
width: '100%',
|
|
162
|
+
}}
|
|
163
|
+
>
|
|
164
|
+
<div className={!isLeaf ? classes.accordionColor : undefined}>
|
|
165
|
+
{!isLeaf ? (
|
|
166
|
+
<div className={classes.accordionText}>
|
|
167
|
+
<Typography>
|
|
168
|
+
{isOpen ? <ArrowDropDownIcon /> : <ArrowRightIcon />}
|
|
169
|
+
{name}
|
|
170
|
+
<IconButton
|
|
171
|
+
onClick={event => {
|
|
172
|
+
setMenuEl(event.currentTarget)
|
|
173
|
+
event.stopPropagation()
|
|
174
|
+
}}
|
|
175
|
+
className={classes.contrastColor}
|
|
176
|
+
>
|
|
177
|
+
<MoreHorizIcon />
|
|
178
|
+
</IconButton>
|
|
179
|
+
</Typography>
|
|
180
|
+
</div>
|
|
181
|
+
) : (
|
|
182
|
+
<>
|
|
183
|
+
<Tooltip
|
|
184
|
+
title={description + (selected ? ' (in selection)' : '')}
|
|
185
|
+
placement={drawerPosition === 'left' ? 'right' : 'left'}
|
|
186
|
+
>
|
|
187
|
+
<FormControlLabel
|
|
188
|
+
className={classes.checkboxLabel}
|
|
189
|
+
control={
|
|
190
|
+
<Checkbox
|
|
191
|
+
className={classes.compactCheckbox}
|
|
192
|
+
checked={checked}
|
|
193
|
+
onChange={() => onChange(id)}
|
|
194
|
+
disabled={isUnsupported(name)}
|
|
195
|
+
inputProps={{
|
|
196
|
+
// @ts-ignore
|
|
197
|
+
'data-testid': `htsTrackEntry-${id}`,
|
|
198
|
+
}}
|
|
199
|
+
/>
|
|
200
|
+
}
|
|
201
|
+
label={
|
|
202
|
+
<div
|
|
203
|
+
style={{
|
|
204
|
+
background: selected ? '#cccc' : undefined,
|
|
205
|
+
padding: 1,
|
|
206
|
+
}}
|
|
207
|
+
>
|
|
208
|
+
{name}
|
|
209
|
+
</div>
|
|
210
|
+
}
|
|
211
|
+
/>
|
|
212
|
+
</Tooltip>
|
|
213
|
+
<IconButton
|
|
214
|
+
onClick={e => setInfo({ target: e.currentTarget, id, conf })}
|
|
215
|
+
style={{ padding: 0 }}
|
|
216
|
+
color="secondary"
|
|
217
|
+
data-testid={`htsTrackEntryMenu-${id}`}
|
|
218
|
+
>
|
|
219
|
+
<MoreHorizIcon />
|
|
220
|
+
</IconButton>
|
|
221
|
+
</>
|
|
222
|
+
)}
|
|
223
|
+
{menuEl ? (
|
|
224
|
+
<JBrowseMenu
|
|
225
|
+
anchorEl={menuEl}
|
|
226
|
+
menuItems={[
|
|
227
|
+
{
|
|
228
|
+
label: 'Add to selection',
|
|
229
|
+
onClick: () =>
|
|
230
|
+
model.addToSelection(
|
|
231
|
+
getAllChildren(treeToMap(tree).get(id)),
|
|
232
|
+
),
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
label: 'Remove from selection',
|
|
236
|
+
onClick: () =>
|
|
237
|
+
model.removeFromSelection(
|
|
238
|
+
getAllChildren(treeToMap(tree).get(id)),
|
|
239
|
+
),
|
|
240
|
+
},
|
|
241
|
+
]}
|
|
242
|
+
onMenuItemClick={(_event, callback) => {
|
|
243
|
+
callback()
|
|
244
|
+
setMenuEl(null)
|
|
245
|
+
}}
|
|
246
|
+
open={Boolean(menuEl)}
|
|
247
|
+
onClose={() => setMenuEl(null)}
|
|
248
|
+
/>
|
|
249
|
+
) : null}
|
|
250
|
+
|
|
251
|
+
{info ? (
|
|
252
|
+
<JBrowseMenu
|
|
253
|
+
anchorEl={info?.target}
|
|
254
|
+
menuItems={[
|
|
255
|
+
...(getSession(model).getTrackActionMenuItems?.(info.conf) ||
|
|
256
|
+
[]),
|
|
257
|
+
{
|
|
258
|
+
label: 'Add to selection',
|
|
259
|
+
onClick: () => model.addToSelection([info.conf]),
|
|
260
|
+
},
|
|
261
|
+
...(selected
|
|
262
|
+
? [
|
|
263
|
+
{
|
|
264
|
+
label: 'Remove from selection',
|
|
265
|
+
onClick: () => model.removeFromSelection([info.conf]),
|
|
266
|
+
},
|
|
267
|
+
]
|
|
268
|
+
: []),
|
|
269
|
+
]}
|
|
270
|
+
onMenuItemClick={(_event, callback) => {
|
|
271
|
+
callback()
|
|
272
|
+
setInfo(undefined)
|
|
273
|
+
}}
|
|
274
|
+
open={Boolean(info)}
|
|
275
|
+
onClose={() => setInfo(undefined)}
|
|
276
|
+
/>
|
|
277
|
+
) : null}
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
)
|
|
282
|
+
}
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
exports[`HierarchicalTrackSelector widget renders nothing with no assembly 1`] = `
|
|
4
4
|
<button
|
|
5
|
-
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-
|
|
5
|
+
class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-secondary tss-805w6w-fab css-10w0o2e-MuiButtonBase-root-MuiFab-root"
|
|
6
6
|
tabindex="0"
|
|
7
7
|
type="button"
|
|
8
8
|
>
|
|
9
9
|
<svg
|
|
10
10
|
aria-hidden="true"
|
|
11
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
11
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
12
12
|
data-testid="AddIcon"
|
|
13
13
|
focusable="false"
|
|
14
14
|
viewBox="0 0 24 24"
|
|
@@ -31,13 +31,13 @@ exports[`HierarchicalTrackSelector widget renders with a couple of categorized t
|
|
|
31
31
|
style="display: flex;"
|
|
32
32
|
>
|
|
33
33
|
<button
|
|
34
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-
|
|
34
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall tss-1qeitpp-menuIcon css-zubjuh-MuiButtonBase-root-MuiIconButton-root"
|
|
35
35
|
tabindex="0"
|
|
36
36
|
type="button"
|
|
37
37
|
>
|
|
38
38
|
<svg
|
|
39
39
|
aria-hidden="true"
|
|
40
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
40
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
41
41
|
data-testid="MenuIcon"
|
|
42
42
|
focusable="false"
|
|
43
43
|
viewBox="0 0 24 24"
|
|
@@ -51,13 +51,13 @@ exports[`HierarchicalTrackSelector widget renders with a couple of categorized t
|
|
|
51
51
|
/>
|
|
52
52
|
</button>
|
|
53
53
|
<button
|
|
54
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-
|
|
54
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall tss-1qeitpp-menuIcon css-zubjuh-MuiButtonBase-root-MuiIconButton-root"
|
|
55
55
|
tabindex="0"
|
|
56
56
|
type="button"
|
|
57
57
|
>
|
|
58
58
|
<svg
|
|
59
59
|
aria-hidden="true"
|
|
60
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
60
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
61
61
|
focusable="false"
|
|
62
62
|
viewBox="0 0 24 24"
|
|
63
63
|
>
|
|
@@ -70,10 +70,10 @@ exports[`HierarchicalTrackSelector widget renders with a couple of categorized t
|
|
|
70
70
|
/>
|
|
71
71
|
</button>
|
|
72
72
|
<div
|
|
73
|
-
class="MuiFormControl-root MuiFormControl-fullWidth MuiTextField-root tss-
|
|
73
|
+
class="MuiFormControl-root MuiFormControl-marginDense MuiFormControl-fullWidth MuiTextField-root tss-45fwc5-searchBox css-1z10yd4-MuiFormControl-root-MuiTextField-root"
|
|
74
74
|
>
|
|
75
75
|
<label
|
|
76
|
-
class="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-
|
|
76
|
+
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-sizeSmall MuiInputLabel-standard MuiFormLabel-colorPrimary css-1s1jvl0-MuiFormLabel-root-MuiInputLabel-root"
|
|
77
77
|
data-shrink="false"
|
|
78
78
|
for="mui-5"
|
|
79
79
|
id="mui-5-label"
|
|
@@ -81,26 +81,26 @@ exports[`HierarchicalTrackSelector widget renders with a couple of categorized t
|
|
|
81
81
|
Filter tracks
|
|
82
82
|
</label>
|
|
83
83
|
<div
|
|
84
|
-
class="
|
|
84
|
+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorPrimary MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-sizeSmall MuiInputBase-adornedEnd css-1wz39fi-MuiInputBase-root-MuiInput-root"
|
|
85
85
|
>
|
|
86
86
|
<input
|
|
87
87
|
aria-invalid="false"
|
|
88
|
-
class="
|
|
88
|
+
class="MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedEnd css-nz481w-MuiInputBase-input-MuiInput-input"
|
|
89
89
|
id="mui-5"
|
|
90
90
|
type="text"
|
|
91
91
|
value=""
|
|
92
92
|
/>
|
|
93
93
|
<div
|
|
94
|
-
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-
|
|
94
|
+
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-standard MuiInputAdornment-sizeSmall css-1laqsz7-MuiInputAdornment-root"
|
|
95
95
|
>
|
|
96
96
|
<button
|
|
97
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorSecondary MuiIconButton-
|
|
97
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorSecondary MuiIconButton-sizeSmall css-16a6k96-MuiButtonBase-root-MuiIconButton-root"
|
|
98
98
|
tabindex="0"
|
|
99
99
|
type="button"
|
|
100
100
|
>
|
|
101
101
|
<svg
|
|
102
102
|
aria-hidden="true"
|
|
103
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
103
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
104
104
|
data-testid="ClearIcon"
|
|
105
105
|
focusable="false"
|
|
106
106
|
viewBox="0 0 24 24"
|
|
@@ -114,18 +114,6 @@ exports[`HierarchicalTrackSelector widget renders with a couple of categorized t
|
|
|
114
114
|
/>
|
|
115
115
|
</button>
|
|
116
116
|
</div>
|
|
117
|
-
<fieldset
|
|
118
|
-
aria-hidden="true"
|
|
119
|
-
class="MuiOutlinedInput-notchedOutline css-1d3z3hw-MuiOutlinedInput-notchedOutline"
|
|
120
|
-
>
|
|
121
|
-
<legend
|
|
122
|
-
class="css-1ftyaf0"
|
|
123
|
-
>
|
|
124
|
-
<span>
|
|
125
|
-
Filter tracks
|
|
126
|
-
</span>
|
|
127
|
-
</legend>
|
|
128
|
-
</fieldset>
|
|
129
117
|
</div>
|
|
130
118
|
</div>
|
|
131
119
|
</div>
|
|
@@ -140,13 +128,13 @@ exports[`HierarchicalTrackSelector widget renders with a couple of uncategorized
|
|
|
140
128
|
style="display: flex;"
|
|
141
129
|
>
|
|
142
130
|
<button
|
|
143
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-
|
|
131
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall tss-1qeitpp-menuIcon css-zubjuh-MuiButtonBase-root-MuiIconButton-root"
|
|
144
132
|
tabindex="0"
|
|
145
133
|
type="button"
|
|
146
134
|
>
|
|
147
135
|
<svg
|
|
148
136
|
aria-hidden="true"
|
|
149
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
137
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
150
138
|
data-testid="MenuIcon"
|
|
151
139
|
focusable="false"
|
|
152
140
|
viewBox="0 0 24 24"
|
|
@@ -160,13 +148,13 @@ exports[`HierarchicalTrackSelector widget renders with a couple of uncategorized
|
|
|
160
148
|
/>
|
|
161
149
|
</button>
|
|
162
150
|
<button
|
|
163
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-
|
|
151
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-sizeSmall tss-1qeitpp-menuIcon css-zubjuh-MuiButtonBase-root-MuiIconButton-root"
|
|
164
152
|
tabindex="0"
|
|
165
153
|
type="button"
|
|
166
154
|
>
|
|
167
155
|
<svg
|
|
168
156
|
aria-hidden="true"
|
|
169
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
157
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
170
158
|
focusable="false"
|
|
171
159
|
viewBox="0 0 24 24"
|
|
172
160
|
>
|
|
@@ -179,10 +167,10 @@ exports[`HierarchicalTrackSelector widget renders with a couple of uncategorized
|
|
|
179
167
|
/>
|
|
180
168
|
</button>
|
|
181
169
|
<div
|
|
182
|
-
class="MuiFormControl-root MuiFormControl-fullWidth MuiTextField-root tss-
|
|
170
|
+
class="MuiFormControl-root MuiFormControl-marginDense MuiFormControl-fullWidth MuiTextField-root tss-45fwc5-searchBox css-1z10yd4-MuiFormControl-root-MuiTextField-root"
|
|
183
171
|
>
|
|
184
172
|
<label
|
|
185
|
-
class="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-
|
|
173
|
+
class="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-sizeSmall MuiInputLabel-standard MuiFormLabel-colorPrimary css-1s1jvl0-MuiFormLabel-root-MuiInputLabel-root"
|
|
186
174
|
data-shrink="false"
|
|
187
175
|
for="mui-1"
|
|
188
176
|
id="mui-1-label"
|
|
@@ -190,26 +178,26 @@ exports[`HierarchicalTrackSelector widget renders with a couple of uncategorized
|
|
|
190
178
|
Filter tracks
|
|
191
179
|
</label>
|
|
192
180
|
<div
|
|
193
|
-
class="
|
|
181
|
+
class="MuiInputBase-root MuiInput-root MuiInput-underline MuiInputBase-colorPrimary MuiInputBase-fullWidth MuiInputBase-formControl MuiInputBase-sizeSmall MuiInputBase-adornedEnd css-1wz39fi-MuiInputBase-root-MuiInput-root"
|
|
194
182
|
>
|
|
195
183
|
<input
|
|
196
184
|
aria-invalid="false"
|
|
197
|
-
class="
|
|
185
|
+
class="MuiInputBase-input MuiInput-input MuiInputBase-inputSizeSmall MuiInputBase-inputAdornedEnd css-nz481w-MuiInputBase-input-MuiInput-input"
|
|
198
186
|
id="mui-1"
|
|
199
187
|
type="text"
|
|
200
188
|
value=""
|
|
201
189
|
/>
|
|
202
190
|
<div
|
|
203
|
-
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-
|
|
191
|
+
class="MuiInputAdornment-root MuiInputAdornment-positionEnd MuiInputAdornment-standard MuiInputAdornment-sizeSmall css-1laqsz7-MuiInputAdornment-root"
|
|
204
192
|
>
|
|
205
193
|
<button
|
|
206
|
-
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorSecondary MuiIconButton-
|
|
194
|
+
class="MuiButtonBase-root MuiIconButton-root MuiIconButton-colorSecondary MuiIconButton-sizeSmall css-16a6k96-MuiButtonBase-root-MuiIconButton-root"
|
|
207
195
|
tabindex="0"
|
|
208
196
|
type="button"
|
|
209
197
|
>
|
|
210
198
|
<svg
|
|
211
199
|
aria-hidden="true"
|
|
212
|
-
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-
|
|
200
|
+
class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-havevq-MuiSvgIcon-root"
|
|
213
201
|
data-testid="ClearIcon"
|
|
214
202
|
focusable="false"
|
|
215
203
|
viewBox="0 0 24 24"
|
|
@@ -223,18 +211,6 @@ exports[`HierarchicalTrackSelector widget renders with a couple of uncategorized
|
|
|
223
211
|
/>
|
|
224
212
|
</button>
|
|
225
213
|
</div>
|
|
226
|
-
<fieldset
|
|
227
|
-
aria-hidden="true"
|
|
228
|
-
class="MuiOutlinedInput-notchedOutline css-1d3z3hw-MuiOutlinedInput-notchedOutline"
|
|
229
|
-
>
|
|
230
|
-
<legend
|
|
231
|
-
class="css-1ftyaf0"
|
|
232
|
-
>
|
|
233
|
-
<span>
|
|
234
|
-
Filter tracks
|
|
235
|
-
</span>
|
|
236
|
-
</legend>
|
|
237
|
-
</fieldset>
|
|
238
214
|
</div>
|
|
239
215
|
</div>
|
|
240
216
|
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration'
|
|
2
|
+
import { TreeNode } from '../model'
|
|
3
|
+
|
|
4
|
+
export function getAllChildren(subtree?: TreeNode): AnyConfigurationModel[] {
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
return (
|
|
7
|
+
subtree?.children.map(t =>
|
|
8
|
+
t.children.length ? getAllChildren(t) : (t.conf as AnyConfigurationModel),
|
|
9
|
+
) || []
|
|
10
|
+
).flat(Infinity)
|
|
11
|
+
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import stateModelFactory, { HierarchicalTrackSelectorModel } from './model'
|
|
2
|
+
import configSchema from './configSchema'
|
|
2
3
|
|
|
3
|
-
export {
|
|
4
|
-
export
|
|
5
|
-
'HierarchicalTrackSelectorWidget',
|
|
6
|
-
{},
|
|
7
|
-
)
|
|
4
|
+
export { stateModelFactory, configSchema }
|
|
5
|
+
export type { HierarchicalTrackSelectorModel }
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { types, getParent, Instance } from 'mobx-state-tree'
|
|
1
|
+
import { types, getParent, getEnv, Instance } from 'mobx-state-tree'
|
|
2
2
|
import {
|
|
3
|
-
AnyConfigurationModel,
|
|
4
3
|
getConf,
|
|
5
4
|
readConfObject,
|
|
5
|
+
AnyConfigurationModel,
|
|
6
6
|
} from '@jbrowse/core/configuration'
|
|
7
7
|
import { getSession } from '@jbrowse/core/util'
|
|
8
8
|
import { ElementId } from '@jbrowse/core/util/types/mst'
|
|
9
9
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
10
|
-
import { AbstractView } from 'react'
|
|
11
10
|
|
|
12
11
|
function hasAnyOverlap<T>(a1: T[] = [], a2: T[] = []) {
|
|
13
12
|
return !!a1.find(value => a2.includes(value))
|
|
@@ -18,11 +17,11 @@ function passesFilter(filter: string, config: AnyConfigurationModel) {
|
|
|
18
17
|
const filterLower = filter.toLowerCase()
|
|
19
18
|
return (
|
|
20
19
|
getTrackName(config).toLowerCase().includes(filterLower) ||
|
|
21
|
-
categories?.filter(c => c.toLowerCase().includes(filterLower)).length
|
|
20
|
+
!!categories?.filter(c => c.toLowerCase().includes(filterLower)).length
|
|
22
21
|
)
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
function getTrackName(config: AnyConfigurationModel) {
|
|
24
|
+
function getTrackName(config: AnyConfigurationModel): string {
|
|
26
25
|
if (!config.trackId) {
|
|
27
26
|
throw new Error('not a track')
|
|
28
27
|
}
|
|
@@ -41,6 +40,32 @@ export type TreeNode = {
|
|
|
41
40
|
children: TreeNode[]
|
|
42
41
|
}
|
|
43
42
|
|
|
43
|
+
function filterTracks(
|
|
44
|
+
tracks: AnyConfigurationModel[],
|
|
45
|
+
self: { view: { type: string } },
|
|
46
|
+
assemblyName: string,
|
|
47
|
+
) {
|
|
48
|
+
const { assemblyManager } = getSession(self)
|
|
49
|
+
const { pluginManager } = getEnv(self)
|
|
50
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
51
|
+
|
|
52
|
+
if (!assembly) {
|
|
53
|
+
return []
|
|
54
|
+
}
|
|
55
|
+
return tracks
|
|
56
|
+
.filter(c => {
|
|
57
|
+
const trackConfAssemblies = readConfObject(c, 'assemblyNames')
|
|
58
|
+
const { allAliases } = assembly
|
|
59
|
+
return hasAnyOverlap(allAliases, trackConfAssemblies)
|
|
60
|
+
})
|
|
61
|
+
.filter(c => {
|
|
62
|
+
const { displayTypes } = pluginManager.getViewType(self.view.type)
|
|
63
|
+
const compatDisplays = displayTypes.map((d: { name: string }) => d.name)
|
|
64
|
+
const trackDisplays = c.displays.map((d: { type: string }) => d.type)
|
|
65
|
+
return hasAnyOverlap(compatDisplays, trackDisplays)
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
|
|
44
69
|
export function generateHierarchy(
|
|
45
70
|
model: HierarchicalTrackSelectorModel,
|
|
46
71
|
trackConfigurations: AnyConfigurationModel[],
|
|
@@ -112,8 +137,20 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
|
|
|
112
137
|
pluginManager.pluggableMstType('view', 'stateModel'),
|
|
113
138
|
),
|
|
114
139
|
})
|
|
140
|
+
.volatile(() => ({
|
|
141
|
+
selection: [] as AnyConfigurationModel[],
|
|
142
|
+
}))
|
|
115
143
|
.actions(self => ({
|
|
116
|
-
|
|
144
|
+
addToSelection(elt: AnyConfigurationModel[]) {
|
|
145
|
+
self.selection = [...self.selection, ...elt]
|
|
146
|
+
},
|
|
147
|
+
removeFromSelection(elt: AnyConfigurationModel[]) {
|
|
148
|
+
self.selection = self.selection.filter(f => !elt.includes(f))
|
|
149
|
+
},
|
|
150
|
+
clearSelection() {
|
|
151
|
+
self.selection = []
|
|
152
|
+
},
|
|
153
|
+
setView(view: unknown) {
|
|
117
154
|
self.view = view
|
|
118
155
|
},
|
|
119
156
|
toggleCategory(pathName: string) {
|
|
@@ -156,20 +193,7 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
|
|
|
156
193
|
// filter out tracks that don't match the current assembly (check all
|
|
157
194
|
// assembly aliases) and display types
|
|
158
195
|
return (refseq ? [refseq] : []).concat([
|
|
159
|
-
...tracks
|
|
160
|
-
.filter(c => {
|
|
161
|
-
const trackConfAssemblies = readConfObject(c, 'assemblyNames')
|
|
162
|
-
const { allAliases } = assembly
|
|
163
|
-
return hasAnyOverlap(allAliases, trackConfAssemblies)
|
|
164
|
-
})
|
|
165
|
-
.filter(c => {
|
|
166
|
-
const { displayTypes } = pluginManager.getViewType(self.view.type)
|
|
167
|
-
const compatibleDisplays = displayTypes.map(d => d.name)
|
|
168
|
-
const trackDisplays = c.displays.map(
|
|
169
|
-
(d: { type: string }) => d.type,
|
|
170
|
-
)
|
|
171
|
-
return hasAnyOverlap(compatibleDisplays, trackDisplays)
|
|
172
|
-
}),
|
|
196
|
+
...filterTracks(tracks, self, assemblyName),
|
|
173
197
|
])
|
|
174
198
|
},
|
|
175
199
|
|
|
@@ -184,29 +208,9 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
|
|
|
184
208
|
if (!self.view) {
|
|
185
209
|
return []
|
|
186
210
|
}
|
|
187
|
-
const trackConfigurations = connection.tracks
|
|
188
|
-
const { assemblyManager } = getSession(self)
|
|
189
|
-
const assembly = assemblyManager.get(assemblyName)
|
|
190
|
-
|
|
191
|
-
if (!(assembly && assembly.initialized)) {
|
|
192
|
-
return []
|
|
193
|
-
}
|
|
194
211
|
|
|
195
212
|
// filter out tracks that don't match the current display types
|
|
196
|
-
return
|
|
197
|
-
.filter(c => {
|
|
198
|
-
const trackConfAssemblies = readConfObject(c, 'assemblyNames')
|
|
199
|
-
const { allAliases } = assembly
|
|
200
|
-
return hasAnyOverlap(allAliases, trackConfAssemblies)
|
|
201
|
-
})
|
|
202
|
-
.filter(c => {
|
|
203
|
-
const { displayTypes } = pluginManager.getViewType(self.view.type)
|
|
204
|
-
const compatibleDisplays = displayTypes.map(d => d.name)
|
|
205
|
-
const trackDisplays = c.displays.map(
|
|
206
|
-
(d: { type: string }) => d.type,
|
|
207
|
-
)
|
|
208
|
-
return hasAnyOverlap(compatibleDisplays, trackDisplays)
|
|
209
|
-
})
|
|
213
|
+
return filterTracks(connection.tracks, self, assemblyName)
|
|
210
214
|
},
|
|
211
215
|
}))
|
|
212
216
|
.views(self => ({
|