Skip to content

Commit e150c03

Browse files
authored
Add ability to load a ?hubURL= from URL bar (#4745)
1 parent bad8184 commit e150c03

10 files changed

Lines changed: 277 additions & 217 deletions

File tree

packages/web-core/src/SessionConnections.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,44 @@ export function WebSessionConnectionsMixin(pluginManager: PluginManager) {
3232
const superDeleteConnection = self.deleteConnection
3333
const superAddConnectionConf = self.addConnectionConf
3434
return {
35+
/**
36+
* #action
37+
*/
3538
addConnectionConf(connectionConf: BaseConnectionConfigModel) {
3639
if (self.adminMode) {
3740
return superAddConnectionConf(connectionConf)
41+
} else {
42+
const { connectionId, type } = connectionConf
43+
if (!type) {
44+
throw new Error(`unknown connection type ${type}`)
45+
}
46+
const connection = self.sessionTracks.find(
47+
c => c.connectionId === connectionId,
48+
)
49+
if (connection) {
50+
return connection
51+
} else {
52+
const length = self.sessionConnections.push(connectionConf)
53+
return self.sessionConnections[length - 1]
54+
}
3855
}
39-
const { connectionId, type } = connectionConf
40-
if (!type) {
41-
throw new Error(`unknown connection type ${type}`)
42-
}
43-
const connection = self.sessionTracks.find(
44-
c => c.connectionId === connectionId,
45-
)
46-
if (connection) {
47-
return connection
48-
}
49-
const length = self.sessionConnections.push(connectionConf)
50-
return self.sessionConnections[length - 1]
5156
},
5257

58+
/**
59+
* #action
60+
*/
5361
deleteConnection(configuration: AnyConfigurationModel) {
54-
let deletedConn: unknown
5562
if (self.adminMode) {
56-
deletedConn = superDeleteConnection(configuration)
57-
}
58-
if (!deletedConn) {
63+
return superDeleteConnection(configuration)
64+
} else {
5965
const { connectionId } = configuration
6066
const idx = self.sessionConnections.findIndex(
6167
c => c.connectionId === connectionId,
6268
)
63-
if (idx === -1) {
64-
return undefined
65-
}
66-
return self.sessionConnections.splice(idx, 1)
69+
return idx === -1
70+
? undefined
71+
: self.sessionConnections.splice(idx, 1)
6772
}
68-
return deletedConn
6973
},
7074
}
7175
})

products/jbrowse-web/src/SessionLoader.ts

Lines changed: 75 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@ import { addDisposer, types } from 'mobx-state-tree'
77
import { readSessionFromDynamo } from './sessionSharing'
88
import { addRelativeUris, checkPlugins, fromUrlSafeB64, readConf } from './util'
99

10+
import type { SessionTriagedInfo } from './types'
1011
import type { PluginDefinition, PluginRecord } from '@jbrowse/core/PluginLoader'
1112
import type { Instance } from 'mobx-state-tree'
1213

13-
export interface SessionTriagedInfo {
14-
snap: unknown
15-
origin: string
16-
reason: PluginDefinition[]
17-
}
18-
1914
const SessionLoader = types
2015
.model({
2116
/**
@@ -66,6 +61,11 @@ const SessionLoader = types
6661
* #property
6762
*/
6863
initialTimestamp: types.number,
64+
65+
/**
66+
* #property
67+
*/
68+
hubURL: types.maybe(types.array(types.string)),
6969
})
7070
.volatile(() => ({
7171
/**
@@ -84,6 +84,10 @@ const SessionLoader = types
8484
* #volatile
8585
*/
8686
sessionSpec: undefined as Record<string, unknown> | undefined,
87+
/**
88+
* #volatile
89+
*/
90+
hubSpec: undefined as Record<string, unknown> | undefined,
8791
/**
8892
* #volatile
8993
*/
@@ -134,6 +138,12 @@ const SessionLoader = types
134138
get isSpecSession() {
135139
return !!self.sessionQuery?.startsWith('spec-')
136140
},
141+
/**
142+
* #getter
143+
*/
144+
get isHubSession() {
145+
return !!self.hubURL
146+
},
137147
/**
138148
* #getter
139149
*/
@@ -275,8 +285,7 @@ const SessionLoader = types
275285
try {
276286
const pluginLoader = new PluginLoader(snap.sessionPlugins || [], {
277287
fetchESM: url => import(/* webpackIgnore:true */ url),
278-
})
279-
pluginLoader.installGlobalReExports(window)
288+
}).installGlobalReExports(window)
280289
const plugins = await pluginLoader.load(window.location.href)
281290
self.setSessionPlugins([...plugins])
282291
} catch (e) {
@@ -315,38 +324,38 @@ const SessionLoader = types
315324
*/
316325
async fetchConfig() {
317326
// @ts-expect-error
327+
const path = window.__jbrowseConfigPath
328+
const { hubURL, configPath = path || 'config.json' } = self
329+
if (!hubURL) {
330+
const text = await openLocation({
331+
uri:
332+
configPath +
333+
// @ts-expect-error
334+
(window.__jbrowseCacheBuster ? `?rand=${Math.random()}` : ''),
335+
locationType: 'UriLocation',
336+
}).readFile('utf8')
337+
const config = JSON.parse(text)
338+
const configUri = new URL(configPath, window.location.href)
339+
addRelativeUris(config, configUri)
318340

319-
let { configPath = window.__jbrowseConfigPath || 'config.json' } = self
320-
321-
// @ts-expect-error
322-
323-
if (window.__jbrowseCacheBuster) {
324-
configPath += `?rand=${Math.random()}`
325-
}
326-
327-
const text = await openLocation({
328-
uri: configPath,
329-
locationType: 'UriLocation',
330-
}).readFile('utf8')
331-
const config = JSON.parse(text)
332-
const configUri = new URL(configPath, window.location.href)
333-
addRelativeUris(config, configUri)
334-
335-
// cross origin config check
336-
if (configUri.hostname !== window.location.hostname) {
337-
const configPlugins = config.plugins || []
338-
const configPluginsAllowed = await checkPlugins(configPlugins)
339-
if (!configPluginsAllowed) {
340-
self.setSessionTriaged({
341-
snap: config,
342-
origin: 'config',
343-
reason: configPlugins,
344-
})
345-
return
341+
// cross origin config check
342+
if (configUri.hostname !== window.location.hostname) {
343+
const configPlugins = config.plugins || []
344+
const configPluginsAllowed = await checkPlugins(configPlugins)
345+
if (!configPluginsAllowed) {
346+
self.setSessionTriaged({
347+
snap: config,
348+
origin: 'config',
349+
reason: configPlugins,
350+
})
351+
return
352+
}
346353
}
354+
await this.fetchPlugins(config)
355+
self.setConfigSnapshot(config)
356+
} else {
357+
self.setConfigSnapshot({})
347358
}
348-
await this.fetchPlugins(config)
349-
self.setConfigSnapshot(config)
350359
},
351360
/**
352361
* #action
@@ -399,7 +408,10 @@ const SessionLoader = types
399408
)
400409

401410
const session = JSON.parse(await fromUrlSafeB64(decryptedSession))
402-
await this.setSessionSnapshot({ ...session, id: nanoid() })
411+
await this.setSessionSnapshot({
412+
...session,
413+
id: nanoid(),
414+
})
403415
},
404416
/**
405417
* #action
@@ -409,7 +421,10 @@ const SessionLoader = types
409421
// @ts-expect-error
410422
await fromUrlSafeB64(self.sessionQuery.replace('encoded-', '')),
411423
)
412-
await this.setSessionSnapshot({ ...session, id: nanoid() })
424+
await this.setSessionSnapshot({
425+
...session,
426+
id: nanoid(),
427+
})
413428
},
414429
/**
415430
* #action
@@ -451,13 +466,28 @@ const SessionLoader = types
451466
}
452467
}
453468
},
469+
470+
/**
471+
* #action
472+
*/
473+
decodeHubSpec() {
474+
const { hubURL, sessionTracksParsed: sessionTracks } = self
475+
476+
self.hubSpec = {
477+
sessionTracks,
478+
hubURL,
479+
}
480+
},
454481
/**
455482
* #action
456483
*/
457484
async decodeJsonUrlSession() {
458485
// @ts-expect-error
459-
const session = JSON.parse(self.sessionQuery.replace('json-', ''))
460-
await this.setSessionSnapshot({ ...session.session, id: nanoid() })
486+
const { session } = JSON.parse(self.sessionQuery.replace(/^json-/, ''))
487+
await this.setSessionSnapshot({
488+
...session,
489+
id: nanoid(),
490+
})
461491
},
462492
/**
463493
* #aftercreate
@@ -479,6 +509,7 @@ const SessionLoader = types
479509
isSharedSession,
480510
isJsonSession,
481511
isJb1StyleSession,
512+
isHubSession,
482513
sessionQuery,
483514
configSnapshot,
484515
} = self
@@ -505,6 +536,9 @@ const SessionLoader = types
505536
this.decodeJb1StyleSession()
506537
} else if (isEncodedSession) {
507538
await this.decodeEncodedUrlSession()
539+
} else if (isHubSession) {
540+
this.decodeHubSpec()
541+
self.setBlankSession(true)
508542
} else if (isJsonSession) {
509543
await this.decodeJsonUrlSession()
510544
} else if (isLocalSession) {
@@ -525,7 +559,6 @@ const SessionLoader = types
525559
} catch (e) {
526560
console.error(e)
527561
self.setConfigError(e)
528-
return
529562
}
530563
})()
531564
},

products/jbrowse-web/src/components/ConfigWarningDialog.tsx

Lines changed: 1 addition & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { pluginDescriptionString } from '@jbrowse/core/PluginLoader'
22
import { Dialog } from '@jbrowse/core/ui'
3-
import { nanoid } from '@jbrowse/core/util/nanoid'
43
import WarningIcon from '@mui/icons-material/Warning'
54
import {
65
Button,
@@ -9,12 +8,9 @@ import {
98
DialogContentText,
109
} from '@mui/material'
1110

12-
import factoryReset from '../factoryReset'
13-
14-
import type { SessionLoaderModel } from '../SessionLoader'
1511
import type { PluginDefinition } from '@jbrowse/core/PluginLoader'
1612

17-
function ConfigWarningDialog({
13+
export default function ConfigWarningDialog({
1814
onConfirm,
1915
onCancel,
2016
reason,
@@ -61,28 +57,3 @@ function ConfigWarningDialog({
6157
</Dialog>
6258
)
6359
}
64-
65-
export default function ConfigTriaged({
66-
loader,
67-
handleClose,
68-
}: {
69-
loader: SessionLoaderModel
70-
handleClose: () => void
71-
}) {
72-
const { sessionTriaged } = loader
73-
return sessionTriaged ? (
74-
<ConfigWarningDialog
75-
onConfirm={async () => {
76-
const session = JSON.parse(JSON.stringify(sessionTriaged.snap))
77-
await loader.fetchPlugins(session)
78-
loader.setConfigSnapshot({ ...session, id: nanoid() })
79-
handleClose()
80-
}}
81-
onCancel={async () => {
82-
await factoryReset()
83-
handleClose()
84-
}}
85-
reason={sessionTriaged.reason}
86-
/>
87-
) : null
88-
}

0 commit comments

Comments
 (0)