@jbrowse/plugin-data-management 2.2.2 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AddTrackWidget/components/AddTrackWidget.js +28 -5
- package/dist/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
- package/dist/AddTrackWidget/components/ConfirmTrack.d.ts +2 -3
- package/dist/AddTrackWidget/components/ConfirmTrack.js +30 -177
- package/dist/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
- package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -1
- package/dist/AddTrackWidget/components/TextIndexingConfig.d.ts +6 -0
- package/dist/AddTrackWidget/components/TextIndexingConfig.js +109 -0
- package/dist/AddTrackWidget/components/TextIndexingConfig.js.map +1 -0
- package/dist/AddTrackWidget/components/TrackAdapterSelector.d.ts +6 -0
- package/dist/AddTrackWidget/components/TrackAdapterSelector.js +50 -0
- package/dist/AddTrackWidget/components/TrackAdapterSelector.js.map +1 -0
- package/dist/AddTrackWidget/components/TrackTypeSelector.d.ts +6 -0
- package/dist/AddTrackWidget/components/TrackTypeSelector.js +27 -0
- package/dist/AddTrackWidget/components/TrackTypeSelector.js.map +1 -0
- package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +3 -4
- package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +3 -1
- package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js.map +1 -1
- package/dist/HierarchicalTrackSelectorWidget/model.d.ts +2 -1
- package/dist/HierarchicalTrackSelectorWidget/model.js +5 -5
- package/dist/HierarchicalTrackSelectorWidget/model.js.map +1 -1
- package/dist/ucsc-trackhub/index.d.ts +2 -2
- package/dist/ucsc-trackhub/index.js.map +1 -1
- package/dist/ucsc-trackhub/model.d.ts +3 -2
- package/dist/ucsc-trackhub/model.js +41 -40
- package/dist/ucsc-trackhub/model.js.map +1 -1
- package/dist/ucsc-trackhub/ucscAssemblies.js.map +1 -1
- package/esm/AddTrackWidget/components/AddTrackWidget.js +6 -6
- package/esm/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
- package/esm/AddTrackWidget/components/ConfirmTrack.d.ts +2 -3
- package/esm/AddTrackWidget/components/ConfirmTrack.js +28 -175
- package/esm/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
- package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -1
- package/esm/AddTrackWidget/components/TextIndexingConfig.d.ts +6 -0
- package/esm/AddTrackWidget/components/TextIndexingConfig.js +81 -0
- package/esm/AddTrackWidget/components/TextIndexingConfig.js.map +1 -0
- package/esm/AddTrackWidget/components/TrackAdapterSelector.d.ts +6 -0
- package/esm/AddTrackWidget/components/TrackAdapterSelector.js +45 -0
- package/esm/AddTrackWidget/components/TrackAdapterSelector.js.map +1 -0
- package/esm/AddTrackWidget/components/TrackTypeSelector.d.ts +6 -0
- package/esm/AddTrackWidget/components/TrackTypeSelector.js +22 -0
- package/esm/AddTrackWidget/components/TrackTypeSelector.js.map +1 -0
- package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +3 -4
- package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
- package/esm/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +3 -1
- package/esm/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js.map +1 -1
- package/esm/HierarchicalTrackSelectorWidget/model.d.ts +2 -1
- package/esm/HierarchicalTrackSelectorWidget/model.js +5 -5
- package/esm/HierarchicalTrackSelectorWidget/model.js.map +1 -1
- package/esm/ucsc-trackhub/index.d.ts +2 -2
- package/esm/ucsc-trackhub/index.js.map +1 -1
- package/esm/ucsc-trackhub/model.d.ts +3 -2
- package/esm/ucsc-trackhub/model.js +41 -40
- package/esm/ucsc-trackhub/model.js.map +1 -1
- package/esm/ucsc-trackhub/ucscAssemblies.js.map +1 -1
- package/package.json +3 -4
- package/src/AddTrackWidget/components/AddTrackWidget.test.tsx +3 -4
- package/src/AddTrackWidget/components/AddTrackWidget.tsx +6 -9
- package/src/AddTrackWidget/components/ConfirmTrack.tsx +36 -296
- package/src/AddTrackWidget/components/DefaultAddTrackWorkflow.tsx +0 -1
- package/src/AddTrackWidget/components/TextIndexingConfig.tsx +134 -0
- package/src/AddTrackWidget/components/TrackAdapterSelector.tsx +73 -0
- package/src/AddTrackWidget/components/TrackTypeSelector.tsx +46 -0
- package/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.tsx +4 -4
- package/src/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.tsx +5 -1
- package/src/HierarchicalTrackSelectorWidget/components/__snapshots__/HierarchicalTrackSelector.test.tsx.snap +1 -1
- package/src/HierarchicalTrackSelectorWidget/model.ts +7 -7
- package/src/PluginStoreWidget/components/__snapshots__/PluginStoreWidget.test.js.snap +0 -22
- package/src/ucsc-trackhub/{index.js → index.ts} +0 -0
- package/src/ucsc-trackhub/model.ts +119 -0
- package/src/ucsc-trackhub/{ucscAssemblies.js → ucscAssemblies.ts} +0 -0
- package/src/ucsc-trackhub/model.js +0 -125
|
@@ -1,56 +1,32 @@
|
|
|
1
1
|
import React, { useEffect, useState } from 'react'
|
|
2
2
|
import {
|
|
3
|
-
Card,
|
|
4
|
-
CardContent,
|
|
5
3
|
Checkbox,
|
|
6
4
|
FormControl,
|
|
7
5
|
FormControlLabel,
|
|
8
|
-
IconButton,
|
|
9
|
-
InputLabel,
|
|
10
|
-
InputAdornment,
|
|
11
|
-
ListSubheader,
|
|
12
6
|
Link,
|
|
13
|
-
List,
|
|
14
|
-
ListItem,
|
|
15
|
-
MenuItem,
|
|
16
|
-
Paper,
|
|
17
7
|
TextField,
|
|
18
8
|
Typography,
|
|
19
9
|
} from '@mui/material'
|
|
20
10
|
import { makeStyles } from 'tss-react/mui'
|
|
21
|
-
import { readConfObject } from '@jbrowse/core/configuration'
|
|
22
11
|
import {
|
|
23
12
|
supportedIndexingAdapters,
|
|
24
13
|
getSession,
|
|
25
|
-
getEnv,
|
|
26
14
|
isElectron,
|
|
27
15
|
} from '@jbrowse/core/util'
|
|
28
|
-
import PluginManager from '@jbrowse/core/PluginManager'
|
|
29
16
|
import { observer } from 'mobx-react'
|
|
30
17
|
import { UNKNOWN } from '@jbrowse/core/util/tracks'
|
|
31
|
-
import {
|
|
18
|
+
import { AssemblySelector } from '@jbrowse/core/ui'
|
|
32
19
|
|
|
33
|
-
// icons
|
|
34
|
-
import DeleteIcon from '@mui/icons-material/Delete'
|
|
35
|
-
import AddIcon from '@mui/icons-material//Add'
|
|
36
20
|
// locals
|
|
37
21
|
import { AddTrackModel } from '../model'
|
|
22
|
+
import TextIndexingConfig from './TextIndexingConfig'
|
|
23
|
+
import TrackTypeSelector from './TrackTypeSelector'
|
|
24
|
+
import TrackAdapterSelector from './TrackAdapterSelector'
|
|
38
25
|
|
|
39
26
|
const useStyles = makeStyles()(theme => ({
|
|
40
27
|
spacing: {
|
|
41
28
|
marginBottom: theme.spacing(3),
|
|
42
29
|
},
|
|
43
|
-
paper: {
|
|
44
|
-
display: 'flex',
|
|
45
|
-
flexDirection: 'column',
|
|
46
|
-
padding: theme.spacing(1),
|
|
47
|
-
},
|
|
48
|
-
spacer: {
|
|
49
|
-
height: theme.spacing(8),
|
|
50
|
-
},
|
|
51
|
-
card: {
|
|
52
|
-
marginTop: theme.spacing(1),
|
|
53
|
-
},
|
|
54
30
|
}))
|
|
55
31
|
|
|
56
32
|
function StatusMessage({
|
|
@@ -61,215 +37,22 @@ function StatusMessage({
|
|
|
61
37
|
trackType: string
|
|
62
38
|
}) {
|
|
63
39
|
const { classes } = useStyles()
|
|
64
|
-
|
|
40
|
+
const { type, subadapter } = trackAdapter
|
|
41
|
+
return type === 'SNPCoverageAdapter' ? (
|
|
65
42
|
<Typography className={classes.spacing}>
|
|
66
|
-
Selected <code>{trackType}</code>. Using adapter{
|
|
67
|
-
<code>{
|
|
68
|
-
|
|
69
|
-
and, if necessary, update the track type.
|
|
43
|
+
Selected <code>{trackType}</code>. Using adapter <code>{type}</code> with
|
|
44
|
+
subadapter <code>{subadapter?.type}</code>. Please enter a track name and,
|
|
45
|
+
if necessary, update the track type.
|
|
70
46
|
</Typography>
|
|
71
47
|
) : (
|
|
72
48
|
<Typography className={classes.spacing}>
|
|
73
|
-
Using adapter <code>{
|
|
49
|
+
Using adapter <code>{type}</code> and guessing track type{' '}
|
|
74
50
|
<code>{trackType}</code>. Please enter a track name and, if necessary,
|
|
75
51
|
update the track type.
|
|
76
52
|
</Typography>
|
|
77
53
|
)
|
|
78
54
|
}
|
|
79
55
|
|
|
80
|
-
/**
|
|
81
|
-
* categorizeAdapters takes a list of adapters and sorts their menu item elements under an appropriate ListSubheader
|
|
82
|
-
* element. In this way, adapters that are from external plugins can have headers that differentiate them from the
|
|
83
|
-
* out-of-the-box plugins.
|
|
84
|
-
* @param adaptersList - a list of adapters found in the PluginManager
|
|
85
|
-
* @returns a series of JSX elements that are ListSubheaders followed by the adapters
|
|
86
|
-
* found under that subheader
|
|
87
|
-
*/
|
|
88
|
-
function categorizeAdapters(
|
|
89
|
-
adaptersList: { name: string; adapterMetadata: AdapterMetadata }[],
|
|
90
|
-
) {
|
|
91
|
-
let currentCategory = ''
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
93
|
-
const items: any = []
|
|
94
|
-
adaptersList.forEach(adapter => {
|
|
95
|
-
if (adapter.adapterMetadata?.category) {
|
|
96
|
-
if (currentCategory !== adapter.adapterMetadata?.category) {
|
|
97
|
-
currentCategory = adapter.adapterMetadata?.category
|
|
98
|
-
items.push(
|
|
99
|
-
<ListSubheader
|
|
100
|
-
key={adapter.adapterMetadata?.category}
|
|
101
|
-
value={adapter.adapterMetadata?.category}
|
|
102
|
-
>
|
|
103
|
-
{adapter.adapterMetadata?.category}
|
|
104
|
-
</ListSubheader>,
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
items.push(
|
|
108
|
-
<MenuItem key={adapter.name} value={adapter.name}>
|
|
109
|
-
{adapter.adapterMetadata?.displayName
|
|
110
|
-
? adapter.adapterMetadata?.displayName
|
|
111
|
-
: adapter.name}
|
|
112
|
-
</MenuItem>,
|
|
113
|
-
)
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
return items
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function getAdapterTypes(pluginManager: PluginManager) {
|
|
120
|
-
return pluginManager.getElementTypesInGroup('adapter') as {
|
|
121
|
-
name: string
|
|
122
|
-
adapterMetadata: AdapterMetadata
|
|
123
|
-
}[]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function getTrackTypes(pluginManager: PluginManager) {
|
|
127
|
-
return pluginManager.getElementTypesInGroup('track') as { name: string }[]
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const TextIndexingConfig = observer(({ model }: { model: AddTrackModel }) => {
|
|
131
|
-
const { classes } = useStyles()
|
|
132
|
-
const [value1, setValue1] = useState('')
|
|
133
|
-
const [value2, setValue2] = useState('')
|
|
134
|
-
const [attributes, setAttributes] = useState(['Name', 'ID'])
|
|
135
|
-
const [exclude, setExclude] = useState(['CDS', 'exon'])
|
|
136
|
-
const sections = [
|
|
137
|
-
{
|
|
138
|
-
label: 'Indexing attributes',
|
|
139
|
-
values: attributes,
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
label: 'Feature types to exclude',
|
|
143
|
-
values: exclude,
|
|
144
|
-
},
|
|
145
|
-
]
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
model.setTextIndexingConf({ attributes, exclude })
|
|
148
|
-
}, [model, attributes, exclude])
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<Paper className={classes.paper}>
|
|
152
|
-
<InputLabel>Indexing configuration</InputLabel>
|
|
153
|
-
{sections.map((section, index) => (
|
|
154
|
-
<Card raised key={section.label} className={classes.card}>
|
|
155
|
-
<CardContent>
|
|
156
|
-
<InputLabel>{section.label}</InputLabel>
|
|
157
|
-
<List disablePadding>
|
|
158
|
-
{section.values.map((val: string, idx: number) => (
|
|
159
|
-
<ListItem key={idx} disableGutters>
|
|
160
|
-
<TextField
|
|
161
|
-
value={val}
|
|
162
|
-
InputProps={{
|
|
163
|
-
endAdornment: (
|
|
164
|
-
<InputAdornment position="end">
|
|
165
|
-
<IconButton
|
|
166
|
-
color="secondary"
|
|
167
|
-
onClick={() => {
|
|
168
|
-
const newAttr = section.values.filter((a, i) => {
|
|
169
|
-
return i !== idx
|
|
170
|
-
})
|
|
171
|
-
index === 0
|
|
172
|
-
? setAttributes(newAttr)
|
|
173
|
-
: setExclude(newAttr)
|
|
174
|
-
}}
|
|
175
|
-
>
|
|
176
|
-
<DeleteIcon />
|
|
177
|
-
</IconButton>
|
|
178
|
-
</InputAdornment>
|
|
179
|
-
),
|
|
180
|
-
}}
|
|
181
|
-
/>
|
|
182
|
-
</ListItem>
|
|
183
|
-
))}
|
|
184
|
-
<ListItem disableGutters>
|
|
185
|
-
<TextField
|
|
186
|
-
value={index === 0 ? value1 : value2}
|
|
187
|
-
placeholder="add new"
|
|
188
|
-
onChange={event => {
|
|
189
|
-
index === 0
|
|
190
|
-
? setValue1(event.target.value)
|
|
191
|
-
: setValue2(event.target.value)
|
|
192
|
-
}}
|
|
193
|
-
InputProps={{
|
|
194
|
-
endAdornment: (
|
|
195
|
-
<InputAdornment position="end">
|
|
196
|
-
<IconButton
|
|
197
|
-
onClick={() => {
|
|
198
|
-
if (index === 0) {
|
|
199
|
-
const newAttr: string[] = attributes
|
|
200
|
-
newAttr.push(value1)
|
|
201
|
-
setAttributes(newAttr)
|
|
202
|
-
setValue1('')
|
|
203
|
-
} else {
|
|
204
|
-
const newFeat: string[] = exclude
|
|
205
|
-
newFeat.push(value2)
|
|
206
|
-
setExclude(newFeat)
|
|
207
|
-
setValue2('')
|
|
208
|
-
}
|
|
209
|
-
}}
|
|
210
|
-
disabled={index === 0 ? value1 === '' : value2 === ''}
|
|
211
|
-
color="secondary"
|
|
212
|
-
data-testid={`stringArrayAdd-Feat`}
|
|
213
|
-
>
|
|
214
|
-
<AddIcon />
|
|
215
|
-
</IconButton>
|
|
216
|
-
</InputAdornment>
|
|
217
|
-
),
|
|
218
|
-
}}
|
|
219
|
-
/>
|
|
220
|
-
</ListItem>
|
|
221
|
-
</List>
|
|
222
|
-
</CardContent>
|
|
223
|
-
</Card>
|
|
224
|
-
))}
|
|
225
|
-
</Paper>
|
|
226
|
-
)
|
|
227
|
-
})
|
|
228
|
-
|
|
229
|
-
const TrackAdapterSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
230
|
-
const { classes } = useStyles()
|
|
231
|
-
const { trackAdapter } = model
|
|
232
|
-
const { pluginManager } = getEnv(model)
|
|
233
|
-
const adapters = getAdapterTypes(pluginManager)
|
|
234
|
-
return (
|
|
235
|
-
<TextField
|
|
236
|
-
className={classes.spacing}
|
|
237
|
-
value={trackAdapter?.type !== 'UNKNOWN' ? trackAdapter?.type : ''}
|
|
238
|
-
label="adapterType"
|
|
239
|
-
helperText="Select an adapter type"
|
|
240
|
-
select
|
|
241
|
-
fullWidth
|
|
242
|
-
onChange={event => model.setAdapterHint(event.target.value)}
|
|
243
|
-
SelectProps={{
|
|
244
|
-
// @ts-ignore
|
|
245
|
-
SelectDisplayProps: { 'data-testid': 'adapterTypeSelect' },
|
|
246
|
-
}}
|
|
247
|
-
>
|
|
248
|
-
{adapters
|
|
249
|
-
// Excludes any adapter with the 'adapterMetadata.hiddenFromGUI' property, and anything with the 'adapterMetadata.category' property
|
|
250
|
-
.filter(
|
|
251
|
-
elt =>
|
|
252
|
-
!elt.adapterMetadata?.hiddenFromGUI &&
|
|
253
|
-
!elt.adapterMetadata?.category,
|
|
254
|
-
)
|
|
255
|
-
.map(elt => (
|
|
256
|
-
<MenuItem key={elt.name} value={elt.name}>
|
|
257
|
-
{elt.adapterMetadata?.displayName
|
|
258
|
-
? elt.adapterMetadata?.displayName
|
|
259
|
-
: elt.name}
|
|
260
|
-
</MenuItem>
|
|
261
|
-
))}
|
|
262
|
-
{
|
|
263
|
-
// adapters with the 'adapterMetadata.category' property are categorized
|
|
264
|
-
// by the value of the property here
|
|
265
|
-
categorizeAdapters(
|
|
266
|
-
adapters.filter(elt => !elt.adapterMetadata?.hiddenFromGUI),
|
|
267
|
-
)
|
|
268
|
-
}
|
|
269
|
-
</TextField>
|
|
270
|
-
)
|
|
271
|
-
})
|
|
272
|
-
|
|
273
56
|
function UnknownAdapterPrompt({ model }: { model: AddTrackModel }) {
|
|
274
57
|
const { classes } = useStyles()
|
|
275
58
|
return (
|
|
@@ -299,72 +82,23 @@ function UnknownAdapterPrompt({ model }: { model: AddTrackModel }) {
|
|
|
299
82
|
)
|
|
300
83
|
}
|
|
301
84
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return (
|
|
309
|
-
<TextField
|
|
310
|
-
className={classes.spacing}
|
|
311
|
-
value={trackType}
|
|
312
|
-
label="trackType"
|
|
313
|
-
helperText="Select a track type"
|
|
314
|
-
select
|
|
315
|
-
fullWidth
|
|
316
|
-
onChange={event => {
|
|
317
|
-
model.setTrackType(event.target.value)
|
|
318
|
-
}}
|
|
319
|
-
SelectProps={{
|
|
320
|
-
// @ts-ignore
|
|
321
|
-
SelectDisplayProps: { 'data-testid': 'trackTypeSelect' },
|
|
322
|
-
}}
|
|
323
|
-
>
|
|
324
|
-
{trackTypes.map(({ name }) => (
|
|
325
|
-
<MenuItem key={name} value={name}>
|
|
326
|
-
{name}
|
|
327
|
-
</MenuItem>
|
|
328
|
-
))}
|
|
329
|
-
</TextField>
|
|
330
|
-
)
|
|
331
|
-
})
|
|
332
|
-
|
|
333
|
-
const TrackAssemblySelector = observer(
|
|
334
|
-
({ model }: { model: AddTrackModel }) => {
|
|
335
|
-
const session = getSession(model)
|
|
336
|
-
const { assembly } = model
|
|
337
|
-
return (
|
|
338
|
-
<TextField
|
|
339
|
-
value={assembly}
|
|
340
|
-
label="assemblyName"
|
|
341
|
-
helperText="Assembly to which the track will be added"
|
|
342
|
-
select
|
|
343
|
-
fullWidth
|
|
344
|
-
onChange={event => model.setAssembly(event.target.value)}
|
|
345
|
-
SelectProps={{
|
|
346
|
-
// @ts-ignore
|
|
347
|
-
SelectDisplayProps: { 'data-testid': 'assemblyNameSelect' },
|
|
348
|
-
}}
|
|
349
|
-
>
|
|
350
|
-
{session.assemblies
|
|
351
|
-
.map(conf => readConfObject(conf, 'name'))
|
|
352
|
-
.map(name => (
|
|
353
|
-
<MenuItem key={name} value={name}>
|
|
354
|
-
{name}
|
|
355
|
-
</MenuItem>
|
|
356
|
-
))}
|
|
357
|
-
</TextField>
|
|
358
|
-
)
|
|
359
|
-
},
|
|
360
|
-
)
|
|
361
|
-
|
|
362
|
-
function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
85
|
+
export default observer(function ConfirmTrack({
|
|
86
|
+
model,
|
|
87
|
+
}: {
|
|
88
|
+
model: AddTrackModel
|
|
89
|
+
}) {
|
|
363
90
|
const { classes } = useStyles()
|
|
364
91
|
const [check, setCheck] = useState(true)
|
|
92
|
+
const session = getSession(model)
|
|
365
93
|
const { trackName, trackAdapter, trackType, warningMessage, adapterHint } =
|
|
366
94
|
model
|
|
367
95
|
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (adapterHint === '' && trackAdapter) {
|
|
98
|
+
model.setAdapterHint(trackAdapter.type)
|
|
99
|
+
}
|
|
100
|
+
}, [adapterHint, trackAdapter, trackAdapter?.type, model])
|
|
101
|
+
|
|
368
102
|
if (model.unsupported) {
|
|
369
103
|
return (
|
|
370
104
|
<Typography className={classes.spacing}>
|
|
@@ -394,10 +128,6 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
|
394
128
|
return <UnknownAdapterPrompt model={model} />
|
|
395
129
|
}
|
|
396
130
|
|
|
397
|
-
if (adapterHint === '' && trackAdapter) {
|
|
398
|
-
model.setAdapterHint(trackAdapter.type)
|
|
399
|
-
}
|
|
400
|
-
|
|
401
131
|
if (!trackAdapter?.type) {
|
|
402
132
|
return <Typography>Could not recognize this data type.</Typography>
|
|
403
133
|
}
|
|
@@ -422,7 +152,19 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
|
422
152
|
/>
|
|
423
153
|
<TrackAdapterSelector model={model} />
|
|
424
154
|
<TrackTypeSelector model={model} />
|
|
425
|
-
<
|
|
155
|
+
<AssemblySelector
|
|
156
|
+
session={session}
|
|
157
|
+
helperText="Select assembly to add track to"
|
|
158
|
+
selected={model.assembly}
|
|
159
|
+
onChange={asm => model.setAssembly(asm)}
|
|
160
|
+
TextFieldProps={{
|
|
161
|
+
fullWidth: true,
|
|
162
|
+
SelectProps: {
|
|
163
|
+
// @ts-ignore
|
|
164
|
+
SelectDisplayProps: { 'data-testid': 'assemblyNameSelect' },
|
|
165
|
+
},
|
|
166
|
+
}}
|
|
167
|
+
/>
|
|
426
168
|
{isElectron && supportedForIndexing && (
|
|
427
169
|
<FormControl>
|
|
428
170
|
<FormControlLabel
|
|
@@ -444,6 +186,4 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
|
444
186
|
) : null}
|
|
445
187
|
</div>
|
|
446
188
|
)
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
export default observer(ConfirmTrack)
|
|
189
|
+
})
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react'
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
IconButton,
|
|
6
|
+
InputLabel,
|
|
7
|
+
InputAdornment,
|
|
8
|
+
List,
|
|
9
|
+
ListItem,
|
|
10
|
+
Paper,
|
|
11
|
+
TextField,
|
|
12
|
+
} from '@mui/material'
|
|
13
|
+
import { makeStyles } from 'tss-react/mui'
|
|
14
|
+
import { observer } from 'mobx-react'
|
|
15
|
+
|
|
16
|
+
// icons
|
|
17
|
+
import DeleteIcon from '@mui/icons-material/Delete'
|
|
18
|
+
import AddIcon from '@mui/icons-material/Add'
|
|
19
|
+
|
|
20
|
+
// locals
|
|
21
|
+
import { AddTrackModel } from '../model'
|
|
22
|
+
|
|
23
|
+
const useStyles = makeStyles()(theme => ({
|
|
24
|
+
paper: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexDirection: 'column',
|
|
27
|
+
padding: theme.spacing(1),
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
card: {
|
|
31
|
+
marginTop: theme.spacing(1),
|
|
32
|
+
},
|
|
33
|
+
}))
|
|
34
|
+
|
|
35
|
+
const TextIndexingConfig = observer(({ model }: { model: AddTrackModel }) => {
|
|
36
|
+
const { classes } = useStyles()
|
|
37
|
+
const [value1, setValue1] = useState('')
|
|
38
|
+
const [value2, setValue2] = useState('')
|
|
39
|
+
const [attributes, setAttributes] = useState(['Name', 'ID'])
|
|
40
|
+
const [exclude, setExclude] = useState(['CDS', 'exon'])
|
|
41
|
+
const sections = [
|
|
42
|
+
{
|
|
43
|
+
label: 'Indexing attributes',
|
|
44
|
+
values: attributes,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
label: 'Feature types to exclude',
|
|
48
|
+
values: exclude,
|
|
49
|
+
},
|
|
50
|
+
]
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
model.setTextIndexingConf({ attributes, exclude })
|
|
53
|
+
}, [model, attributes, exclude])
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Paper className={classes.paper}>
|
|
57
|
+
<InputLabel>Indexing configuration</InputLabel>
|
|
58
|
+
{sections.map((section, index) => (
|
|
59
|
+
<Card raised key={section.label} className={classes.card}>
|
|
60
|
+
<CardContent>
|
|
61
|
+
<InputLabel>{section.label}</InputLabel>
|
|
62
|
+
<List disablePadding>
|
|
63
|
+
{section.values.map((val: string, idx: number) => (
|
|
64
|
+
<ListItem key={idx} disableGutters>
|
|
65
|
+
<TextField
|
|
66
|
+
value={val}
|
|
67
|
+
InputProps={{
|
|
68
|
+
endAdornment: (
|
|
69
|
+
<InputAdornment position="end">
|
|
70
|
+
<IconButton
|
|
71
|
+
color="secondary"
|
|
72
|
+
onClick={() => {
|
|
73
|
+
const newAttr = section.values.filter((a, i) => {
|
|
74
|
+
return i !== idx
|
|
75
|
+
})
|
|
76
|
+
index === 0
|
|
77
|
+
? setAttributes(newAttr)
|
|
78
|
+
: setExclude(newAttr)
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
<DeleteIcon />
|
|
82
|
+
</IconButton>
|
|
83
|
+
</InputAdornment>
|
|
84
|
+
),
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
</ListItem>
|
|
88
|
+
))}
|
|
89
|
+
<ListItem disableGutters>
|
|
90
|
+
<TextField
|
|
91
|
+
value={index === 0 ? value1 : value2}
|
|
92
|
+
placeholder="add new"
|
|
93
|
+
onChange={event => {
|
|
94
|
+
index === 0
|
|
95
|
+
? setValue1(event.target.value)
|
|
96
|
+
: setValue2(event.target.value)
|
|
97
|
+
}}
|
|
98
|
+
InputProps={{
|
|
99
|
+
endAdornment: (
|
|
100
|
+
<InputAdornment position="end">
|
|
101
|
+
<IconButton
|
|
102
|
+
onClick={() => {
|
|
103
|
+
if (index === 0) {
|
|
104
|
+
const newAttr: string[] = attributes
|
|
105
|
+
newAttr.push(value1)
|
|
106
|
+
setAttributes(newAttr)
|
|
107
|
+
setValue1('')
|
|
108
|
+
} else {
|
|
109
|
+
const newFeat: string[] = exclude
|
|
110
|
+
newFeat.push(value2)
|
|
111
|
+
setExclude(newFeat)
|
|
112
|
+
setValue2('')
|
|
113
|
+
}
|
|
114
|
+
}}
|
|
115
|
+
disabled={index === 0 ? value1 === '' : value2 === ''}
|
|
116
|
+
color="secondary"
|
|
117
|
+
data-testid={`stringArrayAdd-Feat`}
|
|
118
|
+
>
|
|
119
|
+
<AddIcon />
|
|
120
|
+
</IconButton>
|
|
121
|
+
</InputAdornment>
|
|
122
|
+
),
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
</ListItem>
|
|
126
|
+
</List>
|
|
127
|
+
</CardContent>
|
|
128
|
+
</Card>
|
|
129
|
+
))}
|
|
130
|
+
</Paper>
|
|
131
|
+
)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
export default TextIndexingConfig
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { ListSubheader, MenuItem, TextField } from '@mui/material'
|
|
3
|
+
import { makeStyles } from 'tss-react/mui'
|
|
4
|
+
import { getEnv } from '@jbrowse/core/util'
|
|
5
|
+
import { observer } from 'mobx-react'
|
|
6
|
+
import AdapterType from '@jbrowse/core/pluggableElementTypes/AdapterType'
|
|
7
|
+
|
|
8
|
+
// locals
|
|
9
|
+
import { AddTrackModel } from '../model'
|
|
10
|
+
|
|
11
|
+
const useStyles = makeStyles()(theme => ({
|
|
12
|
+
spacing: {
|
|
13
|
+
marginBottom: theme.spacing(3),
|
|
14
|
+
},
|
|
15
|
+
}))
|
|
16
|
+
|
|
17
|
+
// collate adapters into a map with
|
|
18
|
+
// key: category
|
|
19
|
+
// value: array of adapters with that category
|
|
20
|
+
function categorizeAdapters(adaptersList: AdapterType[]) {
|
|
21
|
+
const map = {} as { [key: string]: AdapterType[] }
|
|
22
|
+
adaptersList.forEach(adapter => {
|
|
23
|
+
const key = adapter.adapterMetadata?.category || 'Default'
|
|
24
|
+
if (!map[key]) {
|
|
25
|
+
map[key] = []
|
|
26
|
+
}
|
|
27
|
+
map[key].push(adapter)
|
|
28
|
+
})
|
|
29
|
+
return map
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const TrackAdapterSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
33
|
+
const { classes } = useStyles()
|
|
34
|
+
const { trackAdapter } = model
|
|
35
|
+
const { pluginManager } = getEnv(model)
|
|
36
|
+
return (
|
|
37
|
+
<TextField
|
|
38
|
+
className={classes.spacing}
|
|
39
|
+
value={trackAdapter?.type !== 'UNKNOWN' ? trackAdapter?.type : ''}
|
|
40
|
+
label="Adapter type"
|
|
41
|
+
variant="outlined"
|
|
42
|
+
helperText="Select an adapter type"
|
|
43
|
+
select
|
|
44
|
+
fullWidth
|
|
45
|
+
onChange={event => model.setAdapterHint(event.target.value)}
|
|
46
|
+
SelectProps={{
|
|
47
|
+
// @ts-ignore
|
|
48
|
+
SelectDisplayProps: { 'data-testid': 'adapterTypeSelect' },
|
|
49
|
+
}}
|
|
50
|
+
>
|
|
51
|
+
{Object.entries(
|
|
52
|
+
categorizeAdapters(
|
|
53
|
+
pluginManager
|
|
54
|
+
.getAdapterElements()
|
|
55
|
+
.filter(e => !e.adapterMetadata?.hiddenFromGUI),
|
|
56
|
+
),
|
|
57
|
+
).map(([key, val]) => {
|
|
58
|
+
// returning array avoids needing to use a react fragment which
|
|
59
|
+
// Select/TextField sub-elements disagree with
|
|
60
|
+
return [
|
|
61
|
+
<ListSubheader>{key}</ListSubheader>,
|
|
62
|
+
val.map(elt => (
|
|
63
|
+
<MenuItem key={elt.name} value={elt.name}>
|
|
64
|
+
{elt.displayName}
|
|
65
|
+
</MenuItem>
|
|
66
|
+
)),
|
|
67
|
+
]
|
|
68
|
+
})}
|
|
69
|
+
</TextField>
|
|
70
|
+
)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export default TrackAdapterSelector
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { MenuItem, TextField } from '@mui/material'
|
|
3
|
+
import { getEnv } from '@jbrowse/core/util'
|
|
4
|
+
import { observer } from 'mobx-react'
|
|
5
|
+
import { makeStyles } from 'tss-react/mui'
|
|
6
|
+
|
|
7
|
+
// locals
|
|
8
|
+
import { AddTrackModel } from '../model'
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles()(theme => ({
|
|
11
|
+
spacing: {
|
|
12
|
+
marginBottom: theme.spacing(3),
|
|
13
|
+
},
|
|
14
|
+
}))
|
|
15
|
+
|
|
16
|
+
const TrackTypeSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
17
|
+
const { classes } = useStyles()
|
|
18
|
+
const { pluginManager } = getEnv(model)
|
|
19
|
+
const { trackType } = model
|
|
20
|
+
const trackTypes = pluginManager.getTrackElements()
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<TextField
|
|
24
|
+
className={classes.spacing}
|
|
25
|
+
value={trackType}
|
|
26
|
+
variant="outlined"
|
|
27
|
+
label="Track type"
|
|
28
|
+
helperText="Select track type"
|
|
29
|
+
select
|
|
30
|
+
fullWidth
|
|
31
|
+
onChange={event => model.setTrackType(event.target.value)}
|
|
32
|
+
SelectProps={{
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
SelectDisplayProps: { 'data-testid': 'trackTypeSelect' },
|
|
35
|
+
}}
|
|
36
|
+
>
|
|
37
|
+
{trackTypes.map(({ name, displayName }) => (
|
|
38
|
+
<MenuItem key={name} value={name}>
|
|
39
|
+
{displayName}
|
|
40
|
+
</MenuItem>
|
|
41
|
+
))}
|
|
42
|
+
</TextField>
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
export default TrackTypeSelector
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, useState, useRef, useEffect } from 'react'
|
|
2
2
|
import { Fab, Menu, MenuItem } from '@mui/material'
|
|
3
3
|
import { makeStyles } from 'tss-react/mui'
|
|
4
|
-
// icons
|
|
5
|
-
import AddIcon from '@mui/icons-material/Add'
|
|
6
|
-
// other
|
|
7
|
-
import AutoSizer from 'react-virtualized-auto-sizer'
|
|
8
4
|
import {
|
|
9
5
|
getSession,
|
|
10
6
|
isSessionModelWithWidgets,
|
|
@@ -13,6 +9,10 @@ import {
|
|
|
13
9
|
} from '@jbrowse/core/util'
|
|
14
10
|
import { observer } from 'mobx-react'
|
|
15
11
|
import { VariableSizeTree } from 'react-vtree'
|
|
12
|
+
import AutoSizer from 'react-virtualized-auto-sizer'
|
|
13
|
+
|
|
14
|
+
// icons
|
|
15
|
+
import AddIcon from '@mui/icons-material/Add'
|
|
16
16
|
|
|
17
17
|
// locals
|
|
18
18
|
import { TreeNode, HierarchicalTrackSelectorModel } from '../model'
|