From da1640eec9320b0a8289a5c093c109271c0a7627 Mon Sep 17 00:00:00 2001
From: Christina Jenks <christina.jenks@ess.eu>
Date: Wed, 20 Sep 2023 12:18:09 +0000
Subject: [PATCH] CE-2068: replace useOperationsSearch & useOngoingCommand with
 common api

---
 src/api/SwaggerApi.js                         | 43 -------------
 src/components/IOC/IOCManage/IOCManage.js     |  2 +-
 .../common/User/UserOperationList.js          | 25 +++++---
 src/mocks/mockAPI.js                          | 18 +++++-
 .../views/IOC/IocDetailsView.stories.js       | 12 +++-
 src/stories/views/Job/JobListView.stories.js  | 15 +++++
 src/views/IOC/IOCDetailsView.js               | 63 ++++++++++++++-----
 src/views/jobs/JobListView.js                 | 25 +++++---
 8 files changed, 125 insertions(+), 78 deletions(-)
 create mode 100644 src/stories/views/Job/JobListView.stories.js

diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js
index 7ab60b68..59444ee7 100644
--- a/src/api/SwaggerApi.js
+++ b/src/api/SwaggerApi.js
@@ -229,49 +229,6 @@ export function unpackOngoingOperations(input) {
   return output.totalCount > 0 ? output.operationsList[0] : null;
 }
 
-export function useOngoingCommand(iocId) {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(
-    api.apis.Deployments.listOperations,
-    unpackOngoingOperations
-  );
-  const boundMethod = useCallback(
-    method.bind(null, { ioc_id: iocId, type: "COMMAND", status: "ONGOING" }),
-    [iocId]
-  );
-  return useAsync({
-    fcn: boundMethod,
-    call: false,
-    init: emptyOperationsListResponse
-  });
-}
-
-const emptyOperationsListResponse = {
-  totalCount: 0,
-  pageNumber: 0,
-  limit: 0,
-  operationsList: []
-};
-
-export function unpackOperationsList(input) {
-  const { operations: operationsList, ...rest } = input;
-  const output = { ...rest, operationsList };
-  return output;
-}
-
-export function useOperationsSearch() {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(
-    (params) => api.apis.Deployments.listOperations(params),
-    unpackOperationsList
-  );
-  return useAsync({
-    fcn: method,
-    call: false,
-    init: emptyOperationsListResponse
-  });
-}
-
 export function unpackOperation(operation) {
   const d = { ...operation };
   return d;
diff --git a/src/components/IOC/IOCManage/IOCManage.js b/src/components/IOC/IOCManage/IOCManage.js
index 9378005e..e1378e4d 100644
--- a/src/components/IOC/IOCManage/IOCManage.js
+++ b/src/components/IOC/IOCManage/IOCManage.js
@@ -215,7 +215,7 @@ export function IOCManage({
             }
           >
             <JobTable
-              jobs={operations.operationsList}
+              jobs={operations}
               pagination={pagination}
               onPage={onPage}
               loading={operationsLoading}
diff --git a/src/components/common/User/UserOperationList.js b/src/components/common/User/UserOperationList.js
index c90c1957..75372ca2 100644
--- a/src/components/common/User/UserOperationList.js
+++ b/src/components/common/User/UserOperationList.js
@@ -1,13 +1,24 @@
-import React from "react";
+import React, { useContext } from "react";
 import { Card, CardHeader } from "@mui/material";
 import { initRequestParams } from "../Helper";
 import { useEffect } from "react";
-import { useOperationsSearch } from "../../../api/SwaggerApi";
 import { usePagination } from "../../../hooks/pagination";
 import { JobTable } from "../../Job";
+import { apiContext } from "../../../api/DeployApi";
+import { useAPIMethod } from "@ess-ics/ce-ui-common";
 
 export function UserOperationList({ userName }) {
-  const [operations, getOperations, , loading] = useOperationsSearch();
+  const client = useContext(apiContext);
+
+  const {
+    value: operations,
+    wrapper: getOperations,
+    loading,
+    dataReady
+  } = useAPIMethod({
+    fcn: client.apis.Deployments.listOperations,
+    call: false
+  });
 
   const rowsPerPage = [20, 50];
   const { pagination, setPagination } = usePagination({
@@ -18,8 +29,8 @@ export function UserOperationList({ userName }) {
 
   // update pagination whenever search result total pages change
   useEffect(() => {
-    setPagination({ totalCount: operations.totalCount ?? 0 });
-  }, [setPagination, operations.totalCount]);
+    setPagination({ totalCount: operations?.totalCount ?? 0 });
+  }, [setPagination, operations?.totalCount]);
 
   useEffect(() => {
     let requestParams = initRequestParams(pagination);
@@ -44,8 +55,8 @@ export function UserOperationList({ userName }) {
         }}
       />
       <JobTable
-        jobs={operations.operationsList}
-        loading={loading}
+        jobs={operations?.operations}
+        loading={loading || !dataReady}
         pagination={pagination}
         onPage={onPage}
         rowType="userPageJobLog"
diff --git a/src/mocks/mockAPI.js b/src/mocks/mockAPI.js
index 7fa3a2cd..010a2cc1 100644
--- a/src/mocks/mockAPI.js
+++ b/src/mocks/mockAPI.js
@@ -156,6 +156,15 @@ function listOperations(req) {
   return { body };
 }
 
+function fetchOperation(req) {
+  const params = getParameters(req, "/deployments/operations/:id");
+  const data = require("./fixtures/OperationList.json");
+
+  const body = data.operations.find((x) => x?.id === Number(params?.id));
+  const status = body ? 200 : 404;
+  return { body, status };
+}
+
 function getCommandList(req) {
   const body = require("./fixtures/PagedCommandResponse.json");
   return { body };
@@ -262,7 +271,8 @@ const mockAPI = {
     getDeploymentJob,
     getDeploymentJobLog,
     getCommandList,
-    listOperations
+    listOperations,
+    fetchOperation
   },
   hosts: {
     getCSEntryHostWithStatus
@@ -350,6 +360,12 @@ export const apiHandlers = [
     qRegExp(".*/deployments/[0-9]+"),
     mockAPI.deployments.getDeployment
   ),
+  makeHandler(
+    "GET",
+    qRegExp(".*/deployments/operations/[0-9]+"),
+    mockAPI.deployments.fetchOperation,
+    auth
+  ),
   makeHandler(
     "GET",
     qRegExp(".*/deployments/operations/job/[0-9]+"),
diff --git a/src/stories/views/IOC/IocDetailsView.stories.js b/src/stories/views/IOC/IocDetailsView.stories.js
index ea0221de..1b0a9315 100644
--- a/src/stories/views/IOC/IocDetailsView.stories.js
+++ b/src/stories/views/IOC/IocDetailsView.stories.js
@@ -6,10 +6,18 @@ export default {
   title: "Views/IOC/IOCDetailsView"
 };
 
-const Template = () => (
+const Template = (args) => (
   <AppHarness>
-    <IOCDetailsContainer id={346} />
+    <IOCDetailsContainer
+      id={346}
+      {...args}
+    />
   </AppHarness>
 );
 
 export const Default = () => <Template />;
+
+export const Deployable = (args) => <Template {...args} />;
+Deployable.args = {
+  id: 2
+};
diff --git a/src/stories/views/Job/JobListView.stories.js b/src/stories/views/Job/JobListView.stories.js
new file mode 100644
index 00000000..eb4d7960
--- /dev/null
+++ b/src/stories/views/Job/JobListView.stories.js
@@ -0,0 +1,15 @@
+import React from "react";
+import { AppHarness } from "../../../mocks/AppHarness";
+import { JobListView } from "../../../views/jobs/JobListView";
+
+export default {
+  title: "Views/Job/JobListView"
+};
+
+const Template = () => (
+  <AppHarness>
+    <JobListView />
+  </AppHarness>
+);
+
+export const Default = () => <Template />;
diff --git a/src/views/IOC/IOCDetailsView.js b/src/views/IOC/IOCDetailsView.js
index 7cbc136f..f6bc0574 100644
--- a/src/views/IOC/IOCDetailsView.js
+++ b/src/views/IOC/IOCDetailsView.js
@@ -7,7 +7,6 @@ import React, {
   useMemo,
   useState
 } from "react";
-import { useOngoingCommand, useOperationsSearch } from "../../api/SwaggerApi";
 import { IOCLiveStatus } from "../../components/IOC/IOCLiveStatus";
 import { IOCManage } from "../../components/IOC/IOCManage";
 import { useNavigate } from "react-router-dom";
@@ -17,7 +16,7 @@ import {
   applicationTitle,
   initRequestParams
 } from "../../components/common/Helper";
-import { GlobalAppBarContext } from "@ess-ics/ce-ui-common";
+import { GlobalAppBarContext, useAPIMethod } from "@ess-ics/ce-ui-common";
 import { useSafePolling } from "../../hooks/Polling";
 import useUrlState from "@ahooksjs/use-url-state";
 import {
@@ -25,6 +24,7 @@ import {
   deserialize
 } from "../../components/common/URLState/URLState";
 import { usePagination } from "../../hooks/pagination";
+import { apiContext } from "../../api/DeployApi";
 
 const IOC_POLL_INTERVAL = 10000;
 export function IOCDetailsView({ ioc, getIOC, loading }) {
@@ -39,14 +39,37 @@ export function IOCDetailsView({ ioc, getIOC, loading }) {
 
   const [buttonDisabled, setButtonDisabled] = useState(false);
   const navigate = useNavigate();
-  const [operations, getOperations /* reset*/, , operationsLoading] =
-    useOperationsSearch();
-  const [
-    ongoingCommand,
-    getOngoingCommand,
-    ,
-    /* reset*/ ongoingCommandLoading
-  ] = useOngoingCommand(ioc.id);
+
+  const client = useContext(apiContext);
+  const {
+    value: operations,
+    wrapper: getOperations,
+    loading: operationsLoading,
+    dataReady: operationsDataReady
+  } = useAPIMethod({
+    fcn: client.apis.Deployments.listOperations,
+    call: false
+  });
+
+  const ongoingCommandParams = useMemo(
+    () => ({
+      ioc_id: ioc.id,
+      type: "COMMAND",
+      status: "ONGOING"
+    }),
+    [ioc]
+  );
+
+  const {
+    value: ongoingCommand,
+    wrapper: getOngoingCommand,
+    loading: ongoingCommandLoading,
+    dataReady: ongoingCommandDataReady
+  } = useAPIMethod({
+    fcn: client.apis.Deployments.listOperations,
+    params: ongoingCommandParams,
+    call: false
+  });
 
   const jobUrlPagination = useMemo(() => {
     return {
@@ -76,8 +99,8 @@ export function IOCDetailsView({ ioc, getIOC, loading }) {
 
   // update pagination whenever search result total pages change
   useEffect(() => {
-    setJobPagination({ totalCount: operations.totalCount ?? 0 });
-  }, [setJobPagination, operations.totalCount]);
+    setJobPagination({ totalCount: operations?.totalCount ?? 0 });
+  }, [setJobPagination, operations?.totalCount]);
 
   // whenever url state changes, update pagination
   useEffect(() => {
@@ -96,7 +119,11 @@ export function IOCDetailsView({ ioc, getIOC, loading }) {
   };
 
   useSafePolling(getIOC, loading, IOC_POLL_INTERVAL);
-  useSafePolling(getOngoingCommand, ongoingCommandLoading, IOC_POLL_INTERVAL);
+  useSafePolling(
+    getOngoingCommand,
+    ongoingCommandLoading || !ongoingCommandDataReady,
+    IOC_POLL_INTERVAL
+  );
 
   useEffect(() => {
     setButtonDisabled(Boolean(ioc?.operationInProgress));
@@ -234,9 +261,13 @@ export function IOCDetailsView({ ioc, getIOC, loading }) {
               ioc={ioc}
               getIOC={getIOC}
               buttonDisabled={buttonDisabled}
-              currentCommand={ongoingCommand}
-              operations={operations}
-              operationsLoading={operationsLoading}
+              currentCommand={
+                ongoingCommand?.operations?.length > 0
+                  ? ongoingCommand.operations[0]
+                  : null
+              }
+              operations={operations?.operations}
+              operationsLoading={operationsLoading || !operationsDataReady}
               getOperations={getOperations}
               setButtonDisabled={setButtonDisabledAndUpdate}
               pagination={jobPagination}
diff --git a/src/views/jobs/JobListView.js b/src/views/jobs/JobListView.js
index 5fa2a77d..6a43a22e 100644
--- a/src/views/jobs/JobListView.js
+++ b/src/views/jobs/JobListView.js
@@ -10,8 +10,7 @@ import {
 } from "@mui/material";
 import Tabs from "@mui/material/Tabs";
 import Tab from "@mui/material/Tab";
-import { useOperationsSearch } from "../../api/SwaggerApi";
-import { userContext, RootPaper } from "@ess-ics/ce-ui-common";
+import { userContext, RootPaper, useAPIMethod } from "@ess-ics/ce-ui-common";
 import { initRequestParams } from "../../components/common/Helper";
 import { useEffect } from "react";
 import { SearchBar } from "../../components/common/SearchBar/SearchBar";
@@ -23,10 +22,20 @@ import {
 } from "../../components/common/URLState/URLState";
 import { usePagination } from "../../hooks/pagination";
 import { JobTable } from "../../components/Job";
+import { apiContext } from "../../api/DeployApi";
 
 export function JobListView() {
-  const [operations, getOperations /* reset*/, , loading] =
-    useOperationsSearch();
+  const client = useContext(apiContext);
+
+  const {
+    value: operations,
+    wrapper: getOperations,
+    loading,
+    dataReady
+  } = useAPIMethod({
+    fcn: client.apis.Deployments.listOperations,
+    call: false
+  });
 
   const [urlState, setUrlState] = useUrlState(
     {
@@ -99,8 +108,8 @@ export function JobListView() {
 
   // update pagination whenever search result total pages change
   useEffect(() => {
-    setPagination({ totalCount: operations.totalCount ?? 0 });
-  }, [setPagination, operations.totalCount]);
+    setPagination({ totalCount: operations?.totalCount ?? 0 });
+  }, [setPagination, operations?.totalCount]);
 
   // whenever url state changes, update pagination
   useEffect(() => {
@@ -163,10 +172,10 @@ export function JobListView() {
       placeholder="Search in IOC name or user"
     >
       <JobTable
-        jobs={operations.operationsList}
+        jobs={operations?.operations}
         pagination={pagination}
         onPage={onPage}
-        loading={loading}
+        loading={loading || !dataReady}
       />
     </SearchBar>
   );
-- 
GitLab