@jbrowse/plugin-data-management 1.5.0 → 1.5.4
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/model.d.ts +1 -434
- package/dist/AssemblyManager/AssemblyTable.d.ts +8 -2
- package/dist/PluginStoreWidget/components/CustomPluginForm.d.ts +1 -1
- package/dist/PluginStoreWidget/components/PluginCard.d.ts +2 -2
- package/dist/SetDefaultSession/SetDefaultSession.d.ts +4 -6
- package/dist/index.d.ts +8 -12
- package/dist/plugin-data-management.cjs.development.js +387 -324
- package/dist/plugin-data-management.cjs.development.js.map +1 -1
- package/dist/plugin-data-management.cjs.production.min.js +1 -1
- package/dist/plugin-data-management.cjs.production.min.js.map +1 -1
- package/dist/plugin-data-management.esm.js +389 -326
- package/dist/plugin-data-management.esm.js.map +1 -1
- package/package.json +3 -2
- package/src/AddTrackWidget/components/AddTrackWidget.test.js +1 -1
- package/src/AddTrackWidget/components/AddTrackWidget.tsx +3 -1
- package/src/AddTrackWidget/components/ConfirmTrack.tsx +101 -32
- package/src/AddTrackWidget/components/TrackSourceSelect.tsx +2 -3
- package/src/AddTrackWidget/index.test.jsx +34 -15
- package/src/AddTrackWidget/model.ts +5 -14
- package/src/AssemblyManager/AssemblyManager.tsx +3 -1
- package/src/AssemblyManager/AssemblyTable.tsx +40 -39
- package/src/HierarchicalTrackSelectorWidget/model.js +3 -2
- package/src/PluginStoreWidget/components/CustomPluginForm.tsx +164 -56
- package/src/PluginStoreWidget/components/InstalledPlugin.tsx +16 -11
- package/src/PluginStoreWidget/components/PluginCard.tsx +7 -9
- package/src/PluginStoreWidget/components/PluginStoreWidget.test.js +8 -7
- package/src/PluginStoreWidget/components/PluginStoreWidget.tsx +34 -25
- package/src/PluginStoreWidget/components/__snapshots__/PluginStoreWidget.test.js.snap +69 -52
- package/src/SetDefaultSession/SetDefaultSession.test.tsx +6 -81
- package/src/SetDefaultSession/SetDefaultSession.tsx +51 -162
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-data-management",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.4",
|
|
4
4
|
"description": "JBrowse 2 linear genome view",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@gmod/ucsc-hub": "^0.1.3",
|
|
39
39
|
"@material-ui/icons": "^4.9.1",
|
|
40
|
+
"clsx": "^1.1.0",
|
|
40
41
|
"pluralize": "^8.0.0",
|
|
41
42
|
"react-virtualized-auto-sizer": "^1.0.2",
|
|
42
43
|
"react-vtree": "^3.0.0-beta.1",
|
|
@@ -55,5 +56,5 @@
|
|
|
55
56
|
"publishConfig": {
|
|
56
57
|
"access": "public"
|
|
57
58
|
},
|
|
58
|
-
"gitHead": "
|
|
59
|
+
"gitHead": "0c398214590969168694b4ed8e20b595178b9efd"
|
|
59
60
|
}
|
|
@@ -125,7 +125,7 @@ describe('<AddTrackWidget />', () => {
|
|
|
125
125
|
expect(session.sessionTracks.length).toBe(2)
|
|
126
126
|
})
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
xit('fails to add a track', async () => {
|
|
129
129
|
const { getByTestId, getAllByTestId, findByText } = render(
|
|
130
130
|
<AddTrackWidget model={model} />,
|
|
131
131
|
)
|
|
@@ -11,10 +11,12 @@ import {
|
|
|
11
11
|
import { getSession } from '@jbrowse/core/util'
|
|
12
12
|
import { getConf } from '@jbrowse/core/configuration'
|
|
13
13
|
import { observer } from 'mobx-react'
|
|
14
|
+
import { Alert } from '@material-ui/lab'
|
|
15
|
+
|
|
16
|
+
// locals
|
|
14
17
|
import ConfirmTrack from './ConfirmTrack'
|
|
15
18
|
import TrackSourceSelect from './TrackSourceSelect'
|
|
16
19
|
import { AddTrackModel } from '../model'
|
|
17
|
-
import { Alert } from '@material-ui/lab'
|
|
18
20
|
|
|
19
21
|
const useStyles = makeStyles(theme => ({
|
|
20
22
|
root: {
|
|
@@ -1,15 +1,22 @@
|
|
|
1
|
+
import React from 'react'
|
|
1
2
|
import { readConfObject } from '@jbrowse/core/configuration'
|
|
2
3
|
import { getSession } from '@jbrowse/core/util'
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import {
|
|
5
|
+
Link,
|
|
6
|
+
MenuItem,
|
|
7
|
+
TextField,
|
|
8
|
+
ListSubheader,
|
|
9
|
+
Typography,
|
|
10
|
+
makeStyles,
|
|
11
|
+
} from '@material-ui/core'
|
|
12
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
8
13
|
import { observer } from 'mobx-react'
|
|
9
14
|
import { getEnv } from 'mobx-state-tree'
|
|
10
|
-
import React from 'react'
|
|
11
15
|
import { UNKNOWN } from '@jbrowse/core/util/tracks'
|
|
16
|
+
|
|
17
|
+
// locals
|
|
12
18
|
import { AddTrackModel } from '../model'
|
|
19
|
+
import { AdapterMetadata } from '@jbrowse/core/pluggableElementTypes/AdapterType'
|
|
13
20
|
|
|
14
21
|
const useStyles = makeStyles(theme => ({
|
|
15
22
|
spacing: {
|
|
@@ -41,17 +48,68 @@ function StatusMessage({
|
|
|
41
48
|
)
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
/**
|
|
52
|
+
* categorizeAdapters takes a list of adapters and sorts their menu item elements under an appropriate ListSubheader
|
|
53
|
+
* element. In this way, adapters that are from external plugins can have headers that differentiate them from the
|
|
54
|
+
* out-of-the-box plugins.
|
|
55
|
+
* @param adaptersList - a list of adapters found in the PluginManager
|
|
56
|
+
* @returns a series of JSX elements that are ListSubheaders followed by the adapters
|
|
57
|
+
* found under that subheader
|
|
58
|
+
*/
|
|
59
|
+
function categorizeAdapters(
|
|
60
|
+
adaptersList: { name: string; adapterMetadata: AdapterMetadata }[],
|
|
61
|
+
) {
|
|
62
|
+
let currentCategory = ''
|
|
63
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
64
|
+
const items: any = []
|
|
65
|
+
adaptersList.forEach(adapter => {
|
|
66
|
+
if (adapter.adapterMetadata?.category) {
|
|
67
|
+
if (currentCategory !== adapter.adapterMetadata?.category) {
|
|
68
|
+
currentCategory = adapter.adapterMetadata?.category
|
|
69
|
+
items.push(
|
|
70
|
+
<ListSubheader
|
|
71
|
+
key={adapter.adapterMetadata?.category}
|
|
72
|
+
value={adapter.adapterMetadata?.category}
|
|
73
|
+
>
|
|
74
|
+
{adapter.adapterMetadata?.category}
|
|
75
|
+
</ListSubheader>,
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
items.push(
|
|
79
|
+
<MenuItem key={adapter.name} value={adapter.name}>
|
|
80
|
+
{adapter.adapterMetadata?.displayName
|
|
81
|
+
? adapter.adapterMetadata?.displayName
|
|
82
|
+
: adapter.name}
|
|
83
|
+
</MenuItem>,
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
return items
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function getAdapterTypes(pluginManager: PluginManager) {
|
|
91
|
+
return pluginManager.getElementTypesInGroup('adapter') as {
|
|
92
|
+
name: string
|
|
93
|
+
adapterMetadata: AdapterMetadata
|
|
94
|
+
}[]
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function getTrackTypes(pluginManager: PluginManager) {
|
|
98
|
+
return pluginManager.getElementTypesInGroup('track') as { name: string }[]
|
|
99
|
+
}
|
|
100
|
+
|
|
44
101
|
const TrackAdapterSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
45
102
|
const classes = useStyles()
|
|
46
103
|
const session = getSession(model)
|
|
47
104
|
const { trackAdapter } = model
|
|
48
|
-
|
|
105
|
+
// prettier-ignore
|
|
106
|
+
const adapters = getAdapterTypes(getEnv(session).pluginManager)
|
|
49
107
|
return (
|
|
50
108
|
<TextField
|
|
51
109
|
className={classes.spacing}
|
|
52
|
-
value={trackAdapter?.type}
|
|
110
|
+
value={trackAdapter?.type !== 'UNKNOWN' ? trackAdapter?.type : ''}
|
|
53
111
|
label="adapterType"
|
|
54
|
-
helperText="
|
|
112
|
+
helperText="Select an adapter type"
|
|
55
113
|
select
|
|
56
114
|
fullWidth
|
|
57
115
|
onChange={event => model.setAdapterHint(event.target.value)}
|
|
@@ -60,15 +118,24 @@ const TrackAdapterSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
|
60
118
|
SelectDisplayProps: { 'data-testid': 'adapterTypeSelect' },
|
|
61
119
|
}}
|
|
62
120
|
>
|
|
63
|
-
{
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
121
|
+
{adapters
|
|
122
|
+
// Excludes any adapter with the 'adapterMetadata.hiddenFromGUI' property, and anything with the 'adapterMetadata.category' property
|
|
123
|
+
.filter(
|
|
124
|
+
elt =>
|
|
125
|
+
!elt.adapterMetadata?.hiddenFromGUI &&
|
|
126
|
+
!elt.adapterMetadata?.category,
|
|
127
|
+
)
|
|
128
|
+
.map(elt => (
|
|
68
129
|
<MenuItem key={elt.name} value={elt.name}>
|
|
69
|
-
{elt.
|
|
130
|
+
{elt.adapterMetadata?.displayName
|
|
131
|
+
? elt.adapterMetadata?.displayName
|
|
132
|
+
: elt.name}
|
|
70
133
|
</MenuItem>
|
|
71
134
|
))}
|
|
135
|
+
{/* adapters with the 'adapterMetadata.category' property are categorized by the value of the property here */}
|
|
136
|
+
{categorizeAdapters(
|
|
137
|
+
adapters.filter(elt => !elt.adapterMetadata?.hiddenFromGUI),
|
|
138
|
+
)}
|
|
72
139
|
</TextField>
|
|
73
140
|
)
|
|
74
141
|
})
|
|
@@ -78,8 +145,8 @@ function UnknownAdapterPrompt({ model }: { model: AddTrackModel }) {
|
|
|
78
145
|
return (
|
|
79
146
|
<>
|
|
80
147
|
<Typography className={classes.spacing}>
|
|
81
|
-
|
|
82
|
-
the list below. If not, you can{' '}
|
|
148
|
+
JBrowse was not able to guess the adapter type for this data, but it may
|
|
149
|
+
be in the list below. If not, you can{' '}
|
|
83
150
|
<Link
|
|
84
151
|
href="https://github.com/GMOD/jbrowse-components/releases"
|
|
85
152
|
target="_blank"
|
|
@@ -106,13 +173,14 @@ const TrackTypeSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
|
106
173
|
const classes = useStyles()
|
|
107
174
|
const session = getSession(model)
|
|
108
175
|
const { trackType } = model
|
|
176
|
+
const trackTypes = getTrackTypes(getEnv(session).pluginManager)
|
|
109
177
|
|
|
110
178
|
return (
|
|
111
179
|
<TextField
|
|
112
180
|
className={classes.spacing}
|
|
113
181
|
value={trackType}
|
|
114
182
|
label="trackType"
|
|
115
|
-
helperText="
|
|
183
|
+
helperText="Select a track type"
|
|
116
184
|
select
|
|
117
185
|
fullWidth
|
|
118
186
|
onChange={event => {
|
|
@@ -123,14 +191,11 @@ const TrackTypeSelector = observer(({ model }: { model: AddTrackModel }) => {
|
|
|
123
191
|
SelectDisplayProps: { 'data-testid': 'trackTypeSelect' },
|
|
124
192
|
}}
|
|
125
193
|
>
|
|
126
|
-
{
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
{name}
|
|
132
|
-
</MenuItem>
|
|
133
|
-
))}
|
|
194
|
+
{trackTypes.map(({ name }) => (
|
|
195
|
+
<MenuItem key={name} value={name}>
|
|
196
|
+
{name}
|
|
197
|
+
</MenuItem>
|
|
198
|
+
))}
|
|
134
199
|
</TextField>
|
|
135
200
|
)
|
|
136
201
|
})
|
|
@@ -152,14 +217,13 @@ const TrackAssemblySelector = observer(
|
|
|
152
217
|
SelectDisplayProps: { 'data-testid': 'assemblyNameSelect' },
|
|
153
218
|
}}
|
|
154
219
|
>
|
|
155
|
-
{session.assemblies
|
|
156
|
-
|
|
157
|
-
|
|
220
|
+
{session.assemblies
|
|
221
|
+
.map(conf => readConfObject(conf, 'name'))
|
|
222
|
+
.map(name => (
|
|
158
223
|
<MenuItem key={name} value={name}>
|
|
159
224
|
{name}
|
|
160
225
|
</MenuItem>
|
|
161
|
-
)
|
|
162
|
-
})}
|
|
226
|
+
))}
|
|
163
227
|
</TextField>
|
|
164
228
|
)
|
|
165
229
|
},
|
|
@@ -167,7 +231,8 @@ const TrackAssemblySelector = observer(
|
|
|
167
231
|
|
|
168
232
|
function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
169
233
|
const classes = useStyles()
|
|
170
|
-
const { trackName, trackAdapter, trackType, warningMessage } =
|
|
234
|
+
const { trackName, trackAdapter, trackType, warningMessage, adapterHint } =
|
|
235
|
+
model
|
|
171
236
|
|
|
172
237
|
if (model.unsupported) {
|
|
173
238
|
return (
|
|
@@ -198,6 +263,10 @@ function ConfirmTrack({ model }: { model: AddTrackModel }) {
|
|
|
198
263
|
return <UnknownAdapterPrompt model={model} />
|
|
199
264
|
}
|
|
200
265
|
|
|
266
|
+
if (adapterHint === '' && trackAdapter) {
|
|
267
|
+
model.setAdapterHint(trackAdapter.type)
|
|
268
|
+
}
|
|
269
|
+
|
|
201
270
|
if (!trackAdapter?.type) {
|
|
202
271
|
return <Typography>Could not recognize this data type.</Typography>
|
|
203
272
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { FileSelector } from '@jbrowse/core/ui'
|
|
2
|
-
import Paper from '@material-ui/core/Paper'
|
|
3
|
-
import { makeStyles } from '@material-ui/core/styles'
|
|
4
1
|
import React from 'react'
|
|
2
|
+
import { FileSelector } from '@jbrowse/core/ui'
|
|
3
|
+
import { Paper, makeStyles } from '@material-ui/core'
|
|
5
4
|
import { AddTrackModel } from '../model'
|
|
6
5
|
import { getRoot } from 'mobx-state-tree'
|
|
7
6
|
import { observer } from 'mobx-react'
|
|
@@ -4,32 +4,51 @@ import PluginManager from '@jbrowse/core/PluginManager'
|
|
|
4
4
|
import Plugin from '@jbrowse/core/Plugin'
|
|
5
5
|
import ViewType from '@jbrowse/core/pluggableElementTypes/ViewType'
|
|
6
6
|
import stateModelFactory from './model'
|
|
7
|
+
import Alignments from '@jbrowse/plugin-alignments'
|
|
8
|
+
import SVG from '@jbrowse/plugin-svg'
|
|
9
|
+
import Variants from '@jbrowse/plugin-variants'
|
|
10
|
+
import Hic from '@jbrowse/plugin-hic'
|
|
7
11
|
|
|
8
12
|
function standardInitializer() {
|
|
9
|
-
const pluginManager = new PluginManager([
|
|
13
|
+
const pluginManager = new PluginManager([
|
|
14
|
+
new FakeViewPlugin(),
|
|
15
|
+
new Alignments(),
|
|
16
|
+
new SVG(),
|
|
17
|
+
new Variants(),
|
|
18
|
+
new Hic(),
|
|
19
|
+
])
|
|
10
20
|
pluginManager.createPluggableElements()
|
|
11
21
|
pluginManager.configure()
|
|
12
22
|
|
|
13
|
-
const SessionModel = types
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
const SessionModel = types
|
|
24
|
+
.model({
|
|
25
|
+
view: FakeViewModel,
|
|
26
|
+
widget: stateModelFactory(pluginManager),
|
|
27
|
+
})
|
|
28
|
+
.volatile(() => ({
|
|
29
|
+
rpcManager: {},
|
|
30
|
+
configuration: {},
|
|
31
|
+
}))
|
|
17
32
|
|
|
18
33
|
// assemblyNames is defined on the view, which is done in LGV for example
|
|
19
34
|
// this is really just used for convenience to automatically fill in the
|
|
20
35
|
// assembly field in the form
|
|
21
|
-
return SessionModel.create(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
return SessionModel.create(
|
|
37
|
+
{
|
|
38
|
+
view: {
|
|
39
|
+
id: 'testing',
|
|
40
|
+
type: 'FakeView',
|
|
41
|
+
assemblyNames: ['volvox'],
|
|
42
|
+
},
|
|
43
|
+
widget: {
|
|
44
|
+
type: 'AddTrackWidget',
|
|
45
|
+
view: 'testing',
|
|
46
|
+
},
|
|
30
47
|
},
|
|
31
|
-
|
|
48
|
+
{ pluginManager },
|
|
49
|
+
)
|
|
32
50
|
}
|
|
51
|
+
|
|
33
52
|
const realLocation = window.location
|
|
34
53
|
|
|
35
54
|
// https://stackoverflow.com/a/60110508/2129219
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
guessAdapter,
|
|
7
7
|
guessTrackType,
|
|
8
8
|
UNSUPPORTED,
|
|
9
|
+
getFileName,
|
|
9
10
|
} from '@jbrowse/core/util/tracks'
|
|
10
11
|
|
|
11
12
|
function isAbsoluteUrl(url = '') {
|
|
@@ -17,18 +18,6 @@ function isAbsoluteUrl(url = '') {
|
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
function getFileName(track: FileLocation) {
|
|
21
|
-
const uri = 'uri' in track ? track.uri : undefined
|
|
22
|
-
const localPath = 'localPath' in track ? track.localPath : undefined
|
|
23
|
-
const blob = 'blobId' in track ? track : undefined
|
|
24
|
-
return (
|
|
25
|
-
blob?.name ||
|
|
26
|
-
uri?.slice(uri.lastIndexOf('/') + 1) ||
|
|
27
|
-
localPath?.slice(localPath.lastIndexOf('/') + 1) ||
|
|
28
|
-
''
|
|
29
|
-
)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
21
|
export default function f(pluginManager: PluginManager) {
|
|
33
22
|
return types
|
|
34
23
|
.model('AddTrackModel', {
|
|
@@ -88,7 +77,7 @@ export default function f(pluginManager: PluginManager) {
|
|
|
88
77
|
const { trackData, indexTrackData, adapterHint } = self
|
|
89
78
|
|
|
90
79
|
return trackData
|
|
91
|
-
? guessAdapter(trackData, indexTrackData,
|
|
80
|
+
? guessAdapter(trackData, indexTrackData, adapterHint, self)
|
|
92
81
|
: undefined
|
|
93
82
|
},
|
|
94
83
|
|
|
@@ -148,7 +137,9 @@ export default function f(pluginManager: PluginManager) {
|
|
|
148
137
|
get trackType() {
|
|
149
138
|
return (
|
|
150
139
|
self.altTrackType ||
|
|
151
|
-
(this.trackAdapter
|
|
140
|
+
(this.trackAdapter
|
|
141
|
+
? guessTrackType(this.trackAdapter.type, self)
|
|
142
|
+
: '')
|
|
152
143
|
)
|
|
153
144
|
},
|
|
154
145
|
}))
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState } from 'react'
|
|
2
2
|
import { observer } from 'mobx-react'
|
|
3
3
|
import { makeStyles } from '@material-ui/core/styles'
|
|
4
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration/configurationSchema'
|
|
4
5
|
import {
|
|
5
6
|
Button,
|
|
6
7
|
Dialog,
|
|
@@ -52,7 +53,8 @@ const AssemblyManager = observer(
|
|
|
52
53
|
const classes = useStyles()
|
|
53
54
|
const [isFormOpen, setFormOpen] = useState(false)
|
|
54
55
|
const [isAssemblyBeingEdited, setIsAssemblyBeingEdited] = useState(false)
|
|
55
|
-
const [assemblyBeingEdited, setAssemblyBeingEdited] =
|
|
56
|
+
const [assemblyBeingEdited, setAssemblyBeingEdited] =
|
|
57
|
+
useState<AnyConfigurationModel>()
|
|
56
58
|
|
|
57
59
|
const showAssemblyTable = !isFormOpen && !isAssemblyBeingEdited
|
|
58
60
|
|
|
@@ -42,11 +42,14 @@ const AssemblyTable = observer(
|
|
|
42
42
|
setIsAssemblyBeingEdited,
|
|
43
43
|
setAssemblyBeingEdited,
|
|
44
44
|
}: {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
rootModel: {
|
|
46
|
+
jbrowse: {
|
|
47
|
+
removeAssemblyConf: (arg: string) => void
|
|
48
|
+
assemblies: AnyConfigurationModel[]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
47
51
|
setIsAssemblyBeingEdited(arg: boolean): void
|
|
48
|
-
|
|
49
|
-
setAssemblyBeingEdited(arg: any): void
|
|
52
|
+
setAssemblyBeingEdited(arg: AnyConfigurationModel): void
|
|
50
53
|
}) => {
|
|
51
54
|
const classes = useStyles()
|
|
52
55
|
|
|
@@ -54,41 +57,39 @@ const AssemblyTable = observer(
|
|
|
54
57
|
rootModel.jbrowse.removeAssemblyConf(name)
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
const rows = rootModel.jbrowse.assemblies.map(
|
|
58
|
-
(assembly
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
},
|
|
91
|
-
)
|
|
60
|
+
const rows = rootModel.jbrowse.assemblies.map(assembly => {
|
|
61
|
+
const name = readConfObject(assembly, 'name')
|
|
62
|
+
const displayName = readConfObject(assembly, 'displayName')
|
|
63
|
+
const aliases = readConfObject(assembly, 'aliases')
|
|
64
|
+
return (
|
|
65
|
+
<TableRow key={name}>
|
|
66
|
+
<TableCell>{name}</TableCell>
|
|
67
|
+
<TableCell>{displayName}</TableCell>
|
|
68
|
+
<TableCell>{aliases ? aliases.toString() : ''}</TableCell>
|
|
69
|
+
<TableCell className={classes.buttonCell}>
|
|
70
|
+
<IconButton
|
|
71
|
+
data-testid={`${name}-edit`}
|
|
72
|
+
className={classes.button}
|
|
73
|
+
onClick={() => {
|
|
74
|
+
setIsAssemblyBeingEdited(true)
|
|
75
|
+
setAssemblyBeingEdited(assembly)
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
<CreateIcon color="primary" />
|
|
79
|
+
</IconButton>
|
|
80
|
+
<IconButton
|
|
81
|
+
data-testid={`${name}-delete`}
|
|
82
|
+
className={classes.button}
|
|
83
|
+
onClick={() => {
|
|
84
|
+
removeAssembly(name)
|
|
85
|
+
}}
|
|
86
|
+
>
|
|
87
|
+
<DeleteIcon color="error" />
|
|
88
|
+
</IconButton>
|
|
89
|
+
</TableCell>
|
|
90
|
+
</TableRow>
|
|
91
|
+
)
|
|
92
|
+
})
|
|
92
93
|
|
|
93
94
|
return (
|
|
94
95
|
<TableContainer component={Paper}>
|
|
@@ -9,9 +9,10 @@ const hasAnyOverlap = (a1 = [], a2 = []) =>
|
|
|
9
9
|
function passesFilter(filter, config) {
|
|
10
10
|
const name = getTrackName(config)
|
|
11
11
|
const categories = readConfObject(config, 'category') || []
|
|
12
|
-
const
|
|
12
|
+
const filterLower = filter.toLowerCase()
|
|
13
13
|
return (
|
|
14
|
-
!!name.
|
|
14
|
+
!!name.toLowerCase().includes(filterLower) ||
|
|
15
|
+
categories.filter(cat => !!cat.toLowerCase().includes(filterLower)).length
|
|
15
16
|
)
|
|
16
17
|
}
|
|
17
18
|
|