20609: Change subprocess progress bar to combine relevant process statuses
authorStephen Smith <stephen@curii.com>
Tue, 14 Nov 2023 14:07:08 +0000 (09:07 -0500)
committerStephen Smith <stephen@curii.com>
Tue, 14 Nov 2023 14:07:08 +0000 (09:07 -0500)
eg. Queued segment = Queued + OnHold, Failed segment = Failed + Cancelled

Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/components/subprocess-progress-bar/subprocess-progress-bar.test.tsx
src/store/subprocess-panel/subprocess-panel-actions.ts

index 8373717832e6d1f9e93c58e33e94620f894e8090..bd8603f9c2462b965504c3989c0ded5cdec87cf3 100644 (file)
@@ -73,8 +73,14 @@ describe("<SubprocessProgressBar />", () => {
         statusResponse = {
             [ProcessStatusFilter.COMPLETED]: 100,
             [ProcessStatusFilter.RUNNING]: 200,
-            [ProcessStatusFilter.FAILED]: 300,
-            [ProcessStatusFilter.QUEUED]: 400,
+
+            // Combined into failed segment
+            [ProcessStatusFilter.FAILED]: 200,
+            [ProcessStatusFilter.CANCELLED]: 100,
+
+            // Combined into queued segment
+            [ProcessStatusFilter.QUEUED]: 300,
+            [ProcessStatusFilter.ONHOLD]: 100,
         };
 
         services.containerRequestService.list = createMockListFunc(process.containerRequest.containerUuid);
@@ -88,12 +94,14 @@ describe("<SubprocessProgressBar />", () => {
         });
         await progressBar.update();
 
-        // expects 4 subprocess status list requests
+        // expects 6 subprocess status list requests
         const expectedFilters = [
             ProcessStatusFilter.COMPLETED,
             ProcessStatusFilter.RUNNING,
             ProcessStatusFilter.FAILED,
+            ProcessStatusFilter.CANCELLED,
             ProcessStatusFilter.QUEUED,
+            ProcessStatusFilter.ONHOLD,
         ].map((state) =>
             buildProcessStatusFilters(
                 new FilterBuilder().addEqual(
@@ -128,8 +136,12 @@ describe("<SubprocessProgressBar />", () => {
         statusResponse = {
             [ProcessStatusFilter.COMPLETED]: 50,
             [ProcessStatusFilter.RUNNING]: 55,
-            [ProcessStatusFilter.FAILED]: 60,
-            [ProcessStatusFilter.QUEUED]: 335,
+
+            [ProcessStatusFilter.FAILED]: 30,
+            [ProcessStatusFilter.CANCELLED]: 30,
+
+            [ProcessStatusFilter.QUEUED]: 235,
+            [ProcessStatusFilter.ONHOLD]: 100,
         };
 
         services.containerRequestService.list = createMockListFunc(process.containerRequest.containerUuid);
index 68ed453f1a587e5a0c75127fa2e69b18f08f3700..a67dd1f436441fa1cbf9d7ec4abc46c06910adc1 100644 (file)
@@ -18,11 +18,35 @@ export const loadSubprocessPanel = () =>
         dispatch(subprocessPanelActions.REQUEST_ITEMS());
     };
 
-type ProcessStatusCount = {
+/**
+ * Holds a ProgressBarData status type and process count result
+ */
+type ProcessStatusBarCount = {
     status: keyof ProgressBarData;
     count: number;
 };
 
+/**
+ * Associates each of the limited progress bar segment types with an array of
+ * ProcessStatusFilterTypes to be combined when displayed
+ */
+type ProcessStatusMap = Record<keyof ProgressBarData, ProcessStatusFilter[]>;
+
+const statusMap: ProcessStatusMap = {
+        [ProcessStatusFilter.COMPLETED]: [ProcessStatusFilter.COMPLETED],
+        [ProcessStatusFilter.RUNNING]: [ProcessStatusFilter.RUNNING],
+        [ProcessStatusFilter.FAILED]: [ProcessStatusFilter.FAILED, ProcessStatusFilter.CANCELLED],
+        [ProcessStatusFilter.QUEUED]: [ProcessStatusFilter.QUEUED, ProcessStatusFilter.ONHOLD],
+};
+
+/**
+ * Utility type to hold a pair of associated progress bar status and process status
+ */
+type ProgressBarStatusPair = {
+    barStatus: keyof ProcessStatusMap;
+    processStatus: ProcessStatusFilter;
+};
+
 export const fetchSubprocessProgress = (requestingContainerUuid: string) =>
     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<ProgressBarData | undefined> => {
 
@@ -48,15 +72,20 @@ export const fetchSubprocessProgress = (requestingContainerUuid: string) =>
 
                 // Create array of promises that returns the status associated with the item count
                 // Helps to make the requests simultaneously while preserving the association with the status key as a typed key
-                const promises = Object.keys(result).map(async (status: keyof ProgressBarData): Promise<ProcessStatusCount> => {
-                    const filter = buildProcessStatusFilters(new FilterBuilder(baseFilter), status);
-                    const count = (await requestContainerStatusCount(filter)).itemsAvailable;
-                    return {status, count};
-                });
+                const promises = (Object.keys(statusMap) as Array<keyof ProcessStatusMap>)
+                    // Split statusMap into pairs of progress bar status and process status
+                    .reduce((acc, curr) => [...acc, ...statusMap[curr].map(processStatus => ({barStatus: curr, processStatus}))], [] as ProgressBarStatusPair[])
+                    .map(async (statusPair: ProgressBarStatusPair): Promise<ProcessStatusBarCount> => {
+                        // For each status pair, request count and return bar status and count
+                        const { barStatus, processStatus } = statusPair;
+                        const filter = buildProcessStatusFilters(new FilterBuilder(baseFilter), processStatus);
+                        const count = (await requestContainerStatusCount(filter)).itemsAvailable;
+                        return {status: barStatus, count};
+                    });
 
                 // Simultaneously requests each status count and apply them to the return object
                 (await Promise.all(promises)).forEach((singleResult) => {
-                    result[singleResult.status] = singleResult.count;
+                    result[singleResult.status] += singleResult.count;
                 });
                 return result;
             } catch (e) {