-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement grid bookmark widget #2080
Closed
Closed
Changes from 32 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
92d82fb
Scaffold grid bookmark widget
elliothershberg 0b7114c
Add bookmark widget to lgv hamburger menu
elliothershberg 5ae5563
Set up styles
elliothershberg 37eb8cb
Add placeholder table
elliothershberg 689afff
Render locstring cell as link
elliothershberg 362905b
Make bookmarks observable
elliothershberg 6b3f306
Add optional key attribute to MST Region type
elliothershberg 34de1aa
Pass selected region from rubberband to bookmark
elliothershberg fd30e17
Render rows of bookmarks from MST model
elliothershberg b1f2a3b
Update MST model, make method for add bookmarks
elliothershberg b19e90f
Convert MST array to JS before passing to datagrid
elliothershberg 1c5ef99
Move bookmark array from widget to session model
elliothershberg 6cf1daf
Use session method on rubberband
elliothershberg 707d40f
Render rows from session in bookmark widget
elliothershberg ebd25ee
Refactor rubberband
elliothershberg f92b663
Merge branch 'main' into 157_grid_bookmark_widget
elliothershberg f51616a
Update snaps
elliothershberg dcd47b7
Remove key attribute from Region mst model
elliothershberg 4d1c96c
Implement navigation from links
elliothershberg 91d85f3
Avoid bookmarking same region twice
elliothershberg c213b8b
Update height and width of bookmark widget
elliothershberg 761421c
Add column for removing bookmarks
elliothershberg 433958e
Add icon to bookmark option for rubberband
elliothershberg 4ab634b
Add menu item to bookmark current region in LGV
elliothershberg a91945f
Remove unused exports and theme arg
elliothershberg c631489
Add option to download BED or TSV of bookmarks
elliothershberg 341471d
Create option to clear all bookmarks
elliothershberg 41bd6a1
Remove unused import
elliothershberg de6195d
Disable DataGrid row selection on click
elliothershberg c0ad5b7
Add camera icon for svg export
elliothershberg 5c859b0
Add component level tests for bookmark widget
elliothershberg 8a8c543
Add integration tests for bookmark functionality
elliothershberg a5c8a44
Fix region selection in test
elliothershberg 2603d43
Merge branch 'main' into 157_grid_bookmark_widget
elliothershberg c736f73
Fix CLI README formatting
elliothershberg 0cbadd6
Make bookmark table more compact
elliothershberg c3e6574
Update render test to use snap
elliothershberg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
83 changes: 83 additions & 0 deletions
83
plugins/data-management/src/GridBookmarkWidget/components/ClearBookmarks.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import React, { useState } from 'react' | ||
import { observer } from 'mobx-react' | ||
|
||
import { | ||
Button, | ||
IconButton, | ||
Dialog, | ||
DialogTitle, | ||
Typography, | ||
makeStyles, | ||
} from '@material-ui/core' | ||
import ClearAllIcon from '@material-ui/icons/ClearAll' | ||
import CloseIcon from '@material-ui/icons/Close' | ||
|
||
import { getSession } from '@jbrowse/core/util' | ||
|
||
import { GridBookmarkModel } from '../model' | ||
|
||
const useStyles = makeStyles(() => ({ | ||
closeDialog: { | ||
position: 'absolute', | ||
right: 0, | ||
top: 0, | ||
}, | ||
dialogContainer: { | ||
margin: 15, | ||
}, | ||
clearButton: { | ||
marginBottom: 5, | ||
}, | ||
})) | ||
|
||
function ClearBookmarks({ model }: { model: GridBookmarkModel }) { | ||
const classes = useStyles() | ||
const [dialogOpen, setDialogOpen] = useState(false) | ||
|
||
// @ts-ignore | ||
const { clearAllBookmarks } = getSession(model) | ||
|
||
return ( | ||
<> | ||
<Button | ||
className={classes.clearButton} | ||
startIcon={<ClearAllIcon />} | ||
aria-label="clear bookmarks" | ||
onClick={() => setDialogOpen(true)} | ||
> | ||
Clear bookmarks | ||
</Button> | ||
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)}> | ||
<DialogTitle> | ||
<IconButton | ||
className={classes.closeDialog} | ||
aria-label="close-dialog" | ||
onClick={() => setDialogOpen(false)} | ||
> | ||
<CloseIcon /> | ||
</IconButton> | ||
</DialogTitle> | ||
<div className={classes.dialogContainer}> | ||
<> | ||
<Typography>Clear all bookmarks?</Typography> | ||
<br /> | ||
<div style={{ display: 'flex', justifyContent: 'center' }}> | ||
<Button | ||
variant="contained" | ||
color="primary" | ||
onClick={() => { | ||
clearAllBookmarks() | ||
setDialogOpen(false) | ||
}} | ||
> | ||
Confirm | ||
</Button> | ||
</div> | ||
</> | ||
</div> | ||
</Dialog> | ||
</> | ||
) | ||
} | ||
|
||
export default observer(ClearBookmarks) |
87 changes: 87 additions & 0 deletions
87
plugins/data-management/src/GridBookmarkWidget/components/DeleteBookmark.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import React, { useState } from 'react' | ||
import { observer } from 'mobx-react' | ||
|
||
import { | ||
IconButton, | ||
Button, | ||
Dialog, | ||
DialogTitle, | ||
Typography, | ||
makeStyles, | ||
} from '@material-ui/core' | ||
import DeleteIcon from '@material-ui/icons/Delete' | ||
import CloseIcon from '@material-ui/icons/Close' | ||
|
||
import { getSession } from '@jbrowse/core/util' | ||
|
||
import { GridBookmarkModel } from '../model' | ||
|
||
const useStyles = makeStyles(() => ({ | ||
closeDialog: { | ||
position: 'absolute', | ||
right: 0, | ||
top: 0, | ||
}, | ||
dialogContainer: { | ||
margin: 15, | ||
}, | ||
})) | ||
|
||
function DeleteBookmark({ | ||
locString, | ||
model, | ||
}: { | ||
locString: string | ||
model: GridBookmarkModel | ||
}) { | ||
const classes = useStyles() | ||
const [dialogOpen, setDialogOpen] = useState(false) | ||
|
||
// @ts-ignore | ||
const { removeBookmark } = getSession(model) | ||
|
||
return ( | ||
<> | ||
<IconButton | ||
data-testid="deleteBookmark" | ||
aria-label="delete" | ||
onClick={() => setDialogOpen(true)} | ||
> | ||
<DeleteIcon /> | ||
</IconButton> | ||
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)}> | ||
<DialogTitle> | ||
<IconButton | ||
className={classes.closeDialog} | ||
aria-label="close-dialog" | ||
onClick={() => setDialogOpen(false)} | ||
> | ||
<CloseIcon /> | ||
</IconButton> | ||
</DialogTitle> | ||
<div className={classes.dialogContainer}> | ||
<> | ||
<Typography> | ||
Remove <code>{locString}</code>? | ||
</Typography> | ||
<br /> | ||
<div style={{ display: 'flex', justifyContent: 'center' }}> | ||
<Button | ||
variant="contained" | ||
color="primary" | ||
onClick={() => { | ||
removeBookmark(locString) | ||
setDialogOpen(false) | ||
}} | ||
> | ||
Confirm | ||
</Button> | ||
</div> | ||
</> | ||
</div> | ||
</Dialog> | ||
</> | ||
) | ||
} | ||
|
||
export default observer(DeleteBookmark) |
135 changes: 135 additions & 0 deletions
135
plugins/data-management/src/GridBookmarkWidget/components/DownloadBookmarks.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
import React, { useState } from 'react' | ||
import { observer } from 'mobx-react' | ||
import { saveAs } from 'file-saver' | ||
|
||
import { | ||
IconButton, | ||
Button, | ||
Dialog, | ||
DialogTitle, | ||
Select, | ||
MenuItem, | ||
makeStyles, | ||
} from '@material-ui/core' | ||
import CloseIcon from '@material-ui/icons/Close' | ||
import GetAppIcon from '@material-ui/icons/GetApp' | ||
|
||
import { getSession } from '@jbrowse/core/util' | ||
import { Region } from '@jbrowse/core/util/types' | ||
|
||
import { GridBookmarkModel } from '../model' | ||
|
||
function downloadBookmarkFile(bookmarkedRegions: Region[], fileFormat: string) { | ||
const fileHeader = | ||
fileFormat === 'TSV' | ||
? 'chrom\tstart\tend\tassembly_name\tcoord_range\n' | ||
: '' | ||
|
||
const fileContents = bookmarkedRegions | ||
.map(b => { | ||
if (fileFormat === 'BED') { | ||
return `${b.refName}\t${b.start}\t${b.end}\n` | ||
} else { | ||
const locString = `${b.refName}:${b.start}..${b.end}` | ||
return `${b.refName}\t${b.start}\t${b.end}\t${b.assemblyName}\t${locString}\n` | ||
} | ||
}) | ||
.reduce((a, b) => a + b, fileHeader) | ||
|
||
const blob = new Blob([fileContents || ''], { | ||
type: | ||
fileFormat === 'BED' | ||
? 'text/x-bed;charset=utf-8' | ||
: 'text/tab-separated-values;charset=utf-8', | ||
}) | ||
|
||
saveAs(blob, `jbrowse_bookmarks.${fileFormat === 'BED' ? 'bed' : 'tsv'}`) | ||
} | ||
|
||
const useStyles = makeStyles(() => ({ | ||
closeDialog: { | ||
position: 'absolute', | ||
right: 0, | ||
top: 0, | ||
}, | ||
dialogContainer: { | ||
margin: 15, | ||
}, | ||
downloadButton: { | ||
marginBottom: 5, | ||
}, | ||
flexItem: { | ||
margin: 5, | ||
}, | ||
flexContainer: { | ||
display: 'flex', | ||
justifyContent: 'space-evenly', | ||
width: 200, | ||
}, | ||
})) | ||
|
||
function DownloadBookmarks({ model }: { model: GridBookmarkModel }) { | ||
const classes = useStyles() | ||
const [dialogOpen, setDialogOpen] = useState(false) | ||
const [fileType, setFileType] = useState('BED') | ||
|
||
const handleChange = (event: React.ChangeEvent<{ value: unknown }>) => { | ||
setFileType(event.target.value as string) | ||
} | ||
|
||
// @ts-ignore | ||
const { bookmarkedRegions } = getSession(model) | ||
|
||
return ( | ||
<> | ||
<Button | ||
className={classes.downloadButton} | ||
startIcon={<GetAppIcon />} | ||
onClick={() => setDialogOpen(true)} | ||
> | ||
Download | ||
</Button> | ||
<Dialog open={dialogOpen} onClose={() => setDialogOpen(false)}> | ||
<DialogTitle> | ||
<IconButton | ||
className={classes.closeDialog} | ||
aria-label="close-dialog" | ||
onClick={() => setDialogOpen(false)} | ||
> | ||
<CloseIcon /> | ||
</IconButton> | ||
</DialogTitle> | ||
<div className={classes.dialogContainer}> | ||
<> | ||
<div className={classes.flexContainer}> | ||
<Select | ||
className={classes.flexItem} | ||
data-testid="selectFileType" | ||
value={fileType} | ||
onChange={handleChange} | ||
> | ||
<MenuItem value="BED">BED</MenuItem> | ||
<MenuItem value="TSV">TSV</MenuItem> | ||
</Select> | ||
<Button | ||
className={classes.flexItem} | ||
data-testid="dialogDownload" | ||
variant="contained" | ||
color="primary" | ||
startIcon={<GetAppIcon />} | ||
onClick={() => { | ||
downloadBookmarkFile(bookmarkedRegions, fileType) | ||
setDialogOpen(false) | ||
}} | ||
> | ||
Download | ||
</Button> | ||
</div> | ||
</> | ||
</div> | ||
</Dialog> | ||
</> | ||
) | ||
} | ||
|
||
export default observer(DownloadBookmarks) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the code sensitive to these MIME types?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just thought there was something specialized where the mime types needed to be special. I guess it probably isn't that consequential, but is there a source for how these were chosen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It just ends up telling the file downloader what the file type is when it's downloaded, works for me locally at least on MacOS.
Types were both found from Wikipedia: