@jbrowse/plugin-data-management 1.7.8 → 1.7.11

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 (28) hide show
  1. package/dist/AddConnectionWidget/components/AddConnectionWidget.test.js +25 -16
  2. package/dist/AddConnectionWidget/model.d.ts +1 -1
  3. package/dist/AddTrackWidget/index.test.js +1 -0
  4. package/dist/AddTrackWidget/model.js +1 -1
  5. package/dist/HierarchicalTrackSelectorWidget/components/CloseConnectionDialog.d.ts +7 -1
  6. package/dist/HierarchicalTrackSelectorWidget/components/CloseConnectionDialog.js +2 -5
  7. package/dist/HierarchicalTrackSelectorWidget/components/DeleteConnectionDialog.d.ts +1 -1
  8. package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.d.ts +9 -5
  9. package/dist/HierarchicalTrackSelectorWidget/components/HierarchicalTrackSelector.js +67 -51
  10. package/dist/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.d.ts +2 -1
  11. package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.d.ts +2 -1
  12. package/dist/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.js +10 -11
  13. package/dist/HierarchicalTrackSelectorWidget/index.d.ts +2 -2
  14. package/dist/HierarchicalTrackSelectorWidget/model.d.ts +38 -16
  15. package/dist/HierarchicalTrackSelectorWidget/model.js +89 -97
  16. package/dist/ucsc-trackhub/configSchema.d.ts +1 -1
  17. package/dist/ucsc-trackhub/ucscAssemblies.d.ts +1 -1
  18. package/package.json +2 -2
  19. package/src/AddConnectionWidget/components/AddConnectionWidget.test.js +2 -1
  20. package/src/AddTrackWidget/index.test.jsx +1 -0
  21. package/src/AddTrackWidget/model.ts +1 -1
  22. package/src/HierarchicalTrackSelectorWidget/components/CloseConnectionDialog.tsx +7 -11
  23. package/src/HierarchicalTrackSelectorWidget/components/DeleteConnectionDialog.tsx +1 -1
  24. package/src/HierarchicalTrackSelectorWidget/components/{HierarchicalTrackSelector.js → HierarchicalTrackSelector.tsx} +247 -135
  25. package/src/HierarchicalTrackSelectorWidget/components/ManageConnectionsDialog.tsx +5 -2
  26. package/src/HierarchicalTrackSelectorWidget/components/ToggleConnectionsDialog.tsx +24 -26
  27. package/src/HierarchicalTrackSelectorWidget/{index.js → index.ts} +0 -0
  28. package/src/HierarchicalTrackSelectorWidget/{model.js → model.ts} +113 -105
@@ -1,22 +1,28 @@
1
- import { types, getParent } from 'mobx-state-tree'
2
- import { readConfObject } from '@jbrowse/core/configuration'
1
+ import { types, getParent, Instance } from 'mobx-state-tree'
2
+ import {
3
+ AnyConfigurationModel,
4
+ getConf,
5
+ readConfObject,
6
+ } from '@jbrowse/core/configuration'
3
7
  import { getSession } from '@jbrowse/core/util'
4
8
  import { ElementId } from '@jbrowse/core/util/types/mst'
9
+ import PluginManager from '@jbrowse/core/PluginManager'
10
+ import { AbstractView } from 'react'
5
11
 
6
- const hasAnyOverlap = (a1 = [], a2 = []) =>
7
- !!a1.find(value => a2.includes(value))
12
+ function hasAnyOverlap<T>(a1: T[] = [], a2: T[] = []) {
13
+ return !!a1.find(value => a2.includes(value))
14
+ }
8
15
 
9
- function passesFilter(filter, config) {
10
- const name = getTrackName(config)
11
- const categories = readConfObject(config, 'category') || []
16
+ function passesFilter(filter: string, config: AnyConfigurationModel) {
17
+ const categories = readConfObject(config, 'category') as string[] | undefined
12
18
  const filterLower = filter.toLowerCase()
13
19
  return (
14
- !!name.toLowerCase().includes(filterLower) ||
15
- categories.filter(cat => !!cat.toLowerCase().includes(filterLower)).length
20
+ getTrackName(config).toLowerCase().includes(filterLower) ||
21
+ categories?.filter(c => c.toLowerCase().includes(filterLower)).length
16
22
  )
17
23
  }
18
24
 
19
- function getTrackName(config) {
25
+ function getTrackName(config: AnyConfigurationModel) {
20
26
  if (!config.trackId) {
21
27
  throw new Error('not a track')
22
28
  }
@@ -26,20 +32,33 @@ function getTrackName(config) {
26
32
  )
27
33
  }
28
34
 
29
- export function generateHierarchy(model, trackConfigurations, collapsed) {
30
- const hierarchy = { children: [] }
35
+ export type TreeNode = {
36
+ name: string
37
+ id: string
38
+ conf?: AnyConfigurationModel
39
+ checked?: boolean
40
+ isOpenByDefault?: boolean
41
+ children: TreeNode[]
42
+ }
43
+
44
+ export function generateHierarchy(
45
+ model: HierarchicalTrackSelectorModel,
46
+ trackConfigurations: AnyConfigurationModel[],
47
+ collapsed: { get: (arg: string) => boolean | undefined },
48
+ ) {
49
+ const hierarchy = { children: [] as TreeNode[] } as TreeNode
31
50
  const { filterText, view } = model
32
51
 
33
52
  trackConfigurations
34
- .filter(trackConf => passesFilter(filterText, trackConf))
35
- .forEach(trackConf => {
53
+ .filter(conf => passesFilter(filterText, conf))
54
+ .forEach(conf => {
36
55
  // copy the categories since this array can be mutated downstream
37
- const categories = [...(readConfObject(trackConf, 'category') || [])]
56
+ const categories = [...(readConfObject(conf, 'category') || [])]
38
57
 
39
58
  // silly thing where if trackId ends with sessionTrack, then push it to
40
59
  // a category that starts with a space to force sort to the top...
41
60
  // double whammy hackyness
42
- if (trackConf.trackId.endsWith('sessionTrack')) {
61
+ if (conf.trackId.endsWith('sessionTrack')) {
43
62
  categories.unshift(' Session tracks')
44
63
  }
45
64
 
@@ -63,16 +82,17 @@ export function generateHierarchy(model, trackConfigurations, collapsed) {
63
82
  currLevel = ret
64
83
  }
65
84
  }
85
+ const tracks = view.tracks as { configuration: AnyConfigurationModel }[]
66
86
 
67
87
  // using splice here tries to group leaf nodes above hierarchical nodes
68
88
  currLevel.children.splice(
69
89
  currLevel.children.findIndex(elt => elt.children.length),
70
90
  0,
71
91
  {
72
- id: trackConf.trackId,
73
- name: getTrackName(trackConf),
74
- conf: trackConf,
75
- checked: !!view.tracks.find(f => f.configuration === trackConf),
92
+ id: conf.trackId,
93
+ name: getTrackName(conf),
94
+ conf,
95
+ checked: !!tracks.find(f => f.configuration === conf),
76
96
  children: [],
77
97
  },
78
98
  )
@@ -81,8 +101,8 @@ export function generateHierarchy(model, trackConfigurations, collapsed) {
81
101
  return hierarchy.children
82
102
  }
83
103
 
84
- export default pluginManager =>
85
- types
104
+ export default function stateTreeFactory(pluginManager: PluginManager) {
105
+ return types
86
106
  .model('HierarchicalTrackSelectorWidget', {
87
107
  id: ElementId,
88
108
  type: types.literal('HierarchicalTrackSelectorWidget'),
@@ -93,44 +113,41 @@ export default pluginManager =>
93
113
  ),
94
114
  })
95
115
  .actions(self => ({
96
- setView(view) {
116
+ setView(view: AbstractView) {
97
117
  self.view = view
98
118
  },
99
- toggleCategory(pathName) {
119
+ toggleCategory(pathName: string) {
100
120
  self.collapsed.set(pathName, !self.collapsed.get(pathName))
101
121
  },
102
122
  clearFilterText() {
103
123
  self.filterText = ''
104
124
  },
105
- setFilterText(newText) {
125
+ setFilterText(newText: string) {
106
126
  self.filterText = newText
107
127
  },
108
128
  }))
109
129
  .views(self => ({
110
- getRefSeqTrackConf(assemblyName) {
130
+ getRefSeqTrackConf(assemblyName: string) {
111
131
  const { assemblyManager } = getSession(self)
112
132
  const assembly = assemblyManager.get(assemblyName)
113
133
  const trackConf = assembly?.configuration.sequence
114
134
  const viewType = pluginManager.getViewType(self.view.type)
115
- if (trackConf) {
116
- for (const display of trackConf.displays) {
117
- if (
118
- viewType.displayTypes.find(
119
- displayType => displayType.name === display.type,
120
- )
121
- ) {
122
- return trackConf
123
- }
135
+ if (!trackConf) {
136
+ return undefined
137
+ }
138
+ for (const display of trackConf.displays) {
139
+ if (viewType.displayTypes.find(d => d.name === display.type)) {
140
+ return trackConf
124
141
  }
125
142
  }
126
- return undefined
127
143
  },
128
- trackConfigurations(assemblyName) {
144
+ }))
145
+ .views(self => ({
146
+ trackConfigurations(assemblyName: string) {
129
147
  if (!self.view) {
130
148
  return []
131
149
  }
132
- const session = getSession(self)
133
- const { tracks: trackConfigurations, assemblyManager } = session
150
+ const { tracks, assemblyManager } = getSession(self)
134
151
  const assembly = assemblyManager.get(assemblyName)
135
152
  if (!assembly) {
136
153
  return []
@@ -139,34 +156,36 @@ export default pluginManager =>
139
156
  // filter out tracks that don't match the current assembly (check all
140
157
  // assembly aliases) and display types
141
158
  return (refseq ? [refseq] : []).concat([
142
- ...trackConfigurations
143
- .filter(conf => {
144
- const trackConfAssemblies = readConfObject(conf, 'assemblyNames')
159
+ ...tracks
160
+ .filter(c => {
161
+ const trackConfAssemblies = readConfObject(c, 'assemblyNames')
145
162
  const { allAliases } = assembly
146
163
  return hasAnyOverlap(allAliases, trackConfAssemblies)
147
164
  })
148
- .filter(conf => {
165
+ .filter(c => {
149
166
  const { displayTypes } = pluginManager.getViewType(self.view.type)
150
- const compatibleDisplays = displayTypes.map(
151
- display => display.name,
167
+ const compatibleDisplays = displayTypes.map(d => d.name)
168
+ const trackDisplays = c.displays.map(
169
+ (d: { type: string }) => d.type,
152
170
  )
153
- const trackDisplays = conf.displays.map(display => display.type)
154
171
  return hasAnyOverlap(compatibleDisplays, trackDisplays)
155
172
  }),
156
173
  ])
157
174
  },
158
175
 
159
- get assemblyNames() {
160
- return self.view ? self.view.assemblyNames : []
176
+ get assemblyNames(): string[] {
177
+ return self.view?.assemblyNames || []
161
178
  },
162
179
 
163
- connectionTrackConfigurations(assemblyName, connection) {
180
+ connectionTrackConfigurations(
181
+ assemblyName: string,
182
+ connection: { tracks: AnyConfigurationModel[] },
183
+ ) {
164
184
  if (!self.view) {
165
185
  return []
166
186
  }
167
187
  const trackConfigurations = connection.tracks
168
- const session = getSession(self)
169
- const { assemblyManager } = session
188
+ const { assemblyManager } = getSession(self)
170
189
  const assembly = assemblyManager.get(assemblyName)
171
190
 
172
191
  if (!(assembly && assembly.initialized)) {
@@ -175,49 +194,49 @@ export default pluginManager =>
175
194
 
176
195
  // filter out tracks that don't match the current display types
177
196
  return trackConfigurations
178
- .filter(conf => {
179
- const trackConfAssemblies = readConfObject(conf, 'assemblyNames')
197
+ .filter(c => {
198
+ const trackConfAssemblies = readConfObject(c, 'assemblyNames')
180
199
  const { allAliases } = assembly
181
200
  return hasAnyOverlap(allAliases, trackConfAssemblies)
182
201
  })
183
- .filter(conf => {
202
+ .filter(c => {
184
203
  const { displayTypes } = pluginManager.getViewType(self.view.type)
185
- const compatibleDisplays = displayTypes.map(display => display.name)
186
- const trackDisplays = conf.displays.map(display => display.type)
204
+ const compatibleDisplays = displayTypes.map(d => d.name)
205
+ const trackDisplays = c.displays.map(
206
+ (d: { type: string }) => d.type,
207
+ )
187
208
  return hasAnyOverlap(compatibleDisplays, trackDisplays)
188
209
  })
189
210
  },
190
-
191
- hierarchy(assemblyName) {
211
+ }))
212
+ .views(self => ({
213
+ hierarchy(assemblyName: string) {
192
214
  const hier = generateHierarchy(
193
- self,
215
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
216
+ self as any,
194
217
  self.trackConfigurations(assemblyName),
195
218
  self.collapsed,
196
219
  )
197
220
 
198
221
  const session = getSession(self)
199
- const conns = session.connectionInstances
200
- .filter(conn => {
201
- const configAssemblyNames = readConfObject(
202
- conn.configuration,
203
- 'assemblyNames',
204
- )
205
- if (configAssemblyNames.length === 0) {
206
- return true
207
- }
208
- return configAssemblyNames.includes(assemblyName)
209
- })
210
- .map((conn, index) => {
211
- const c = session.connections[index]
212
- return {
213
- id: c.connectionId,
214
- name: readConfObject(c, 'name'),
215
- children: this.connectionHierarchy(assemblyName, conn),
216
- state: {
217
- expanded: true,
218
- },
219
- }
220
- })
222
+ const { connections, connectionInstances } = session
223
+ const conns =
224
+ connectionInstances
225
+ ?.filter(c => {
226
+ const names = getConf(c, 'assemblyNames')
227
+ return names.length === 0 ? true : names.includes(assemblyName)
228
+ })
229
+ .map((conn, index) => {
230
+ const c = connections[index]
231
+ return {
232
+ id: c.connectionId,
233
+ name: readConfObject(c, 'name'),
234
+ children: this.connectionHierarchy(assemblyName, conn),
235
+ state: {
236
+ expanded: true,
237
+ },
238
+ }
239
+ }) || []
221
240
 
222
241
  return {
223
242
  name: 'Root',
@@ -229,33 +248,22 @@ export default pluginManager =>
229
248
  }
230
249
  },
231
250
 
232
- connectionHierarchy(assemblyName, connection) {
251
+ connectionHierarchy(
252
+ assemblyName: string,
253
+ connection: { tracks: AnyConfigurationModel[] },
254
+ ) {
233
255
  return generateHierarchy(
234
- self,
256
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
257
+ self as any,
235
258
  self.connectionTrackConfigurations(assemblyName, connection),
236
259
  self.collapsed,
237
260
  )
238
261
  },
239
-
240
- // This recursively gets tracks from lower paths
241
- allTracksInCategoryPath(path, connection, assemblyName) {
242
- let currentHier = connection
243
- ? self.connectionHierarchy(connection)
244
- : self.hierarchy(assemblyName)
245
- path.forEach(pathItem => {
246
- currentHier = currentHier.get(pathItem) || new Map()
247
- })
248
- let tracks = {}
249
- currentHier.forEach((contents, name) => {
250
- if (contents.trackId) {
251
- tracks[contents.trackId] = contents
252
- } else {
253
- tracks = Object.assign(
254
- tracks,
255
- self.allTracksInCategoryPath(path.concat([name])),
256
- )
257
- }
258
- })
259
- return tracks
260
- },
261
262
  }))
263
+ }
264
+
265
+ export type HierarchicalTrackSelectorStateModel = ReturnType<
266
+ typeof stateTreeFactory
267
+ >
268
+ export type HierarchicalTrackSelectorModel =
269
+ Instance<HierarchicalTrackSelectorStateModel>