diff --git a/package.json b/package.json
index 1291265420..83b6b6831d 100644
--- a/package.json
+++ b/package.json
@@ -98,7 +98,7 @@
"cross-spawn": "^7.0.1",
"del": "^5.1.0",
"dependency-graph": "^0.9.0",
- "electron": "13.1.2",
+ "electron": "15.0.0",
"electron-builder": "^22.1.0",
"electron-mock-ipc": "^0.3.8",
"electron-notarize": "^1.0.0",
diff --git a/products/jbrowse-desktop/package.json b/products/jbrowse-desktop/package.json
index cbb803af73..146600cb48 100644
--- a/products/jbrowse-desktop/package.json
+++ b/products/jbrowse-desktop/package.json
@@ -92,7 +92,7 @@
"last 1 chrome version"
],
"build": {
- "electronVersion": "13.1.2",
+ "electronVersion": "15.0.0",
"extraMetadata": {
"main": "build/electron.js"
},
diff --git a/products/jbrowse-desktop/public/electron.ts b/products/jbrowse-desktop/public/electron.ts
index 3ebda2c7a4..0966153fc2 100644
--- a/products/jbrowse-desktop/public/electron.ts
+++ b/products/jbrowse-desktop/public/electron.ts
@@ -221,19 +221,21 @@ ipcMain.handle('listSessions', async () => {
)
})
-ipcMain.handle('loadExternalConfig', (_event: unknown, sessionPath) =>
- readFile(sessionPath, 'utf8'),
-)
-ipcMain.handle('loadSession', (_event: unknown, sessionName: string) =>
- readFile(getPath(sessionName), 'utf8'),
-)
+ipcMain.handle('loadExternalConfig', (_event: unknown, sessionPath) => {
+ return readFile(sessionPath, 'utf8')
+})
+
+ipcMain.handle('loadSession', (_event: unknown, sessionName: string) => {
+ return readFile(getPath(sessionName), 'utf8')
+})
-ipcMain.on('saveSession', async (_event: unknown, snap: SessionSnap) => {
+ipcMain.handle('saveSession', async (_event: unknown, snap: SessionSnap) => {
const page = await mainWindow?.capturePage()
+ const name = snap.defaultSession.name
if (page) {
- writeFile(getPath(snap.defaultSession.name, 'thumbnail'), page.toDataURL())
+ await writeFile(getPath(name, 'thumbnail'), page.toDataURL())
}
- writeFile(getPath(snap.defaultSession.name), JSON.stringify(snap, null, 2))
+ await writeFile(getPath(name), JSON.stringify(snap, null, 2))
})
ipcMain.handle(
diff --git a/products/jbrowse-desktop/src/Loader.tsx b/products/jbrowse-desktop/src/Loader.tsx
index 4d7af54a5d..4809c041d6 100644
--- a/products/jbrowse-desktop/src/Loader.tsx
+++ b/products/jbrowse-desktop/src/Loader.tsx
@@ -1,23 +1,117 @@
-import React, { useState } from 'react'
-import PluginManager from '@jbrowse/core/PluginManager'
-import { CssBaseline, ThemeProvider } from '@material-ui/core'
+import React, { useState, useCallback, useEffect } from 'react'
import { observer } from 'mobx-react'
+import PluginManager from '@jbrowse/core/PluginManager'
+import { CssBaseline, ThemeProvider, makeStyles } from '@material-ui/core'
+import { createJBrowseTheme } from '@jbrowse/core/ui'
+import { StringParam, useQueryParam } from 'use-query-params'
+import { ipcRenderer } from 'electron'
+import { createPluginManager } from './StartScreen/util'
+
import JBrowse from './JBrowse'
import StartScreen from './StartScreen'
-import { createJBrowseTheme } from '@jbrowse/core/ui'
-function Loader() {
+const useStyles = makeStyles(theme => ({
+ message: {
+ border: '1px solid black',
+ overflow: 'auto',
+ maxHeight: 200,
+ margin: theme.spacing(1),
+ padding: theme.spacing(1),
+ },
+
+ errorBox: {
+ background: 'lightgrey',
+ border: '1px solid black',
+ margin: 20,
+ },
+}))
+
+const ErrorMessage = ({
+ error,
+ snapshotError,
+}: {
+ error: Error
+ snapshotError?: string
+}) => {
+ const classes = useStyles()
+ return (
+
+ {`${error}`}
+ {snapshotError ? (
+ <>
+ ... Failed element had snapshot:
+
+ {JSON.stringify(JSON.parse(snapshotError), null, 2)}
+
+ >
+ ) : null}
+
+ )
+}
+
+const Loader = observer(() => {
const [pluginManager, setPluginManager] = useState()
+ const [config, setConfig] = useQueryParam('config', StringParam)
+ const [error, setError] = useState()
+ const [snapshotError, setSnapshotError] = useState('')
+
+ function handleError(e: Error) {
+ const match = e.message.match(
+ /.*at path "(.*)" snapshot `(.*)` is not assignable/,
+ )
+
+ // best effort to make a better error message than the default
+ // mobx-state-tree
+ if (match) {
+ setError(new Error(`Failed to load element at ${match[1]}`))
+ setSnapshotError(match[2])
+ } else {
+ setError(new Error(e.message.slice(0, 10000)))
+ }
+ console.error(e)
+ }
+
+ const handleSetPluginManager = useCallback(
+ (pm: PluginManager) => {
+ setPluginManager(pm)
+ setError(undefined)
+ setSnapshotError('')
+ setConfig('')
+ },
+ [setConfig],
+ )
+
+ useEffect(() => {
+ ;(async () => {
+ if (config) {
+ try {
+ const data = await ipcRenderer.invoke('loadSession', config)
+ const pm = await createPluginManager(JSON.parse(data))
+ handleSetPluginManager(pm)
+ } catch (e) {
+ handleError(e)
+ }
+ }
+ })()
+ }, [config, handleSetPluginManager])
+
return (
+
+ {error ? (
+
+ ) : null}
{pluginManager?.rootModel?.session ? (
- ) : (
-
- )}
+ ) : !config || error ? (
+
+ ) : null}
)
-}
+})
-export default observer(Loader)
+export default Loader
diff --git a/products/jbrowse-desktop/src/StartScreen/data/preloadedConfigs.js b/products/jbrowse-desktop/src/StartScreen/data/preloadedConfigs.js
index e7759fcdd2..313828bfe9 100644
--- a/products/jbrowse-desktop/src/StartScreen/data/preloadedConfigs.js
+++ b/products/jbrowse-desktop/src/StartScreen/data/preloadedConfigs.js
@@ -203,11 +203,47 @@ const preloadedConfigs = {
},
},
},
+ {
+ type: 'FeatureTrack',
+ trackId: 'ncbi_refseq_109_hg38_latest',
+ name: 'NCBI RefSeq',
+ assemblyNames: ['hg38'],
+ category: ['Annotation'],
+ adapter: {
+ type: 'Gff3TabixAdapter',
+ gffGzLocation: {
+ uri:
+ 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/ncbi_refseq/GRCh38_latest_genomic.sort.gff.gz',
+ },
+ index: {
+ location: {
+ uri:
+ 'https://s3.amazonaws.com/jbrowse.org/genomes/GRCh38/ncbi_refseq/GRCh38_latest_genomic.sort.gff.gz.tbi',
+ },
+ },
+ },
+ },
],
defaultSession: {
name: 'New Session',
},
+ aggregateTextSearchAdapters: [
+ {
+ type: 'TrixTextSearchAdapter',
+ textSearchAdapterId: 'hg38-index',
+ ixFilePath: {
+ uri: 'https://jbrowse.org/genomes/GRCh38/trix/hg38.ix',
+ },
+ ixxFilePath: {
+ uri: 'https://jbrowse.org/genomes/GRCh38/trix/hg38.ixx',
+ },
+ metaFilePath: {
+ uri: 'https://jbrowse.org/genomes/GRCh38/trix/meta.json',
+ },
+ assemblyNames: ['hg38'],
+ },
+ ],
},
hg19: {
assemblies: [
@@ -243,6 +279,30 @@ const preloadedConfigs = {
},
],
tracks: [
+ {
+ type: 'FeatureTrack',
+ trackId: 'ncbi_gff_hg19',
+ name: 'NCBI RefSeq',
+ assemblyNames: ['hg19'],
+ category: ['Annotation'],
+ metadata: {
+ source: 'https://www.ncbi.nlm.nih.gov/genome/guide/human/',
+ dateaccessed: '12/03/2020',
+ },
+ adapter: {
+ type: 'Gff3TabixAdapter',
+ gffGzLocation: {
+ uri:
+ 'https://s3.amazonaws.com/jbrowse.org/genomes/hg19/ncbi_refseq/GRCh37_latest_genomic.sort.gff.gz',
+ },
+ index: {
+ location: {
+ uri:
+ 'https://s3.amazonaws.com/jbrowse.org/genomes/hg19/ncbi_refseq/GRCh37_latest_genomic.sort.gff.gz.tbi',
+ },
+ },
+ },
+ },
{
type: 'FeatureTrack',
trackId: 'repeats_hg19',
@@ -397,6 +457,23 @@ const preloadedConfigs = {
defaultSession: {
name: 'New Session',
},
+
+ aggregateTextSearchAdapters: [
+ {
+ type: 'TrixTextSearchAdapter',
+ textSearchAdapterId: 'hg19-index',
+ ixFilePath: {
+ uri: 'https://jbrowse.org/genomes/hg19/trix/hg19.ix',
+ },
+ ixxFilePath: {
+ uri: 'https://jbrowse.org/genomes/hg19/trix/hg19.ixx',
+ },
+ metaFilePath: {
+ uri: 'https://jbrowse.org/genomes/hg19/trix/meta.json',
+ },
+ assemblyNames: ['hg19'],
+ },
+ ],
},
mm10: {
assemblies: [
diff --git a/products/jbrowse-desktop/src/StartScreen/index.tsx b/products/jbrowse-desktop/src/StartScreen/index.tsx
index 9ada89308f..89794c8ea5 100644
--- a/products/jbrowse-desktop/src/StartScreen/index.tsx
+++ b/products/jbrowse-desktop/src/StartScreen/index.tsx
@@ -80,8 +80,10 @@ function LogoWithVersion() {
}
export default function StartScreen({
setPluginManager,
+ setError,
}: {
setPluginManager: (arg: PluginManager) => void
+ setError: (arg: Error) => void
}) {
const classes = useStyles()
const [sessions, setSessions] = useState