([]);
- const columns = isMobile ? mobileHeadCells : headCells;
+ const { configuration } = useOIDCContext();
+ const { accessToken } = useOidcAccessToken(configuration?.scope);
+ const [backdropOpen, setBackdropOpen] = React.useState(false);
+ const [snackbarInfo, setSnackbarInfo] = React.useState({
+ open: false,
+ message: "",
+ severity: "success",
+ });
- if (isLoading) return Loading...
;
+ /**
+ * Fetches the jobs from the /api/jobs/search endpoint
+ */
+ const urlGetJobs = `/api/jobs/search?page=0&per_page=100`;
+ const { data, error } = useSWR([urlGetJobs, accessToken, "POST"], fetcher);
+
+ if (!data && !error) return Loading...
;
if (error) return An error occurred while fetching jobs
;
- if (!rows || rows.length === 0) return No job submitted.
;
+ if (!data || data.length === 0) return No job submitted.
;
+
+ const columns = isMobile ? mobileHeadCells : headCells;
+ const clearSelected = () => setSelected([]);
+
+ /**
+ * Handle the deletion of the selected jobs
+ */
+ const handleDelete = async (selectedIds: readonly number[]) => {
+ const queryString = selectedIds.map((id) => `job_ids=${id}`).join("&");
+ const deleteUrl = `/api/jobs/?${queryString}`;
+ const requestOptions = {
+ method: "DELETE",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${accessToken}`, // Use the access token for authorization
+ },
+ };
+
+ setBackdropOpen(true);
+ try {
+ const response = await fetch(deleteUrl, requestOptions);
+ if (!response.ok)
+ throw new Error("An error occurred while deleting jobs.");
+ const data = await response.json();
+ setBackdropOpen(false);
+ mutate([urlGetJobs, accessToken, "POST"]);
+ clearSelected();
+ setSnackbarInfo({
+ open: true,
+ message: "Deleted successfully",
+ severity: "success",
+ });
+ } catch (error: any) {
+ setSnackbarInfo({
+ open: true,
+ message: "Delete failed: " + error.message,
+ severity: "error",
+ });
+ } finally {
+ setBackdropOpen(false);
+ }
+ };
+
+ /**
+ * Handle the killing of the selected jobs
+ */
+ const handleKill = async (selectedIds: readonly number[]) => {
+ const queryString = selectedIds.map((id) => `job_ids=${id}`).join("&");
+ const killUrl = `/api/jobs/kill?${queryString}`;
+ const requestOptions = {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${accessToken}`, // Use the access token for authorization
+ },
+ };
+
+ setBackdropOpen(true);
+ try {
+ const response = await fetch(killUrl, requestOptions);
+ if (!response.ok)
+ throw new Error("An error occurred while deleting jobs.");
+ const data = await response.json();
+ setBackdropOpen(false);
+ mutate([urlGetJobs, accessToken, "POST"]);
+ clearSelected();
+ setSnackbarInfo({
+ open: true,
+ message: "Killed successfully",
+ severity: "success",
+ });
+ } catch (error: any) {
+ setSnackbarInfo({
+ open: true,
+ message: "Kill failed: " + error.message,
+ severity: "error",
+ });
+ } finally {
+ setBackdropOpen(false);
+ }
+ };
+
+ /**
+ * Handle the rescheduling of the selected jobs
+ */
+ const handleReschedule = async (selectedIds: readonly number[]) => {
+ const queryString = selectedIds.map((id) => `job_ids=${id}`).join("&");
+ const rescheduleUrl = `/api/jobs/reschedule?${queryString}`;
+ const requestOptions = {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ Authorization: `Bearer ${accessToken}`, // Use the access token for authorization
+ },
+ };
+
+ setBackdropOpen(true);
+ try {
+ const response = await fetch(rescheduleUrl, requestOptions);
+ if (!response.ok)
+ throw new Error("An error occurred while deleting jobs.");
+ const data = await response.json();
+ setBackdropOpen(false);
+ mutate([urlGetJobs, accessToken, "POST"]);
+ clearSelected();
+ setSnackbarInfo({
+ open: true,
+ message: "Rescheduled successfully",
+ severity: "success",
+ });
+ } catch (error: any) {
+ setSnackbarInfo({
+ open: true,
+ message: "Reschedule failed: " + error.message,
+ severity: "error",
+ });
+ } finally {
+ setBackdropOpen(false);
+ }
+ };
+
+ /**
+ * The toolbar components for the data grid
+ */
+ const toolbarComponents = (
+ <>
+
+ handleReschedule(selected)}>
+
+
+
+
+ handleKill(selected)}>
+
+
+
+
+ handleDelete(selected)}>
+
+
+
+ >
+ );
return (
-
+ <>
+
+ setSnackbarInfo((old) => ({ ...old, open: false }))}
+ >
+ setSnackbarInfo((old) => ({ ...old, open: false }))}
+ severity={snackbarInfo.severity as AlertColor}
+ sx={{ width: "100%" }}
+ >
+ {snackbarInfo.message}
+
+
+ theme.zIndex.drawer + 1 }}
+ open={backdropOpen}
+ >
+
+
+ >
);
}
diff --git a/src/hooks/jobs.tsx b/src/hooks/jobs.tsx
deleted file mode 100644
index 872991b4..00000000
--- a/src/hooks/jobs.tsx
+++ /dev/null
@@ -1,23 +0,0 @@
-import { useOidcAccessToken } from "@axa-fr/react-oidc";
-import useSWR from "swr";
-import { useDiracxUrl, fetcher } from "./utils";
-import { useOIDCContext } from "./oidcConfiguration";
-
-/**
- * Fetches the jobs from the /api/jobs/search endpoint
- * @returns the jobs
- */
-export function useJobs() {
- const { configuration } = useOIDCContext();
- const diracxUrl = useDiracxUrl();
- const { accessToken } = useOidcAccessToken(configuration?.scope);
-
- const url = `${diracxUrl}/api/jobs/search?page=0&per_page=100`;
- const { data, error } = useSWR([url, accessToken, "POST"], fetcher);
-
- return {
- data,
- error,
- isLoading: !data && !error,
- };
-}
diff --git a/test/unit-tests/JobDataTable.test.tsx b/test/unit-tests/JobDataTable.test.tsx
index 9ce3117e..7c0e7c47 100644
--- a/test/unit-tests/JobDataTable.test.tsx
+++ b/test/unit-tests/JobDataTable.test.tsx
@@ -1,21 +1,27 @@
import React from "react";
import { render } from "@testing-library/react";
import { JobDataTable } from "@/components/ui/JobDataTable";
-import { useJobs } from "@/hooks/jobs";
+import useSWR from "swr";
+import { useOidcAccessToken } from "@axa-fr/react-oidc";
-// Mocking the useJobs hook
-jest.mock("../../src/hooks/jobs");
+// Mock the module
+jest.mock("@axa-fr/react-oidc", () => ({
+ useOidcAccessToken: jest.fn(),
+}));
+
+jest.mock("swr", () => jest.fn());
describe("", () => {
it("displays loading state", () => {
- (useJobs as jest.Mock).mockReturnValue({ isLoading: true });
+ (useSWR as jest.Mock).mockReturnValue({ data: null, error: null });
+ (useOidcAccessToken as jest.Mock).mockReturnValue("1234");
const { getByText } = render();
expect(getByText("Loading...")).toBeInTheDocument();
});
it("displays error state", () => {
- (useJobs as jest.Mock).mockReturnValue({ error: true });
+ (useSWR as jest.Mock).mockReturnValue({ error: true });
const { getByText } = render();
expect(
@@ -24,7 +30,7 @@ describe("", () => {
});
it("displays no jobs data state", () => {
- (useJobs as jest.Mock).mockReturnValue({ data: [] });
+ (useSWR as jest.Mock).mockReturnValue({ data: [] });
const { getByText } = render();
expect(getByText("No job submitted.")).toBeInTheDocument();
@@ -40,7 +46,7 @@ describe("", () => {
SubmissionTime: "2023-10-13",
},
];
- (useJobs as jest.Mock).mockReturnValue({ data: mockData });
+ (useSWR as jest.Mock).mockReturnValue({ data: mockData });
const { getByText } = render();
expect(getByText("TestJob1")).toBeInTheDocument();