From 8dbf46995f9e9a1b7f10dfe0a5624b7abb43357d Mon Sep 17 00:00:00 2001 From: Devansh3712 Date: Sun, 13 Aug 2023 22:20:12 +0530 Subject: [PATCH 01/15] pages/Run/index.tsx: Add kill run button Signed-off-by: Devansh3712 --- src/pages/Run/index.tsx | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index a71382c..bd343c7 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -2,6 +2,7 @@ import { PropsWithChildren } from 'react' import { useQueryParams, StringParam, NumberParam } from "use-query-params"; import { styled } from "@mui/material/styles"; import { useParams } from "react-router-dom"; +import { useState } from "react"; import Typography from "@mui/material/Typography"; import { format } from "date-fns"; import { Helmet } from "react-helmet"; @@ -42,6 +43,28 @@ export default function Run() { page: NumberParam, pageSize: NumberParam, }); + const [kill, setKill] = useState(false); + const [success, setSuccess] = useState(false); + const [error, setError] = useState(false); + const killRun = async () => { + setKill(true); + // Using a mock API endpoint for testing + const response = await fetch("https://reqres.in/api/users/2?delay=3"); + const status = response.status; + if (status === 200) setSuccess(true); + else setError(true); + setKill(false); + }; + const handleClose = ( + event?: React.SyntheticEvent | Event, + reason?: string + ) => { + if (reason === "clickaway") { + return; + } + setSuccess(false); + setError(false); + }; const { name } = useParams(); const query = useRun(name === undefined ? "" : name); if (query === null) return 404; From 72487d5cad0f8247a7dab6a085bade046314c41f Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Sat, 2 Dec 2023 02:23:19 +0530 Subject: [PATCH 02/15] Add component Alert and KillButton 1. create `Alert` and `KillButton` components 2. lib/teuthologyAPI: add useRunKill hook (which uses `useMutation` to send POST req at /kill to t-api) 3. create lib/teuthologyAPI.d.ts and add 'KillRun' Signed-off-by: Vallari Agrawal --- src/components/Alert/index.tsx | 29 +++++++++++++++++++ src/components/KillButton/index.tsx | 43 +++++++++++++++++++++++++++++ src/lib/paddles.d.ts | 1 + src/lib/teuthologyAPI.d.ts | 7 +++++ src/lib/teuthologyAPI.ts | 21 ++++++++++++-- src/pages/Run/index.tsx | 33 +++++++--------------- 6 files changed, 108 insertions(+), 26 deletions(-) create mode 100644 src/components/Alert/index.tsx create mode 100644 src/components/KillButton/index.tsx create mode 100644 src/lib/teuthologyAPI.d.ts 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..5f32eec --- /dev/null +++ b/src/components/KillButton/index.tsx @@ -0,0 +1,43 @@ +import type { UseMutationResult } from "@tanstack/react-query"; +import Button from "@mui/material/Button"; +import Box from "@mui/material/Box"; +import { CircularProgress } from "@mui/material"; + +import { KillRun } from "../../lib/teuthologyAPI.d"; +import Alert from "../Alert"; + + +type KillButtonProps = { + mutation: UseMutationResult; + text: string; + payload: KillRun; +}; + + +export default function KillButton(props: KillButtonProps) { + const mutation: UseMutationResult = props.mutation; + + + return ( +
+
+ + {(mutation.isLoading) ? ( + + + + ) : null} +
+ { (mutation.isError) ? : null } + { (mutation.isSuccess) ? : null } +
+ ); +}; diff --git a/src/lib/paddles.d.ts b/src/lib/paddles.d.ts index aa3c086..107f9af 100644 --- a/src/lib/paddles.d.ts +++ b/src/lib/paddles.d.ts @@ -76,6 +76,7 @@ export type Run = { results: RunResults; machine_type: string; status: RunStatus; + user: string; }; export type Node = { diff --git a/src/lib/teuthologyAPI.d.ts b/src/lib/teuthologyAPI.d.ts new file mode 100644 index 0000000..85fd2b8 --- /dev/null +++ b/src/lib/teuthologyAPI.d.ts @@ -0,0 +1,7 @@ + +export type KillRun = { + "--run": string, + "--owner": string, + "--machine-type": string, + "--user": string, +} diff --git a/src/lib/teuthologyAPI.ts b/src/lib/teuthologyAPI.ts index 41f6651..07b1bd8 100644 --- a/src/lib/teuthologyAPI.ts +++ b/src/lib/teuthologyAPI.ts @@ -1,7 +1,7 @@ import axios from "axios"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery, useMutation } from "@tanstack/react-query"; +import type { UseQueryResult, UseMutationResult } from "@tanstack/react-query"; import { Cookies } from "react-cookie"; -import type { UseQueryResult } from "@tanstack/react-query"; const TEUTHOLOGY_API_SERVER = import.meta.env.VITE_TEUTHOLOGY_API || ""; @@ -56,9 +56,24 @@ function useUserData(): Map { return new Map(); } +function useRunKill(): UseMutationResult { + const url = getURL("/kill?dry_run=false&logs=true"); + const mutation: UseMutationResult = useMutation({ + mutationKey: ['run-kill', { url }], + mutationFn: (payload) => ( + axios.post(url, payload, { + withCredentials: true + }) + ), + retry: 0, + }); + return mutation; +} + export { doLogin, doLogout, useSession, - useUserData + useUserData, + useRunKill, } diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index bd343c7..fa0f698 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -2,7 +2,6 @@ import { PropsWithChildren } from 'react' import { useQueryParams, StringParam, NumberParam } from "use-query-params"; import { styled } from "@mui/material/styles"; import { useParams } from "react-router-dom"; -import { useState } from "react"; import Typography from "@mui/material/Typography"; import { format } from "date-fns"; import { Helmet } from "react-helmet"; @@ -10,8 +9,11 @@ import { Helmet } from "react-helmet"; import type { Run as Run_, RunParams } from "../../lib/paddles.d"; import { useRun } from "../../lib/paddles"; +import { useRunKill } from "../../lib/teuthologyAPI"; import JobList from "../../components/JobList"; import Link from "../../components/Link"; +import KillButton from "../../components/KillButton"; +import { KillRun } from '../../lib/teuthologyAPI.d'; const PREFIX = "index"; @@ -43,29 +45,8 @@ export default function Run() { page: NumberParam, pageSize: NumberParam, }); - const [kill, setKill] = useState(false); - const [success, setSuccess] = useState(false); - const [error, setError] = useState(false); - const killRun = async () => { - setKill(true); - // Using a mock API endpoint for testing - const response = await fetch("https://reqres.in/api/users/2?delay=3"); - const status = response.status; - if (status === 200) setSuccess(true); - else setError(true); - setKill(false); - }; - const handleClose = ( - event?: React.SyntheticEvent | Event, - reason?: string - ) => { - if (reason === "clickaway") { - return; - } - setSuccess(false); - setError(false); - }; const { name } = useParams(); + const killMutation = useRunKill(); const query = useRun(name === undefined ? "" : name); if (query === null) return 404; if (query.isError) return null; @@ -75,6 +56,12 @@ export default function Run() { const date = query.data?.scheduled ? format(new Date(query.data.scheduled), "yyyy-MM-dd") : null; + const killPayload: KillRun = { + "--run": data?.name || "", + "--owner": data?.user || "", + "--machine-type": data?.machine_type || "", + "--user": data?.user || "", + } return ( From d3c9118f7f87f5b84b2775b6e954b02de282edf3 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Wed, 3 Jan 2024 16:17:23 +0530 Subject: [PATCH 03/15] Optionally show & disable kill-run btn new features: 1. Disable kill-run button for finished runs 2. Hide kill-run button for users who don't own the run Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 16 ++++++++++++---- src/lib/paddles.d.ts | 1 + src/lib/teuthologyAPI.d.ts | 9 ++++++++- src/lib/teuthologyAPI.ts | 5 +++-- src/pages/Run/index.tsx | 13 ++++++++++--- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index 5f32eec..9ca5526 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -3,20 +3,28 @@ import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; import { CircularProgress } from "@mui/material"; -import { KillRun } from "../../lib/teuthologyAPI.d"; +import { KillRunPayload } from "../../lib/teuthologyAPI.d"; +import { useSession } from "../../lib/teuthologyAPI"; import Alert from "../Alert"; type KillButtonProps = { mutation: UseMutationResult; text: string; - payload: KillRun; + payload: KillRunPayload; + disabled?: boolean; }; export default function KillButton(props: KillButtonProps) { const mutation: UseMutationResult = props.mutation; - + const sessionQuery = useSession(); + const loggedUser = sessionQuery.data?.session.username; + + if (loggedUser?.toLowerCase() != props.payload["--user"].toLowerCase()) { + // logged user and owner of the job should be equal (case insensitive) + return null + } return (
@@ -26,7 +34,7 @@ export default function KillButton(props: KillButtonProps) { color="error" size="large" onClick={() => mutation.mutate(props.payload)} - disabled={(mutation.isLoading)} + disabled={(props.disabled || mutation.isLoading)} > {props.text} diff --git a/src/lib/paddles.d.ts b/src/lib/paddles.d.ts index 107f9af..e72fe81 100644 --- a/src/lib/paddles.d.ts +++ b/src/lib/paddles.d.ts @@ -42,6 +42,7 @@ export type Job = { roles: NodeRoles[]; os_type: string; os_version: string; + owner: string; }; export type NodeRoles = string[]; diff --git a/src/lib/teuthologyAPI.d.ts b/src/lib/teuthologyAPI.d.ts index 85fd2b8..3a8aa35 100644 --- a/src/lib/teuthologyAPI.d.ts +++ b/src/lib/teuthologyAPI.d.ts @@ -1,5 +1,12 @@ -export type KillRun = { +export type Session = { + session: { + id: int, + username: string + } +} + +export type KillRunPayload = { "--run": string, "--owner": string, "--machine-type": string, diff --git a/src/lib/teuthologyAPI.ts b/src/lib/teuthologyAPI.ts index 07b1bd8..574c335 100644 --- a/src/lib/teuthologyAPI.ts +++ b/src/lib/teuthologyAPI.ts @@ -2,6 +2,7 @@ import axios from "axios"; import { useQuery, useMutation } from "@tanstack/react-query"; import type { UseQueryResult, UseMutationResult } from "@tanstack/react-query"; import { Cookies } from "react-cookie"; +import { Session } from "./teuthologyAPI.d" const TEUTHOLOGY_API_SERVER = import.meta.env.VITE_TEUTHOLOGY_API || ""; @@ -25,9 +26,9 @@ function doLogout() { window.location.href = url; } -function useSession(): UseQueryResult { +function useSession(): UseQueryResult { const url = getURL("/"); - const query = useQuery({ + const query = useQuery({ queryKey: ['ping-api', { url }], queryFn: () => ( axios.get(url, { diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index fa0f698..0922ff5 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -13,7 +13,7 @@ import { useRunKill } from "../../lib/teuthologyAPI"; import JobList from "../../components/JobList"; import Link from "../../components/Link"; import KillButton from "../../components/KillButton"; -import { KillRun } from '../../lib/teuthologyAPI.d'; +import { KillRunPayload } from '../../lib/teuthologyAPI.d'; const PREFIX = "index"; @@ -56,9 +56,10 @@ export default function Run() { const date = query.data?.scheduled ? format(new Date(query.data.scheduled), "yyyy-MM-dd") : null; - const killPayload: KillRun = { + const run_owner = data?.jobs[0].owner || ""; + const killPayload: KillRunPayload = { "--run": data?.name || "", - "--owner": data?.user || "", + "--owner": run_owner, "--machine-type": data?.machine_type || "", "--user": data?.user || "", } @@ -82,6 +83,12 @@ export default function Run() { date
+
); From 727e0eab9b14b9e6c7339328ab7a663677d9358d Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Mon, 12 Feb 2024 14:59:02 +0530 Subject: [PATCH 04/15] components/KillButton: add KillButtonDialog component This commit also removes "--user" from the t-api /kill route request. Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 82 +++++++++++++++++++++++++---- src/lib/teuthologyAPI.d.ts | 3 +- src/pages/Run/index.tsx | 1 - 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index 9ca5526..0febf82 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -1,7 +1,13 @@ +import { useState } from "react"; import type { UseMutationResult } from "@tanstack/react-query"; import Button from "@mui/material/Button"; import Box from "@mui/material/Box"; -import { CircularProgress } from "@mui/material"; +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 { KillRunPayload } from "../../lib/teuthologyAPI.d"; import { useSession } from "../../lib/teuthologyAPI"; @@ -15,17 +21,29 @@ type KillButtonProps = { disabled?: boolean; }; +type KillButtonDialogProps = { + mutation: UseMutationResult; + payload: KillRunPayload; + open: boolean; + handleClose: () => void; +}; export default function KillButton(props: KillButtonProps) { + const [open, setOpen] = useState(false); const mutation: UseMutationResult = props.mutation; const sessionQuery = useSession(); const loggedUser = sessionQuery.data?.session.username; - if (loggedUser?.toLowerCase() != props.payload["--user"].toLowerCase()) { + if (loggedUser?.toLowerCase() != props.payload["--owner"].toLowerCase()) { // logged user and owner of the job should be equal (case insensitive) return null } + const toggleDialog = () => { + setOpen(!open); + }; + + return (
@@ -33,19 +51,65 @@ export default function KillButton(props: KillButtonProps) { variant="contained" color="error" size="large" - onClick={() => mutation.mutate(props.payload)} + onClick={toggleDialog} disabled={(props.disabled || mutation.isLoading)} > {props.text} - {(mutation.isLoading) ? ( - - - - ) : null} +
{ (mutation.isError) ? : null } - { (mutation.isSuccess) ? : null } + { (mutation.isSuccess) ? : null }
); }; + +function KillButtonDialog({mutation, open, handleClose, payload}: KillButtonDialogProps) { + return ( +
+ + Kill confirmation + + { (mutation.data && mutation.data.data ) ? +
+ + {mutation.isSuccess ? "Successful!": "Failed!"} + + + + {mutation.data.data.logs} + + +
: + (mutation.isLoading) ? ( + + + + Killing run... + + + ) : +
+ + Are you sure you want to kill this run/job? + + +
+ } +
+
+
+ ) +} diff --git a/src/lib/teuthologyAPI.d.ts b/src/lib/teuthologyAPI.d.ts index 3a8aa35..9404c2e 100644 --- a/src/lib/teuthologyAPI.d.ts +++ b/src/lib/teuthologyAPI.d.ts @@ -9,6 +9,5 @@ export type Session = { export type KillRunPayload = { "--run": string, "--owner": string, - "--machine-type": string, - "--user": string, + "--machine-type": string, } diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index 0922ff5..c4a4912 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -61,7 +61,6 @@ export default function Run() { "--run": data?.name || "", "--owner": run_owner, "--machine-type": data?.machine_type || "", - "--user": data?.user || "", } return ( From 4b5680ff5b472332c05092902de6dd8cadb868e1 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Wed, 14 Feb 2024 10:02:08 +0530 Subject: [PATCH 05/15] components/KillButton: improve error handling Show error message received in response from api when killing a run. This commit also includes some minor UI improvements on KillButtonDialog. And removes "dry_run" query param from "useRunKill". Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 33 ++++++++++++++++++++--------- src/lib/teuthologyAPI.ts | 2 +- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index 0febf82..e9dd637 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -32,7 +32,7 @@ export default function KillButton(props: KillButtonProps) { const [open, setOpen] = useState(false); const mutation: UseMutationResult = props.mutation; const sessionQuery = useSession(); - const loggedUser = sessionQuery.data?.session.username; + const loggedUser = sessionQuery.data?.session?.username; if (loggedUser?.toLowerCase() != props.payload["--owner"].toLowerCase()) { // logged user and owner of the job should be equal (case insensitive) @@ -53,6 +53,7 @@ export default function KillButton(props: KillButtonProps) { size="large" onClick={toggleDialog} disabled={(props.disabled || mutation.isLoading)} + sx={{ marginBottom: "12px" }} > {props.text} @@ -73,27 +74,39 @@ function KillButtonDialog({mutation, open, handleClose, payload}: KillButtonDial return (
- Kill confirmation + KILL CONFIRMATION - { (mutation.data && mutation.data.data ) ? + { (mutation.isSuccess && mutation.data ) ?
- - {mutation.isSuccess ? "Successful!": "Failed!"} + + Successful! - {mutation.data.data.logs} + {mutation.data?.data?.logs}
: (mutation.isLoading) ? ( - - - +
+ + Killing run... - +
) : + (mutation.isError) ? ( +
+ + Failed! + + + + {mutation.error?.response?.data?.detail} + + +
+ ) :
Are you sure you want to kill this run/job? diff --git a/src/lib/teuthologyAPI.ts b/src/lib/teuthologyAPI.ts index 574c335..4ae0abd 100644 --- a/src/lib/teuthologyAPI.ts +++ b/src/lib/teuthologyAPI.ts @@ -58,7 +58,7 @@ function useUserData(): Map { } function useRunKill(): UseMutationResult { - const url = getURL("/kill?dry_run=false&logs=true"); + const url = getURL("/kill?logs=true"); const mutation: UseMutationResult = useMutation({ mutationKey: ['run-kill', { url }], mutationFn: (payload) => ( From d645fb4dcb5d12f957e96817bcfe6ac5488db07c Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Wed, 24 Apr 2024 21:46:08 +0530 Subject: [PATCH 06/15] KillButton: Add "Kill as Admin" btn If the run belongs to the logged-in user, then it'll show "Kill" button. If not, then "Kill As Admin" btn. For now, pulpito-ng does not verify if user has admin privileges. That check happens on t-api after the request is sent. This commit also refreshes the mutation obj for kill-button, upon button click. This fixes the issue of retrying to kill runs by clicking the button again. Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 29 +++++++++++++++-------------- src/pages/Run/index.tsx | 1 - 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index e9dd637..48bb719 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -16,7 +16,6 @@ import Alert from "../Alert"; type KillButtonProps = { mutation: UseMutationResult; - text: string; payload: KillRunPayload; disabled?: boolean; }; @@ -34,14 +33,16 @@ export default function KillButton(props: KillButtonProps) { const sessionQuery = useSession(); const loggedUser = sessionQuery.data?.session?.username; - if (loggedUser?.toLowerCase() != props.payload["--owner"].toLowerCase()) { - // logged user and owner of the job should be equal (case insensitive) - return null - } + const isOwner = (loggedUser?.toLowerCase() == props.payload["--owner"].toLowerCase()) const toggleDialog = () => { setOpen(!open); }; + + const refreshAndtoggle = () => { + toggleDialog(); + mutation.reset(); + } return ( @@ -51,11 +52,11 @@ export default function KillButton(props: KillButtonProps) { variant="contained" color="error" size="large" - onClick={toggleDialog} + onClick={refreshAndtoggle} disabled={(props.disabled || mutation.isLoading)} sx={{ marginBottom: "12px" }} > - {props.text} + {(isOwner) ? "Kill" : "Kill As Admin"} { (mutation.isSuccess && mutation.data ) ?
- - Successful! - - - - {mutation.data?.data?.logs} + + Successful! - + + + {mutation.data?.data?.logs} + +
: (mutation.isLoading) ? (
diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index c4a4912..1cd906b 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -84,7 +84,6 @@ export default function Run() {
From 75eb9516356eeb7d2209f6488ebf844746fa3ab4 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Thu, 25 Apr 2024 15:09:50 +0530 Subject: [PATCH 07/15] components/KillButton: Owner can also be "scheduled_@teuthology" "scheduled_@teuthology" is the default owner name if run is scheduled from teuthology CLI tool. This commit allows users of same github username to recognize it as their jobs. Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index 48bb719..71a5442 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -33,7 +33,8 @@ export default function KillButton(props: KillButtonProps) { const sessionQuery = useSession(); const loggedUser = sessionQuery.data?.session?.username; - const isOwner = (loggedUser?.toLowerCase() == props.payload["--owner"].toLowerCase()) + const owner = props.payload["--owner"].toLowerCase() + const isOwner = (loggedUser?.toLowerCase() == owner) || (`scheduled_${loggedUser?.toLowerCase()}@teuthology` == owner) const toggleDialog = () => { setOpen(!open); From fa407b4fca0608f04e2f490fd2117ed0d2da49a6 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 10 May 2024 17:09:23 +0530 Subject: [PATCH 08/15] KillButton: disable when user is not admin Read "isUserAdmin" from useSession and disable "Kill as Admin" button if isUserAdmin is false Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 10 ++++++++-- src/lib/teuthologyAPI.d.ts | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index 71a5442..d9d330b 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -8,6 +8,7 @@ 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 { KillRunPayload } from "../../lib/teuthologyAPI.d"; import { useSession } from "../../lib/teuthologyAPI"; @@ -32,7 +33,7 @@ export default function KillButton(props: KillButtonProps) { const mutation: UseMutationResult = props.mutation; const sessionQuery = useSession(); const loggedUser = sessionQuery.data?.session?.username; - + const isUserAdmin = sessionQuery.data?.session?.isUserAdmin; const owner = props.payload["--owner"].toLowerCase() const isOwner = (loggedUser?.toLowerCase() == owner) || (`scheduled_${loggedUser?.toLowerCase()}@teuthology` == owner) @@ -49,16 +50,21 @@ export default function KillButton(props: KillButtonProps) { return (
+ + + + Date: Tue, 11 Jun 2024 20:07:24 +0530 Subject: [PATCH 09/15] KillButtonDialog: use CodeBlock to display logs Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index d9d330b..c49b6f9 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -10,6 +10,7 @@ import Paper from "@mui/material/Paper"; import Typography from "@mui/material/Typography"; import Tooltip from '@mui/material/Tooltip'; +import CodeBlock from "../CodeBlock"; import { KillRunPayload } from "../../lib/teuthologyAPI.d"; import { useSession } from "../../lib/teuthologyAPI"; import Alert from "../Alert"; @@ -81,18 +82,16 @@ export default function KillButton(props: KillButtonProps) { function KillButtonDialog({mutation, open, handleClose, payload}: KillButtonDialogProps) { return (
- + KILL CONFIRMATION - + { (mutation.isSuccess && mutation.data ) ?
Successful! - - {mutation.data?.data?.logs} - +
: (mutation.isLoading) ? ( @@ -109,9 +108,7 @@ function KillButtonDialog({mutation, open, handleClose, payload}: KillButtonDial Failed! - - {mutation.error?.response?.data?.detail} - +
) : From 0e712f08d9f273632fadee3de1e6c1055dbdc161 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Mon, 8 Jul 2024 14:10:27 +0530 Subject: [PATCH 10/15] add "--preserve-queue" in kill run request payload Signed-off-by: Vallari Agrawal --- src/lib/teuthologyAPI.d.ts | 1 + src/pages/Run/index.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/src/lib/teuthologyAPI.d.ts b/src/lib/teuthologyAPI.d.ts index a7f0149..5843b7e 100644 --- a/src/lib/teuthologyAPI.d.ts +++ b/src/lib/teuthologyAPI.d.ts @@ -11,4 +11,5 @@ export type KillRunPayload = { "--run": string, "--owner": string, "--machine-type": string, + "--preserve-queue": boolean, } diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index 1cd906b..281c3a3 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -61,6 +61,7 @@ export default function Run() { "--run": data?.name || "", "--owner": run_owner, "--machine-type": data?.machine_type || "", + "--preserve-queue": true, } return ( From ebaaebe25061f497f148083c9efc62b06af69bdf Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Tue, 10 Sep 2024 23:17:46 +0530 Subject: [PATCH 11/15] src/lib/teuthologyAPI.ts: add trailing slash to run-kill req Request get redirected to /kill/?logs=true if trailing slash is missing. Signed-off-by: Vallari Agrawal --- src/lib/teuthologyAPI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/teuthologyAPI.ts b/src/lib/teuthologyAPI.ts index 4ae0abd..edde052 100644 --- a/src/lib/teuthologyAPI.ts +++ b/src/lib/teuthologyAPI.ts @@ -58,7 +58,7 @@ function useUserData(): Map { } function useRunKill(): UseMutationResult { - const url = getURL("/kill?logs=true"); + const url = getURL("/kill/?logs=true"); const mutation: UseMutationResult = useMutation({ mutationKey: ['run-kill', { url }], mutationFn: (payload) => ( From 54763f12e77c600acd2304ec29f5b6bbc6bb6078 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Fri, 13 Sep 2024 19:06:49 +0530 Subject: [PATCH 12/15] KillButton: Improve tooltip message Add getHelperMessage() to display better tooltip message on kill button. The message should help the user understand why the button is disabled and know if they are admin user. Signed-off-by: Vallari Agrawal --- src/components/KillButton/index.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/components/KillButton/index.tsx b/src/components/KillButton/index.tsx index c49b6f9..d3f8343 100644 --- a/src/components/KillButton/index.tsx +++ b/src/components/KillButton/index.tsx @@ -37,6 +37,17 @@ export default function KillButton(props: KillButtonProps) { const isUserAdmin = sessionQuery.data?.session?.isUserAdmin; const owner = props.payload["--owner"].toLowerCase() const isOwner = (loggedUser?.toLowerCase() == owner) || (`scheduled_${loggedUser?.toLowerCase()}@teuthology` == owner) + const isButtonDisabled = ((props.disabled) || (!isOwner && !isUserAdmin)) + + const getHelperMessage = () => { + if (isButtonDisabled) { + if (!isOwner && !isUserAdmin) return "You don't have admin privileges to kill runs owned by another user. "; + return "All jobs in the run have already finished"; + } else { + if (!isOwner && isUserAdmin) return "Use admin privileges to kill another user's run."; + return "Terminate all jobs in this run"; + } + } const toggleDialog = () => { setOpen(!open); @@ -51,18 +62,17 @@ export default function KillButton(props: KillButtonProps) { return (
- + From 5c733ec19da6a8961fd4e6dab0850f2409bdb428 Mon Sep 17 00:00:00 2001 From: Vallari Agrawal Date: Sat, 14 Sep 2024 12:33:41 +0530 Subject: [PATCH 13/15] Fix login component to show user image Signed-off-by: Vallari Agrawal --- src/components/Login/index.jsx | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) 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
:
- { (mutation.isError) ? : null } - { (mutation.isSuccess) ? : null } + { (killMutation.isError) ? : null } + { (killMutation.isSuccess) ? : null }
); }; diff --git a/src/pages/Run/index.tsx b/src/pages/Run/index.tsx index 281c3a3..4827669 100644 --- a/src/pages/Run/index.tsx +++ b/src/pages/Run/index.tsx @@ -9,11 +9,9 @@ import { Helmet } from "react-helmet"; import type { Run as Run_, RunParams } from "../../lib/paddles.d"; import { useRun } from "../../lib/paddles"; -import { useRunKill } from "../../lib/teuthologyAPI"; import JobList from "../../components/JobList"; import Link from "../../components/Link"; import KillButton from "../../components/KillButton"; -import { KillRunPayload } from '../../lib/teuthologyAPI.d'; const PREFIX = "index"; @@ -46,7 +44,6 @@ export default function Run() { pageSize: NumberParam, }); const { name } = useParams(); - const killMutation = useRunKill(); const query = useRun(name === undefined ? "" : name); if (query === null) return 404; if (query.isError) return null; @@ -56,13 +53,6 @@ export default function Run() { const date = query.data?.scheduled ? format(new Date(query.data.scheduled), "yyyy-MM-dd") : null; - const run_owner = data?.jobs[0].owner || ""; - const killPayload: KillRunPayload = { - "--run": data?.name || "", - "--owner": run_owner, - "--machine-type": data?.machine_type || "", - "--preserve-queue": true, - } return ( @@ -83,11 +73,7 @@ export default function Run() { date
- + );