Skip to content

Commit

Permalink
Fix opening local files in the multi-wiggle add track selector (#4634)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin authored Nov 3, 2024
1 parent be177a4 commit 6c5407f
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 373 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"dependency-graph": "^1.0.0",
"dotenv": "^16.3.1",
"dotenv-expand": "^11.0.3",
"electron": "32.1.0",
"electron": "33.0.2",
"electron-builder": "^25.1.6",
"electron-mock-ipc": "^0.3.8",
"eslint": "^9.0.0",
Expand Down
103 changes: 55 additions & 48 deletions plugins/wiggle/src/MultiWiggleAddTrackWorkflow/AddTrackWorkflow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import { storeBlobLocation } from '@jbrowse/core/util/tracks'
import { AddTrackModel } from '@jbrowse/plugin-data-management'

const useStyles = makeStyles()(theme => ({
textbox: {
width: '100%',
},
paper: {
margin: theme.spacing(),
padding: theme.spacing(),
Expand All @@ -25,6 +22,17 @@ const useStyles = makeStyles()(theme => ({
},
}))

// on electron, use path to LocalFileLocation, on web, use the BlobLocation
function makeFileLocation(file: File) {
const { webUtils } = window.require('electron')
return isElectron
? {
localPath: webUtils.getPathForFile(file),
locationType: 'LocalPathLocation',
}
: storeBlobLocation({ blob: file })
}

export default function MultiWiggleWidget({ model }: { model: AddTrackModel }) {
const { classes } = useStyles()
const [val, setVal] = useState('')
Expand All @@ -41,14 +49,14 @@ export default function MultiWiggleWidget({ model }: { model: AddTrackModel }) {

<TextField
multiline
fullWidth
rows={10}
value={val}
placeholder="Paste list of URLs here, or use file selector below"
variant="outlined"
onChange={event => {
setVal(event.target.value)
}}
placeholder={'Paste list of URLs here, or use file selector below'}
variant="outlined"
className={classes.textbox}
/>

<Button variant="outlined" component="label">
Expand All @@ -60,12 +68,7 @@ export default function MultiWiggleWidget({ model }: { model: AddTrackModel }) {
onChange={({ target }) => {
const res = [...(target.files || [])].map(file => ({
type: 'BigWigAdapter',
bigWigLocation: isElectron
? {
localPath: (file as File & { path: string }).path,
locationType: 'LocalPathLocation',
}
: storeBlobLocation({ blob: file }),
bigWigLocation: makeFileLocation(file),
source: file.name,
}))
setVal(JSON.stringify(res, null, 2))
Expand All @@ -74,54 +77,58 @@ export default function MultiWiggleWidget({ model }: { model: AddTrackModel }) {
</Button>
<TextField
value={trackName}
helperText="Track name"
onChange={event => {
setTrackName(event.target.value)
}}
helperText="Track name"
/>
<Button
variant="contained"
className={classes.submit}
onClick={() => {
const session = getSession(model)

const trackId = [
`${trackName.toLowerCase().replaceAll(' ', '_')}-${Date.now()}`,
session.adminMode ? '' : '-sessionTrack',
].join('')

// allow list of bigwigs in JSON format or line-by-line
let bigWigs: unknown[]
try {
bigWigs = JSON.parse(val)
} catch (e) {
bigWigs = val
.split(/\n|\r\n|\r/)
.map(f => f.trim())
.filter(f => !!f)
}
const obj =
typeof bigWigs[0] === 'string'
? { bigWigs }
: { subadapters: bigWigs }
const trackId = [
`${trackName.toLowerCase().replaceAll(' ', '_')}-${Date.now()}`,
session.adminMode ? '' : '-sessionTrack',
].join('')

if (isSessionWithAddTracks(session)) {
session.addTrackConf({
trackId,
type: 'MultiQuantitativeTrack',
name: trackName,
assemblyNames: [model.assembly],
adapter: {
type: 'MultiWiggleAdapter',
...obj,
},
})
// allow list of bigwigs in JSON format or line-by-line
let bigWigs: unknown[]
try {
bigWigs = JSON.parse(val)
} catch (e) {
bigWigs = val
.split(/\n|\r\n|\r/)
.map(f => f.trim())
.filter(f => !!f)
}
const obj =
typeof bigWigs[0] === 'string'
? { bigWigs }
: { subadapters: bigWigs }

model.view?.showTrack(trackId)
}
model.clearData()
if (isSessionModelWithWidgets(session)) {
session.hideWidget(model)
if (isSessionWithAddTracks(session)) {
session.addTrackConf({
trackId,
type: 'MultiQuantitativeTrack',
name: trackName,
assemblyNames: [model.assembly],
adapter: {
type: 'MultiWiggleAdapter',
...obj,
},
})

model.view?.showTrack(trackId)
}
model.clearData()
if (isSessionModelWithWidgets(session)) {
session.hideWidget(model)
}
} catch (e) {
console.error(e)
session.notifyError(`${e}`, e)
}
}}
>
Expand Down
4 changes: 2 additions & 2 deletions products/jbrowse-desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,13 @@
"use-query-params": "^2.0.0"
},
"devDependencies": {
"electron": "32.1.0"
"electron": "33.0.2"
},
"browserslist": [
"last 1 chrome version"
],
"build": {
"electronVersion": "32.1.0",
"electronVersion": "33.0.2",
"extraMetadata": {
"main": "build/electron.js"
},
Expand Down
32 changes: 22 additions & 10 deletions website/docs/tutorials/desktop_spec_plugin_tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,24 @@ We'll add some more UI elements that allow us to do something more interesting:

**./src/MyToolWidget/MyToolWidget.tsx**

```jsx
```tsx
import React, { useEffect, useState } from 'react'
import { Box, Button, FormControl, Paper, TextField, Typography } from '@mui/material'
import {
Box,
Button,
FormControl,
Paper,
TextField,
Typography,
} from '@mui/material'
import { makeStyles } from 'tss-react/mui'
import { getSession } from '@jbrowse/core/util'
import { AddTrackModel } from '@jbrowse/plugin-data-management'
import { LocalPathLocation, FileLocation, BlobLocation } from '@jbrowse/core/util/types'
import {
LocalPathLocation,
FileLocation,
BlobLocation,
} from '@jbrowse/core/util/types'
import { getBlob, storeBlobLocation } from '@jbrowse/core/util/tracks'
import { isElectron } from '@jbrowse/core/util'

Expand Down Expand Up @@ -331,27 +342,26 @@ export default function MyToolWidget({ model }: { model: AddTrackModel }) {
}, [model.trackData])

return (
{ /* formatting using paper and other mui elements */ }
<Paper className={classes.paper}>
<p>
This desktop plugin widget will allow you to submit an unindexed{' '}
<code>.vcf</code> file to JBrowse which will then use a script to sort,
index, and zip the file. This circumvents any CLI operations you may
have otherwise needed to do!
</p>
{ /* LocalFileChooser is a component we define below, it allows us to select local files only */ }
{/* LocalFileChooser is a component we define below, it allows us to select local files only */}
<LocalFileChooser
location={model.trackData}
setLocation={model.setTrackData}
setName={setTrackName}
/>
{ /* displays the track name and lets the user edit it to something they wish */ }
{/* displays the track name and lets the user edit it to something they wish */}
<TextField
value={trackName}
onChange={event => setTrackName(event.target.value)}
helperText="Track name"
/>
{ /* the submit button will eventually be responsible for executing our script */ }
{/* the submit button will eventually be responsible for executing our script */}
<Button variant="contained" className={classes.submit} onClick={() => {}}>
Submit
</Button>
Expand All @@ -371,7 +381,7 @@ function LocalFileChooser(props: {
}) {
const { classes } = useStyles()
const { location, setLocation, setName } = props
const [filename, setFilename] = useState(``)
const [filename, setFilename] = useState('')

const needToReload =
location && isBlobLocation(location) && !getBlob(location.blobId)
Expand All @@ -390,17 +400,19 @@ function LocalFileChooser(props: {
const file = target && target.files && target.files[0]
if (file) {
if (isElectron) {
const { webUtils } = window.require('electron')
const path = webUtils.getPathForFile(file)
// here we are setting the location information for the file selected
// these features are necessary for the VcfTabixAdapter
setLocation({
localPath: (file as File & { path: string }).path,
localPath: path,
locationType: 'LocalPathLocation',
})
} else {
setLocation(storeBlobLocation({ blob: file }))
}
// these set ui elements
setFilename((file as File & { path: string }).path)
setFilename(file.name)
setName(file.name)
}
}}
Expand Down
Loading

0 comments on commit 6c5407f

Please sign in to comment.