Skip to content

Commit

Permalink
Show last autosave on jbrowse-web start screen (#4046)
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Nov 6, 2023
1 parent 2937f7c commit f0063a8
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 120 deletions.
58 changes: 58 additions & 0 deletions products/jbrowse-web/src/components/DeleteSessionDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React, { useState } from 'react'
import {
Button,
DialogActions,
DialogContent,
DialogContentText,
} from '@mui/material'
import { Dialog, ErrorMessage } from '@jbrowse/core/ui'

const DeleteSessionDialog = ({
sessionToDelete,
onClose,
rootModel,
}: {
sessionToDelete?: string
onClose: (_arg0: boolean) => void
rootModel: { removeSavedSession: (arg: { name?: string }) => void }
}) => {
const [error, setError] = useState<unknown>()
return (
<Dialog
open
onClose={() => onClose(false)}
title={`Delete session "${sessionToDelete}"?`}
>
<DialogContent>
{error ? <ErrorMessage error={error} /> : null}
<DialogContentText>This action cannot be undone</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => onClose(false)} color="primary">
Cancel
</Button>
<Button
onClick={() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
;(async () => {
try {
rootModel.removeSavedSession({ name: sessionToDelete })
onClose(true)
} catch (e) {
console.error(e)
setError(e)
}
})()
}}
color="primary"
variant="contained"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
)
}

export default DeleteSessionDialog
67 changes: 31 additions & 36 deletions products/jbrowse-web/src/components/RecentSessionCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,68 +2,63 @@ import React, { useState } from 'react'
import {
IconButton,
ListItem,
ListItemButton,
ListItemIcon,
Menu,
MenuItem,
Tooltip,
Typography,
} from '@mui/material'
import { makeStyles } from 'tss-react/mui'

// icons
import DeleteIcon from '@mui/icons-material/Delete'
import MoreVertIcon from '@mui/icons-material/MoreVert'

const useStyles = makeStyles()({
menu: {
left: '65%',
},
})

function RecentSessionCard({
sessionName,
onClick,
onDelete,
}: {
sessionName: string
onClick: (arg: string) => void
onDelete: (arg: string) => void
onDelete?: (arg: string) => void
}) {
const { classes } = useStyles()
const [menuAnchorEl, setMenuAnchorEl] = useState<HTMLElement | null>(null)

const handleMenuClose = (action: string) => {
setMenuAnchorEl(null)
if (action === 'delete') {
return onDelete(sessionName)
}
return undefined
}

return (
<>
<ListItem onClick={() => onClick(sessionName)} button>
<Tooltip title={sessionName} enterDelay={300}>
<Typography variant="body2" noWrap style={{ width: 250 }}>
{sessionName}
</Typography>
</Tooltip>
<IconButton
className={classes.menu}
onClick={event => {
event.stopPropagation()
setMenuAnchorEl(event.currentTarget)
}}
>
<MoreVertIcon />
</IconButton>
<ListItem
secondaryAction={
<IconButton
onClick={event => {
event.stopPropagation()
setMenuAnchorEl(event.currentTarget)
}}
>
<MoreVertIcon />
</IconButton>
}
>
<ListItemButton onClick={() => onClick(sessionName)}>
<Tooltip title={sessionName} enterDelay={300}>
<Typography variant="body2" noWrap>
{sessionName}
</Typography>
</Tooltip>
</ListItemButton>
</ListItem>
<Menu
id="simple-menu"
anchorEl={menuAnchorEl}
keepMounted
open={Boolean(menuAnchorEl)}
onClose={handleMenuClose}
onClose={() => setMenuAnchorEl(null)}
>
<MenuItem onClick={() => handleMenuClose('delete')}>
<MenuItem
onClick={() => {
setMenuAnchorEl(null)
onDelete?.(sessionName)
}}
disabled={!onDelete}
>
<ListItemIcon>
<DeleteIcon />
</ListItemIcon>
Expand Down
137 changes: 53 additions & 84 deletions products/jbrowse-web/src/components/StartScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import React, { useEffect, useState } from 'react'
import React, { lazy, useEffect, useState } from 'react'
import {
Button,
CircularProgress,
Container,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Grid,
IconButton,
List,
Expand All @@ -19,7 +13,7 @@ import {
Typography,
} from '@mui/material'
import { makeStyles } from 'tss-react/mui'
import { LogoFull, FactoryResetDialog, ErrorMessage } from '@jbrowse/core/ui'
import { LogoFull, ErrorMessage } from '@jbrowse/core/ui'

// icons
import WarningIcon from '@mui/icons-material/Warning'
Expand All @@ -32,6 +26,13 @@ import {
NewSVInspectorSession,
} from './NewSessionCards'
import RecentSessionCard from './RecentSessionCard'
import { localStorageGetItem } from '@jbrowse/core/util'

// lazies
const DeleteSessionDialog = lazy(() => import('./DeleteSessionDialog'))
const FactoryResetDialog = lazy(
() => import('@jbrowse/core/ui/FactoryResetDialog'),
)

const useStyles = makeStyles()(theme => ({
newSession: {
Expand All @@ -45,62 +46,12 @@ const useStyles = makeStyles()(theme => ({
settings: {
float: 'right',
},
list: {
overflow: 'auto',
maxHeight: 200,
},
}))

const DeleteSessionDialog = ({
sessionToDelete,
onClose,
rootModel,
}: {
sessionToDelete?: string
onClose: (_arg0: boolean) => void
rootModel: any
}) => {
const [deleteSession, setDeleteSession] = useState(false)
useEffect(() => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
;(async () => {
try {
if (deleteSession) {
setDeleteSession(false)
rootModel.removeSavedSession({ name: sessionToDelete })
onClose(true)
}
} catch (e) {
setDeleteSession(() => {
throw e
})
}
})()
}, [deleteSession, onClose, rootModel, sessionToDelete])

return (
<Dialog open={!!sessionToDelete} onClose={() => onClose(false)}>
<DialogTitle id="alert-dialog-title">
{`Delete session "${sessionToDelete}"?`}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
This action cannot be undone
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={() => onClose(false)} color="primary">
Cancel
</Button>
<Button
onClick={() => setDeleteSession(true)}
color="primary"
variant="contained"
autoFocus
>
Delete
</Button>
</DialogActions>
</Dialog>
)
}

export default function StartScreen({
rootModel,
onFactoryReset,
Expand Down Expand Up @@ -145,6 +96,10 @@ export default function StartScreen({
})()
}, [rootModel.savedSessions, updateSessionsList])

const lastAutosavedSession = JSON.parse(
localStorageGetItem(rootModel.previousAutosaveId) || '{}',
).session

return !sessionNames ? (
<CircularProgress
style={{
Expand All @@ -158,21 +113,27 @@ export default function StartScreen({
/>
) : (
<>
<FactoryResetDialog
open={reset}
onFactoryReset={onFactoryReset}
onClose={() => {
setReset(false)
}}
/>
<DeleteSessionDialog
rootModel={rootModel}
sessionToDelete={sessionToDelete}
onClose={update => {
setSessionToDelete(undefined)
setUpdateSessionsList(update)
}}
/>
{reset ? (
<React.Suspense fallback={null}>
<FactoryResetDialog
open={reset}
onFactoryReset={onFactoryReset}
onClose={() => setReset(false)}
/>
</React.Suspense>
) : null}
{sessionToDelete ? (
<React.Suspense fallback={null}>
<DeleteSessionDialog
rootModel={rootModel}
sessionToDelete={sessionToDelete}
onClose={update => {
setSessionToDelete(undefined)
setUpdateSessionsList(update)
}}
/>
</React.Suspense>
) : null}
<IconButton
className={classes.settings}
onClick={event => {
Expand Down Expand Up @@ -204,13 +165,8 @@ export default function StartScreen({
<Typography variant="h5" className={classes.header}>
Recent sessions
</Typography>
<List
style={{
overflow: 'auto',
maxHeight: 200,
}}
>
{sessionNames?.map((name: string) => (
<List className={classes.list}>
{sessionNames?.map(name => (
<RecentSessionCard
key={name}
sessionName={name}
Expand All @@ -219,6 +175,19 @@ export default function StartScreen({
/>
))}
</List>
{lastAutosavedSession ? (
<>
<Typography variant="h5" className={classes.header}>
Last autosave session
</Typography>
<List className={classes.list}>
<RecentSessionCard
sessionName={lastAutosavedSession.name}
onClick={() => rootModel.loadAutosaveSession()}
/>
</List>
</>
) : null}
{error ? <ErrorMessage error={error} /> : null}
</div>
</Container>
Expand Down

0 comments on commit f0063a8

Please sign in to comment.