diff --git a/src/components/confirm-buttons.tsx b/src/components/confirm-buttons.tsx new file mode 100644 index 00000000..25cb242c --- /dev/null +++ b/src/components/confirm-buttons.tsx @@ -0,0 +1,72 @@ +import { Box, Button, Chip, IconButton, SvgIconTypeMap } from '@mui/material'; +import React, { useState } from 'react'; +import { useTranslator } from '../hooks'; +import CloseIcon from '@mui/icons-material/Close'; +import { OverridableComponent } from '@mui/material/OverridableComponent'; + +export function ConfirmButton(props: { + onConfirm: () => void; + confirmationText: string; + icon: + | JSX.Element + | (OverridableComponent> & { + muiName: string; + }); + name?: string | undefined; + remainAfterConfirmation?: boolean; + remainText?: string; +}): JSX.Element | null { + const [clicked, setClicked] = useState(false); + const [confirmed, setConfirmed] = useState(false); + + return ( + + {clicked ? ( + props.remainAfterConfirmation && confirmed ? ( + + ) : ( + + ) + ) : ( + setClicked(true)}> + {props.icon} + + )} + + ); +} + +export function ConfirmDeleteButton(props: { + clickHandler: () => void; + name?: string; +}): JSX.Element | null { + const trans = useTranslator('jupyterlab'); + + const buttonTitle = props.name + ? trans.__('Delete "%1"', props.name) + : trans.__('Delete job'); + + return ( + } + /> + ); +} diff --git a/src/components/confirm-delete-button.tsx b/src/components/confirm-delete-button.tsx deleted file mode 100644 index 9f189d40..00000000 --- a/src/components/confirm-delete-button.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; - -import { - Button, - Dialog, - DialogTitle, - DialogContent, - DialogContentText, - DialogActions -} from '@mui/material'; -import { useTranslator } from '../hooks'; - -export const ConfirmDeleteButton = (props: { - handleDelete: () => Promise; - title: string; - text?: string; -}): JSX.Element => { - const [open, setOpen] = React.useState(false); - - const trans = useTranslator('jupyterlab'); - - const handleClose = () => { - setOpen(false); - }; - - return ( - <> - - - {props.title} - {props.text && ( - - {props.text} - - )} - - - - - - - ); -}; diff --git a/src/components/confirm-delete-icon.tsx b/src/components/confirm-delete-icon.tsx deleted file mode 100644 index 2d8da87c..00000000 --- a/src/components/confirm-delete-icon.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Box, Button, IconButton } from '@mui/material'; -import React, { useState } from 'react'; -import { useTranslator } from '../hooks'; -import CloseIcon from '@mui/icons-material/Close'; - -export function ConfirmDeleteIcon(props: { - name: string | undefined; - clickHandler: () => void; -}): JSX.Element | null { - const [clicked, setClicked] = useState(false); - - const trans = useTranslator('jupyterlab'); - - const buttonTitle = props.name - ? trans.__('Delete "%1"', props.name) - : trans.__('Delete job'); - - return ( - - {clicked ? ( - - ) : ( - setClicked(true)}> - - - )} - - ); -} diff --git a/src/components/confirm-dialog-buttons.tsx b/src/components/confirm-dialog-buttons.tsx new file mode 100644 index 00000000..d042b1c0 --- /dev/null +++ b/src/components/confirm-dialog-buttons.tsx @@ -0,0 +1,105 @@ +import React, { useState } from 'react'; + +import { + Button, + Dialog, + DialogTitle, + DialogContent, + DialogContentText, + DialogActions, + useTheme +} from '@mui/material'; +import { useTranslator } from '../hooks'; + +export const ConfirmDialogButton = (props: { + onConfirm: () => Promise; + title: string; + dialogText: string; + dialogConfirmText: string; + variant?: 'text' | 'contained' | 'outlined'; + errorColor?: boolean; + pendingConfirmText?: string; +}): JSX.Element => { + const [open, setOpen] = useState(false); + + const trans = useTranslator('jupyterlab'); + const theme = useTheme(); + + const handleClose = () => { + setOpen(false); + }; + + return ( + <> + + + {props.title} + + {props.dialogText} + + + + + + + + ); +}; + +export const ConfirmDialogDeleteButton = (props: { + handleDelete: () => Promise; + title: string; + dialogText: string; +}): JSX.Element => { + const trans = useTranslator('jupyterlab'); + return ( + + ); +}; + +export const ConfirmDialogStopButton = (props: { + handleStop: () => Promise; + title: string; + dialogText: string; +}): JSX.Element => { + const trans = useTranslator('jupyterlab'); + return ( + + ); +}; diff --git a/src/components/job-definition-row.tsx b/src/components/job-definition-row.tsx index 53b19b7b..82f7f035 100644 --- a/src/components/job-definition-row.tsx +++ b/src/components/job-definition-row.tsx @@ -15,7 +15,7 @@ import TableCell from '@mui/material/TableCell'; import { Scheduler, SchedulerService } from '../handler'; import { useTranslator } from '../hooks'; import { TranslationBundle } from '@jupyterlab/translation'; -import { ConfirmDeleteIcon } from './confirm-delete-icon'; +import { ConfirmDeleteButton } from './confirm-buttons'; function CreatedAt(props: { job: Scheduler.IDescribeJobDefinition; @@ -117,7 +117,7 @@ export function buildJobDefinitionRow( forceReload(); }} /> - { await ss.deleteJobDefinition(jobDef.job_definition_id); diff --git a/src/components/job-row.tsx b/src/components/job-row.tsx index 0f326094..bc580b2e 100644 --- a/src/components/job-row.tsx +++ b/src/components/job-row.tsx @@ -1,19 +1,15 @@ import React, { useState } from 'react'; import { JupyterFrontEnd } from '@jupyterlab/application'; - -import DownloadIcon from '@mui/icons-material/Download'; -import StopIcon from '@mui/icons-material/Stop'; -import IconButton from '@mui/material/IconButton'; -import { Stack, TableCell, TableRow } from '@mui/material'; - -import { ConfirmDeleteIcon } from './confirm-delete-icon'; +import { ConfirmDeleteButton, ConfirmButton } from './confirm-buttons'; import { JobFileLink } from './job-file-link'; - import { CommandIDs } from '..'; import { Scheduler } from '../handler'; import { useTranslator } from '../hooks'; import { ICreateJobModel } from '../model'; +import DownloadIcon from '@mui/icons-material/Download'; +import StopIcon from '@mui/icons-material/Stop'; +import { IconButton, Stack, TableCell, TableRow } from '@mui/material'; function StopButton(props: { job: Scheduler.IDescribeJob; @@ -28,9 +24,14 @@ function StopButton(props: {
- - - + } + remainAfterConfirmation + remainText={trans.__('Stopping')} + />
); } @@ -117,15 +118,7 @@ export function buildJobRow( , translateStatus(job.status), - - app.commands.execute(CommandIDs.stopJob, { - id: job.job_id - }) - } - /> - { // optimistic delete for now, no verification on whether the delete @@ -136,6 +129,14 @@ export function buildJobRow( deleteRow(job.job_id); }} /> + + app.commands.execute(CommandIDs.stopJob, { + id: job.job_id + }) + } + /> ]; diff --git a/src/mainviews/detail-view/job-definition.tsx b/src/mainviews/detail-view/job-definition.tsx index 8c535f8e..8e073b44 100644 --- a/src/mainviews/detail-view/job-definition.tsx +++ b/src/mainviews/detail-view/job-definition.tsx @@ -13,7 +13,7 @@ import { ListJobsTable } from '../list-jobs'; import { Scheduler as SchedulerTokens } from '../../tokens'; import { Button, Card, CardContent, FormLabel, Stack } from '@mui/material'; -import { ConfirmDeleteButton } from '../../components/confirm-delete-button'; +import { ConfirmDialogDeleteButton } from '../../components/confirm-dialog-buttons'; import { JupyterFrontEnd } from '@jupyterlab/application'; import { ILabeledValueProps, @@ -97,10 +97,10 @@ export function JobDefinition(props: IJobDefinitionProps): JSX.Element { > {trans.__('Edit Job Definition')} - diff --git a/src/mainviews/detail-view/job-detail.tsx b/src/mainviews/detail-view/job-detail.tsx index 6ef8f9bc..17bd52d2 100644 --- a/src/mainviews/detail-view/job-detail.tsx +++ b/src/mainviews/detail-view/job-detail.tsx @@ -2,7 +2,10 @@ import React, { useState } from 'react'; import { JupyterFrontEnd } from '@jupyterlab/application'; -import { ConfirmDeleteButton } from '../../components/confirm-delete-button'; +import { + ConfirmDialogDeleteButton, + ConfirmDialogStopButton +} from '../../components/confirm-dialog-buttons'; import { JobFileLink } from '../../components/job-file-link'; import { Scheduler, SchedulerService } from '../../handler'; import { useTranslator } from '../../hooks'; @@ -97,14 +100,16 @@ export function JobDetail(props: IJobDetailProps): JSX.Element { )} {props.model.status === 'IN_PROGRESS' && ( - + )} - );