diff --git a/src/components/Alert/index.tsx b/src/components/Alert/index.tsx new file mode 100644 index 0000000..bb8f86c --- /dev/null +++ b/src/components/Alert/index.tsx @@ -0,0 +1,29 @@ +import Snackbar from "@mui/material/Snackbar"; +import Alert from "@mui/material/Alert"; +import { useState } from "react"; + +type AlertProps = { + severity: "success" | "error", + message: string, +}; + +export default function AlertComponent(props: AlertProps) { + const [isOpen, setIsOpen] = useState(true); + const handleClose = ( + event?: React.SyntheticEvent | Event, + reason?: string + ) => { + if (reason === "clickaway") { + return; + } + setIsOpen(false); + }; + + return ( + + + {props.message} + + + ); +} \ No newline at end of file diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx new file mode 100644 index 0000000..77479f2 --- /dev/null +++ b/src/components/KillButton/index.tsx @@ -0,0 +1,157 @@ +import { useState } from "react"; +import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import CircularProgress from "@mui/material/CircularProgress"; +import DialogTitle from '@mui/material/DialogTitle'; +import DialogContent from '@mui/material/DialogContent'; +import Dialog from '@mui/material/Dialog'; +import Paper from "@mui/material/Paper"; +import Typography from "@mui/material/Typography"; +import Tooltip from '@mui/material/Tooltip'; + +import CodeBlock from "../CodeBlock"; +import type { Run as RunResponse } from "../../lib/paddles.d"; +import { KillRunPayload } from "../../lib/teuthologyAPI.d"; +import { useSession, useRunKill } from "../../lib/teuthologyAPI"; +import Alert from "../Alert"; + + +type KillButtonProps = { + query: UseQueryResult; +}; + +type KillButtonDialogProps = { + mutation: UseMutationResult; + payload: KillRunPayload; + open: boolean; + handleClose: () => void; +}; + +export default function KillButton({query: runQuery}: KillButtonProps) { + const killMutation = useRunKill(); + const [open, setOpen] = useState(false); + const sessionQuery = useSession(); + const data: RunResponse | undefined = runQuery.data; + const run_owner = data?.jobs[0].owner || ""; + const killPayload: KillRunPayload = { + "--run": data?.name || "", + "--owner": run_owner, + "--machine-type": data?.machine_type || "", + "--preserve-queue": true, + } + const loggedUser = sessionQuery.data?.session?.username; + const isUserAdmin = sessionQuery.data?.session?.isUserAdmin; + const owner = killPayload["--owner"].toLowerCase() + const isOwner = (loggedUser?.toLowerCase() == owner) || (`scheduled_${loggedUser?.toLowerCase()}@teuthology` == owner) + const isButtonDisabled = (!isOwner && !isUserAdmin) + + const getHelperMessage = () => { + if (isButtonDisabled) { + return `User (${loggedUser}) does not have admin privileges to kill runs owned by another user (${owner}). `; + } else { + if (!isOwner && isUserAdmin) return `Use admin privileges to kill run owned by '${owner}'. `; + return "Terminate all jobs in this run"; + } + } + + const toggleDialog = () => { + setOpen(!open); + }; + + const refreshAndtoggle = () => { + if (open && !killMutation.isIdle) { // on closing confirmation dialog after kill-run + runQuery.refetch(); + } + toggleDialog(); + killMutation.reset(); + } + + if ((data?.status.includes("finished")) || !(sessionQuery.data?.session?.username)) { + // run finished or user logged out + return null; + } + + + return ( +
+
+ + + + + + +
+ { (killMutation.isError) ? : null } + { (killMutation.isSuccess) ? : null } +
+ ); +}; + +function KillButtonDialog({mutation, open, handleClose, payload}: KillButtonDialogProps) { + return ( +
+ + KILL CONFIRMATION + + { (mutation.isSuccess && mutation.data ) ? +
+ + Successful! + + + + +
: + (mutation.isLoading) ? ( +
+ + + Killing run... + +
+ ) : + (mutation.isError) ? ( +
+ + Failed! + + + + +
+ ) : +
+ + Are you sure you want to kill this run/job? + + +
+ } +
+
+
+ ) +} diff --git a/src/components/Login/index.jsx b/src/components/Login/index.jsx index 1fcf82f..fe07671 100644 --- a/src/components/Login/index.jsx +++ b/src/components/Login/index.jsx @@ -5,19 +5,18 @@ import Menu from '@mui/material/Menu'; import MenuItem from '@mui/material/MenuItem'; import GitHubIcon from '@mui/icons-material/GitHub'; -import { doLogin, doLogout, useSession, useUserData } from "../../lib/teuthologyAPI"; +import { doLogin, doLogout, useSession } from "../../lib/teuthologyAPI"; export default function Login() { const sessionQuery = useSession(); - const userData = useUserData(); - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); + const [dropMenuAnchor, setDropMenuAnchor] = useState(null); + const open = Boolean(dropMenuAnchor); const handleClick = (event) => { - setAnchorEl(event.currentTarget); + setDropMenuAnchor(event.currentTarget); }; const handleClose = () => { - setAnchorEl(null); + setDropMenuAnchor(null); }; if ( ! sessionQuery.isSuccess ) return null; @@ -27,26 +26,21 @@ export default function Login() { {sessionQuery.data?.session ?
Logout
: