@jbrowse/plugin-data-management 2.2.1 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/AddTrackWidget/components/AddTrackWidget.js +28 -5
  2. package/dist/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
  3. package/dist/AddTrackWidget/components/ConfirmTrack.d.ts +2 -3
  4. package/dist/AddTrackWidget/components/ConfirmTrack.js +30 -177
  5. package/dist/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
  6. package/dist/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -1
  7. package/dist/AddTrackWidget/components/TextIndexingConfig.d.ts +6 -0
  8. package/dist/AddTrackWidget/components/TextIndexingConfig.js +109 -0
  9. package/dist/AddTrackWidget/components/TextIndexingConfig.js.map +1 -0
  10. package/dist/AddTrackWidget/components/TrackAdapterSelector.d.ts +6 -0
  11. package/dist/AddTrackWidget/components/TrackAdapterSelector.js +50 -0
  12. package/dist/AddTrackWidget/components/TrackAdapterSelector.js.map +1 -0
  13. package/dist/AddTrackWidget/components/TrackTypeSelector.d.ts +6 -0
  14. package/dist/AddTrackWidget/components/TrackTypeSelector.js +27 -0
  15. package/dist/AddTrackWidget/components/TrackTypeSelector.js.map +1 -0
  16. package/dist/AssemblyManager/AssemblyAddForm.js +14 -41
  17. package/dist/AssemblyManager/AssemblyAddForm.js.map +1 -1
  18. package/dist/AssemblyManager/AssemblyEditor.js +2 -1
  19. package/dist/AssemblyManager/AssemblyEditor.js.map +1 -1
  20. package/dist/AssemblyManager/AssemblyManager.js +14 -54
  21. package/dist/AssemblyManager/AssemblyManager.js.map +1 -1
  22. package/dist/AssemblyManager/AssemblyTable.js +24 -47
  23. package/dist/AssemblyManager/AssemblyTable.js.map +1 -1
  24. package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +3 -4
  25. package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
  26. package/dist/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js +4 -12
  27. package/dist/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js.map +1 -1
  28. package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +5 -13
  29. package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js.map +1 -1
  30. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +2 -1
  31. package/dist/HierarchicalTrackSelectorWidget/model.js +6 -6
  32. package/dist/HierarchicalTrackSelectorWidget/model.js.map +1 -1
  33. package/dist/PluginStoreWidget/components/CustomPluginForm.js +1 -11
  34. package/dist/PluginStoreWidget/components/CustomPluginForm.js.map +1 -1
  35. package/dist/PluginStoreWidget/components/PluginStoreWidget.js.map +1 -1
  36. package/dist/ucsc-trackhub/index.d.ts +2 -2
  37. package/dist/ucsc-trackhub/index.js.map +1 -1
  38. package/dist/ucsc-trackhub/model.d.ts +3 -2
  39. package/dist/ucsc-trackhub/model.js +41 -40
  40. package/dist/ucsc-trackhub/model.js.map +1 -1
  41. package/dist/ucsc-trackhub/ucscAssemblies.js.map +1 -1
  42. package/esm/AddTrackWidget/components/AddTrackWidget.js +6 -6
  43. package/esm/AddTrackWidget/components/AddTrackWidget.js.map +1 -1
  44. package/esm/AddTrackWidget/components/ConfirmTrack.d.ts +2 -3
  45. package/esm/AddTrackWidget/components/ConfirmTrack.js +28 -175
  46. package/esm/AddTrackWidget/components/ConfirmTrack.js.map +1 -1
  47. package/esm/AddTrackWidget/components/DefaultAddTrackWorkflow.js.map +1 -1
  48. package/esm/AddTrackWidget/components/TextIndexingConfig.d.ts +6 -0
  49. package/esm/AddTrackWidget/components/TextIndexingConfig.js +81 -0
  50. package/esm/AddTrackWidget/components/TextIndexingConfig.js.map +1 -0
  51. package/esm/AddTrackWidget/components/TrackAdapterSelector.d.ts +6 -0
  52. package/esm/AddTrackWidget/components/TrackAdapterSelector.js +45 -0
  53. package/esm/AddTrackWidget/components/TrackAdapterSelector.js.map +1 -0
  54. package/esm/AddTrackWidget/components/TrackTypeSelector.d.ts +6 -0
  55. package/esm/AddTrackWidget/components/TrackTypeSelector.js +22 -0
  56. package/esm/AddTrackWidget/components/TrackTypeSelector.js.map +1 -0
  57. package/esm/AssemblyManager/AssemblyAddForm.js +9 -36
  58. package/esm/AssemblyManager/AssemblyAddForm.js.map +1 -1
  59. package/esm/AssemblyManager/AssemblyEditor.js +2 -1
  60. package/esm/AssemblyManager/AssemblyEditor.js.map +1 -1
  61. package/esm/AssemblyManager/AssemblyManager.js +15 -55
  62. package/esm/AssemblyManager/AssemblyManager.js.map +1 -1
  63. package/esm/AssemblyManager/AssemblyTable.js +25 -48
  64. package/esm/AssemblyManager/AssemblyTable.js.map +1 -1
  65. package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +3 -4
  66. package/esm/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js.map +1 -1
  67. package/esm/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js +5 -13
  68. package/esm/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.js.map +1 -1
  69. package/esm/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +6 -14
  70. package/esm/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js.map +1 -1
  71. package/esm/HierarchicalTrackSelectorWidget/model.d.ts +2 -1
  72. package/esm/HierarchicalTrackSelectorWidget/model.js +7 -7
  73. package/esm/HierarchicalTrackSelectorWidget/model.js.map +1 -1
  74. package/esm/PluginStoreWidget/components/CustomPluginForm.js +2 -12
  75. package/esm/PluginStoreWidget/components/CustomPluginForm.js.map +1 -1
  76. package/esm/PluginStoreWidget/components/PluginStoreWidget.js.map +1 -1
  77. package/esm/ucsc-trackhub/index.d.ts +2 -2
  78. package/esm/ucsc-trackhub/index.js.map +1 -1
  79. package/esm/ucsc-trackhub/model.d.ts +3 -2
  80. package/esm/ucsc-trackhub/model.js +41 -40
  81. package/esm/ucsc-trackhub/model.js.map +1 -1
  82. package/esm/ucsc-trackhub/ucscAssemblies.js.map +1 -1
  83. package/package.json +4 -5
  84. package/src/AddTrackWidget/components/AddTrackWidget.test.tsx +3 -4
  85. package/src/AddTrackWidget/components/AddTrackWidget.tsx +6 -9
  86. package/src/AddTrackWidget/components/ConfirmTrack.tsx +36 -296
  87. package/src/AddTrackWidget/components/DefaultAddTrackWorkflow.tsx +0 -1
  88. package/src/AddTrackWidget/components/TextIndexingConfig.tsx +134 -0
  89. package/src/AddTrackWidget/components/TrackAdapterSelector.tsx +73 -0
  90. package/src/AddTrackWidget/components/TrackTypeSelector.tsx +46 -0
  91. package/src/AssemblyManager/AssemblyAddForm.tsx +147 -182
  92. package/src/AssemblyManager/AssemblyEditor.tsx +5 -1
  93. package/src/AssemblyManager/AssemblyManager.test.tsx +1 -1
  94. package/src/AssemblyManager/AssemblyManager.tsx +70 -137
  95. package/src/AssemblyManager/AssemblyTable.tsx +65 -97
  96. package/src/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.tsx +4 -4
  97. package/src/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.tsx +5 -20
  98. package/src/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.tsx +12 -22
  99. package/src/HierarchicalTrackSelectorWidget/components/__snapshots__/HierarchicalTrackSelector.test.tsx.snap +1 -1
  100. package/src/HierarchicalTrackSelectorWidget/model.ts +14 -9
  101. package/src/PluginStoreWidget/components/CustomPluginForm.tsx +1 -18
  102. package/src/PluginStoreWidget/components/PluginStoreWidget.tsx +1 -0
  103. package/src/PluginStoreWidget/components/__snapshots__/PluginStoreWidget.test.js.snap +0 -22
  104. package/src/ucsc-trackhub/{index.js → index.ts} +0 -0
  105. package/src/ucsc-trackhub/model.ts +119 -0
  106. package/src/ucsc-trackhub/{ucscAssemblies.js → ucscAssemblies.ts} +0 -0
  107. package/src/ucsc-trackhub/model.js +0 -125
@@ -9,112 +9,80 @@ import {
9
9
  TableHead,
10
10
  TableRow,
11
11
  Paper,
12
- Typography,
13
12
  } from '@mui/material'
14
- import { makeStyles } from 'tss-react/mui'
15
-
16
- import CreateIcon from '@mui/icons-material/Create'
17
- import DeleteIcon from '@mui/icons-material/Delete'
18
13
  import {
19
14
  readConfObject,
20
15
  AnyConfigurationModel,
21
16
  } from '@jbrowse/core/configuration'
22
17
 
23
- const useStyles = makeStyles()(() => ({
24
- table: {
25
- minWidth: 500,
26
- minHeight: 150,
27
- },
28
- buttonCell: {
29
- padding: 3,
30
- },
31
- button: {
32
- display: 'inline-block',
33
- padding: 3,
34
- minHeight: 0,
35
- minWidth: 0,
36
- },
37
- }))
38
-
39
- const AssemblyTable = observer(
40
- ({
41
- rootModel,
42
- setIsAssemblyBeingEdited,
43
- setAssemblyBeingEdited,
44
- }: {
45
- rootModel: {
46
- jbrowse: {
47
- removeAssemblyConf: (arg: string) => void
48
- assemblies: AnyConfigurationModel[]
49
- }
50
- }
51
- setIsAssemblyBeingEdited(arg: boolean): void
52
- setAssemblyBeingEdited(arg: AnyConfigurationModel): void
53
- }) => {
54
- const { classes } = useStyles()
18
+ import CreateIcon from '@mui/icons-material/Create'
19
+ import DeleteIcon from '@mui/icons-material/Delete'
55
20
 
56
- function removeAssembly(name: string) {
57
- rootModel.jbrowse.removeAssemblyConf(name)
21
+ const AssemblyTable = observer(function ({
22
+ rootModel,
23
+ setIsAssemblyBeingEdited,
24
+ setAssemblyBeingEdited,
25
+ }: {
26
+ rootModel: {
27
+ jbrowse: {
28
+ removeAssemblyConf: (arg: string) => void
29
+ assemblies: AnyConfigurationModel[]
58
30
  }
31
+ }
32
+ setIsAssemblyBeingEdited(arg: boolean): void
33
+ setAssemblyBeingEdited(arg: AnyConfigurationModel): void
34
+ }) {
35
+ function removeAssembly(name: string) {
36
+ rootModel.jbrowse.removeAssemblyConf(name)
37
+ }
59
38
 
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
- })
39
+ const { assemblies } = rootModel.jbrowse
93
40
 
94
- return (
95
- <TableContainer component={Paper}>
96
- <Table className={classes.table}>
97
- <TableHead>
98
- <TableRow>
99
- <TableCell>
100
- <Typography variant="h5">Name</Typography>
101
- </TableCell>
102
- <TableCell>
103
- <Typography variant="h5">Display name</Typography>
104
- </TableCell>
105
- <TableCell>
106
- <Typography variant="h5">Aliases</Typography>
107
- </TableCell>
108
- <TableCell>
109
- <Typography variant="h5">Actions</Typography>
110
- </TableCell>
111
- </TableRow>
112
- </TableHead>
113
- <TableBody>{rows}</TableBody>
114
- </Table>
115
- </TableContainer>
116
- )
117
- },
118
- )
41
+ return (
42
+ <TableContainer component={Paper}>
43
+ <Table>
44
+ <TableHead>
45
+ <TableRow>
46
+ <TableCell>Name</TableCell>
47
+ <TableCell>Display name</TableCell>
48
+ <TableCell>Aliases</TableCell>
49
+ <TableCell>Actions</TableCell>
50
+ </TableRow>
51
+ </TableHead>
52
+ <TableBody>
53
+ {assemblies.map(assembly => {
54
+ const name = readConfObject(assembly, 'name')
55
+ const displayName = readConfObject(assembly, 'displayName')
56
+ const aliases = readConfObject(assembly, 'aliases')
57
+ return (
58
+ <TableRow key={name}>
59
+ <TableCell>{name}</TableCell>
60
+ <TableCell>{displayName}</TableCell>
61
+ <TableCell>{aliases ? aliases.toString() : ''}</TableCell>
62
+ <TableCell>
63
+ <IconButton
64
+ data-testid={`${name}-edit`}
65
+ onClick={() => {
66
+ setIsAssemblyBeingEdited(true)
67
+ setAssemblyBeingEdited(assembly)
68
+ }}
69
+ >
70
+ <CreateIcon color="primary" />
71
+ </IconButton>
72
+ <IconButton
73
+ data-testid={`${name}-delete`}
74
+ onClick={() => removeAssembly(name)}
75
+ >
76
+ <DeleteIcon color="error" />
77
+ </IconButton>
78
+ </TableCell>
79
+ </TableRow>
80
+ )
81
+ })}
82
+ </TableBody>
83
+ </Table>
84
+ </TableContainer>
85
+ )
86
+ })
119
87
 
120
88
  export default AssemblyTable
@@ -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'
@@ -1,16 +1,14 @@
1
1
  import React from 'react'
2
2
  import {
3
3
  Button,
4
- Dialog,
5
- DialogTitle,
6
4
  DialogContent,
7
5
  DialogActions,
8
6
  IconButton,
9
7
  Tooltip,
10
8
  Typography,
11
9
  } from '@mui/material'
10
+ import { Dialog } from '@jbrowse/core/ui'
12
11
  import { makeStyles } from 'tss-react/mui'
13
- import CloseIcon from '@mui/icons-material/Close'
14
12
  import { observer } from 'mobx-react'
15
13
  import {
16
14
  AnyConfigurationModel,
@@ -18,14 +16,10 @@ import {
18
16
  } from '@jbrowse/core/configuration'
19
17
  import { AbstractSessionModel } from '@jbrowse/core/util'
20
18
 
21
- const useStyles = makeStyles()(theme => ({
22
- closeButton: {
23
- position: 'absolute',
24
- right: theme.spacing(1),
25
- top: theme.spacing(1),
26
- color: theme.palette.grey[500],
27
- },
19
+ // icons
20
+ import CloseIcon from '@mui/icons-material/Close'
28
21
 
22
+ const useStyles = makeStyles()(theme => ({
29
23
  connectionContainer: {
30
24
  margin: theme.spacing(4),
31
25
  width: 500,
@@ -44,16 +38,7 @@ function ManageConnectionsDlg({
44
38
  const { classes } = useStyles()
45
39
  const { adminMode, connections, sessionConnections } = session
46
40
  return (
47
- <Dialog open onClose={handleClose} maxWidth="lg">
48
- <DialogTitle>
49
- Delete connections
50
- <IconButton
51
- className={classes.closeButton}
52
- onClick={() => handleClose()}
53
- >
54
- <CloseIcon />
55
- </IconButton>
56
- </DialogTitle>
41
+ <Dialog open onClose={handleClose} maxWidth="lg" title="Delete connections">
57
42
  <DialogContent>
58
43
  <Typography>
59
44
  Click the X icon to delete the connection from your config completely
@@ -2,16 +2,13 @@ import React from 'react'
2
2
  import {
3
3
  Button,
4
4
  Checkbox,
5
- Dialog,
6
- DialogTitle,
7
5
  DialogContent,
8
6
  DialogActions,
9
7
  FormControlLabel,
10
- IconButton,
11
8
  Typography,
12
9
  } from '@mui/material'
10
+ import { Dialog } from '@jbrowse/core/ui'
13
11
  import { makeStyles } from 'tss-react/mui'
14
- import CloseIcon from '@mui/icons-material/Close'
15
12
  import { observer } from 'mobx-react'
16
13
  import {
17
14
  AnyConfigurationModel,
@@ -24,13 +21,6 @@ export function ellipses(slug: string) {
24
21
  }
25
22
 
26
23
  const useStyles = makeStyles()(theme => ({
27
- closeButton: {
28
- position: 'absolute',
29
- right: theme.spacing(1),
30
- top: theme.spacing(1),
31
- color: theme.palette.grey[500],
32
- },
33
-
34
24
  connectionContainer: {
35
25
  width: 500,
36
26
  margin: theme.spacing(4),
@@ -49,16 +39,12 @@ function ToggleConnectionDialog({
49
39
  const { classes } = useStyles()
50
40
  const { connections, connectionInstances: instances = [] } = session
51
41
  return (
52
- <Dialog open onClose={handleClose} maxWidth="lg">
53
- <DialogTitle>
54
- Turn on/off connections
55
- <IconButton
56
- className={classes.closeButton}
57
- onClick={() => handleClose()}
58
- >
59
- <CloseIcon />
60
- </IconButton>
61
- </DialogTitle>
42
+ <Dialog
43
+ open
44
+ onClose={handleClose}
45
+ maxWidth="lg"
46
+ title="Turn on/off connections"
47
+ >
62
48
  <DialogContent>
63
49
  <Typography>Use the checkbox to turn on/off connections</Typography>
64
50
  <div className={classes.connectionContainer}>
@@ -82,7 +68,11 @@ function ToggleConnectionDialog({
82
68
  color="primary"
83
69
  />
84
70
  }
85
- label={`${name} (${ellipses(assemblyNames.join(','))})`}
71
+ label={`${name} ${
72
+ assemblyNames.length
73
+ ? '(' + ellipses(assemblyNames.join(',')) + ')'
74
+ : ''
75
+ }`}
86
76
  />
87
77
  )
88
78
  })}
@@ -2,7 +2,7 @@
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-sizeSmall MuiFab-secondary MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-secondary css-tbl9bo-MuiButtonBase-root-MuiFab-root-fab"
5
+ class="MuiButtonBase-root MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-secondary MuiFab-root MuiFab-circular MuiFab-sizeSmall MuiFab-secondary css-15opis6-MuiButtonBase-root-MuiFab-root-fab"
6
6
  tabindex="0"
7
7
  type="button"
8
8
  >
@@ -4,7 +4,12 @@ import {
4
4
  readConfObject,
5
5
  AnyConfigurationModel,
6
6
  } from '@jbrowse/core/configuration'
7
- import { AbstractSessionModel, getSession, getEnv } from '@jbrowse/core/util'
7
+ import {
8
+ AbstractSessionModel,
9
+ dedupe,
10
+ getSession,
11
+ getEnv,
12
+ } from '@jbrowse/core/util'
8
13
  import { getTrackName } from '@jbrowse/core/util/tracks'
9
14
  import { ElementId } from '@jbrowse/core/util/types/mst'
10
15
  import PluginManager from '@jbrowse/core/PluginManager'
@@ -62,6 +67,7 @@ export function generateHierarchy(
62
67
  model: HierarchicalTrackSelectorModel,
63
68
  trackConfigurations: AnyConfigurationModel[],
64
69
  collapsed: { get: (arg: string) => boolean | undefined },
70
+ extra?: string,
65
71
  ) {
66
72
  const hierarchy = { children: [] as TreeNode[] } as TreeNode
67
73
  const { filterText, view } = model
@@ -86,7 +92,7 @@ export function generateHierarchy(
86
92
  for (let i = 0; i < categories.length; i++) {
87
93
  const category = categories[i]
88
94
  const ret = currLevel.children.find(c => c.name === category)
89
- const id = categories.slice(0, i + 1).join(',')
95
+ const id = extra + '-' + categories.slice(0, i + 1).join(',')
90
96
  if (!ret) {
91
97
  const n = {
92
98
  children: [],
@@ -135,7 +141,7 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
135
141
  }))
136
142
  .actions(self => ({
137
143
  addToSelection(elt: AnyConfigurationModel[]) {
138
- self.selection = [...self.selection, ...elt]
144
+ self.selection = dedupe([...self.selection, ...elt], e => e.trackId)
139
145
  },
140
146
  removeFromSelection(elt: AnyConfigurationModel[]) {
141
147
  self.selection = self.selection.filter(f => !elt.includes(f))
@@ -223,10 +229,7 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
223
229
  const conns =
224
230
  (assembly &&
225
231
  connectionInstances
226
- ?.filter(c =>
227
- hasAnyOverlap(assembly.allAliases, getConf(c, 'assemblyNames')),
228
- )
229
- .map(c => ({
232
+ ?.map(c => ({
230
233
  // @ts-ignore
231
234
  id: getSnapshot(c).configuration,
232
235
  name: getConf(c, 'name'),
@@ -234,7 +237,8 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
234
237
  state: {
235
238
  expanded: true,
236
239
  },
237
- }))) ||
240
+ }))
241
+ .filter(f => f.children.length)) ||
238
242
  []
239
243
 
240
244
  return {
@@ -249,13 +253,14 @@ export default function stateTreeFactory(pluginManager: PluginManager) {
249
253
 
250
254
  connectionHierarchy(
251
255
  assemblyName: string,
252
- connection: { tracks: AnyConfigurationModel[] },
256
+ connection: { name: string; tracks: AnyConfigurationModel[] },
253
257
  ) {
254
258
  return generateHierarchy(
255
259
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
256
260
  self as any,
257
261
  self.connectionTrackConfigurations(assemblyName, connection),
258
262
  self.collapsed,
263
+ connection.name,
259
264
  )
260
265
  },
261
266
  }))
@@ -7,7 +7,6 @@ import {
7
7
  Collapse,
8
8
  Dialog,
9
9
  DialogActions,
10
- DialogTitle,
11
10
  DialogContent,
12
11
  DialogContentText,
13
12
  TextField,
@@ -16,18 +15,12 @@ import { makeStyles } from 'tss-react/mui'
16
15
 
17
16
  // icons
18
17
  import IconButton from '@mui/material/IconButton'
19
- import CloseIcon from '@mui/icons-material/Close'
20
18
  import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
21
19
 
22
20
  // locals
23
21
  import { PluginStoreModel } from '../model'
24
22
 
25
23
  const useStyles = makeStyles()(theme => ({
26
- closeButton: {
27
- position: 'absolute',
28
- right: theme.spacing(1),
29
- top: theme.spacing(1),
30
- },
31
24
  dialogContent: {
32
25
  display: 'flex',
33
26
  flexDirection: 'column',
@@ -114,17 +107,7 @@ function CustomPluginForm({
114
107
  }
115
108
 
116
109
  return (
117
- <Dialog open={open} onClose={handleClose}>
118
- <DialogTitle>
119
- Add custom plugin
120
- <IconButton
121
- size="medium"
122
- className={classes.closeButton}
123
- onClick={() => onClose()}
124
- >
125
- <CloseIcon />
126
- </IconButton>
127
- </DialogTitle>
110
+ <Dialog open={open} onClose={handleClose} title="Add custom plugin">
128
111
  <form onSubmit={handleSubmit}>
129
112
  <DialogContent className={classes.dialogContent}>
130
113
  <DialogContentText>
@@ -61,6 +61,7 @@ function PluginStoreWidget({ model }: { model: PluginStoreModel }) {
61
61
  const controller = new AbortController()
62
62
  const { signal } = controller
63
63
 
64
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
64
65
  ;(async () => {
65
66
  try {
66
67
  const response = await fetch(
@@ -501,28 +501,6 @@ exports[`<PluginStoreWidget /> renders with the available plugins 1`] = `
501
501
  SequencePlugin
502
502
  </p>
503
503
  </li>
504
- <li
505
- class="MuiListItem-root MuiListItem-dense MuiListItem-gutters MuiListItem-padding css-ypie1g-MuiListItem-root"
506
- >
507
- <svg
508
- aria-hidden="true"
509
- aria-label="This plugin was installed by an administrator, you cannot remove it."
510
- class="MuiSvgIcon-root MuiSvgIcon-fontSizeMedium css-1a34d00-MuiSvgIcon-root-lockedPluginTooltip"
511
- data-mui-internal-clone-element="true"
512
- data-testid="LockIcon"
513
- focusable="false"
514
- viewBox="0 0 24 24"
515
- >
516
- <path
517
- d="M18 8h-1V6c0-2.76-2.24-5-5-5S7 3.24 7 6v2H6c-1.1 0-2 .9-2 2v10c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V10c0-1.1-.9-2-2-2zm-6 9c-1.1 0-2-.9-2-2s.9-2 2-2 2 .9 2 2-.9 2-2 2zm3.1-9H8.9V6c0-1.71 1.39-3.1 3.1-3.1 1.71 0 3.1 1.39 3.1 3.1v2z"
518
- />
519
- </svg>
520
- <p
521
- class="MuiTypography-root MuiTypography-body1 css-k0xfey-MuiTypography-root"
522
- >
523
- TrackHubRegistryPlugin
524
- </p>
525
- </li>
526
504
  <li
527
505
  class="MuiListItem-root MuiListItem-dense MuiListItem-gutters MuiListItem-padding css-ypie1g-MuiListItem-root"
528
506
  >
File without changes
@@ -0,0 +1,119 @@
1
+ import PluginManager from '@jbrowse/core/PluginManager'
2
+ import { BaseConnectionModelFactory } from '@jbrowse/core/pluggableElementTypes/models'
3
+ import {
4
+ ConfigurationReference,
5
+ readConfObject,
6
+ getConf,
7
+ } from '@jbrowse/core/configuration'
8
+ import { getSession } from '@jbrowse/core/util'
9
+ import { types } from 'mobx-state-tree'
10
+
11
+ // locals
12
+ import configSchema from './configSchema'
13
+ import {
14
+ fetchGenomesFile,
15
+ fetchHubFile,
16
+ fetchTrackDbFile,
17
+ generateTracks,
18
+ } from './ucscTrackHub'
19
+
20
+ export default function UCSCTrackHubConnection(pluginManager: PluginManager) {
21
+ return types
22
+ .compose(
23
+ 'UCSCTrackHubConnection',
24
+ BaseConnectionModelFactory(pluginManager),
25
+ types.model({
26
+ configuration: ConfigurationReference(configSchema),
27
+ type: types.literal('UCSCTrackHubConnection'),
28
+ }),
29
+ )
30
+ .actions(self => ({
31
+ async connect() {
32
+ const session = getSession(self)
33
+ try {
34
+ const connectionName = getConf(self, 'name')
35
+ const hubFileLocation = getConf(self, 'hubTxtLocation')
36
+ const hubFile = await fetchHubFile(hubFileLocation)
37
+ const genomeFile = hubFile.get('genomesFile')
38
+ if (!genomeFile) {
39
+ throw new Error('genomesFile not found on hub')
40
+ }
41
+
42
+ const hubUri = new URL(hubFileLocation.uri, hubFileLocation.baseUri)
43
+ const genomesFileLocation = hubUri
44
+ ? {
45
+ uri: new URL(genomeFile, hubUri).href,
46
+ locationType: 'UriLocation',
47
+ }
48
+ : {
49
+ localPath: genomeFile,
50
+ locationType: 'LocalPathLocation',
51
+ }
52
+ const genomesFile = await fetchGenomesFile(genomesFileLocation)
53
+ const trackDbData = []
54
+ for (const [genomeName, genome] of genomesFile) {
55
+ const assemblyNames = getConf(self, 'assemblyNames')
56
+ if (
57
+ assemblyNames.length > 0 &&
58
+ !assemblyNames.includes(genomeName)
59
+ ) {
60
+ continue
61
+ }
62
+ const conf = session.assemblies.find(
63
+ a => readConfObject(a, 'name') === genomeName,
64
+ )
65
+ if (!conf) {
66
+ throw new Error(
67
+ `Cannot find assembly for "${genomeName}" from the genomes file for connection "${connectionName}"`,
68
+ )
69
+ }
70
+ const trackDb = genome.get('trackDb')
71
+ if (!trackDb) {
72
+ throw new Error('genomesFile not found on hub')
73
+ }
74
+ const trackDbFileLocation = hubUri
75
+ ? {
76
+ uri: new URL(trackDb, new URL(genomeFile, hubUri)).href,
77
+ locationType: 'UriLocation',
78
+ }
79
+ : {
80
+ localPath: trackDb,
81
+ locationType: 'LocalPathLocation',
82
+ }
83
+ trackDbData.push([
84
+ trackDbFileLocation,
85
+ await fetchTrackDbFile(trackDbFileLocation),
86
+ genomeName,
87
+ conf,
88
+ ] as const)
89
+ }
90
+ for (const [
91
+ trackDbFileLocation,
92
+ trackDbFile,
93
+ genomeName,
94
+ conf,
95
+ ] of trackDbData) {
96
+ const sequenceAdapter = readConfObject(conf, [
97
+ 'sequence',
98
+ 'adapter',
99
+ ])
100
+ self.addTrackConfs(
101
+ generateTracks(
102
+ trackDbFile,
103
+ trackDbFileLocation,
104
+ genomeName,
105
+ sequenceAdapter,
106
+ ),
107
+ )
108
+ }
109
+ } catch (e) {
110
+ console.error(e)
111
+ session.notify(
112
+ `There was a problem connecting to the UCSC Track Hub "${self.configuration.name}". Please make sure you have entered a valid hub.txt file. The error that was thrown is: "${e}"`,
113
+ 'error',
114
+ )
115
+ session.breakConnection(self.configuration)
116
+ }
117
+ },
118
+ }))
119
+ }