Merge branch '21128-toolbar-context-menu'
[arvados-workbench2.git] / src / store / subprocess-panel / subprocess-panel-actions.ts
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import { Dispatch } from 'redux';
6 import { RootState } from 'store/store';
7 import { ServiceRepository } from 'services/services';
8 import { bindDataExplorerActions } from 'store/data-explorer/data-explorer-action';
9 import { FilterBuilder } from 'services/api/filter-builder';
10 import { ProgressBarData } from 'components/subprocess-progress-bar/subprocess-progress-bar';
11 import { ProcessStatusFilter, buildProcessStatusFilters } from 'store/resource-type-filters/resource-type-filters';
12 export const SUBPROCESS_PANEL_ID = "subprocessPanel";
13 export const SUBPROCESS_ATTRIBUTES_DIALOG = 'subprocessAttributesDialog';
14 export const subprocessPanelActions = bindDataExplorerActions(SUBPROCESS_PANEL_ID);
15
16 export const loadSubprocessPanel = () =>
17     (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
18         dispatch(subprocessPanelActions.REQUEST_ITEMS());
19     };
20
21 /**
22  * Holds a ProgressBarData status type and process count result
23  */
24 type ProcessStatusBarCount = {
25     status: keyof ProgressBarData;
26     count: number;
27 };
28
29 /**
30  * Associates each of the limited progress bar segment types with an array of
31  * ProcessStatusFilterTypes to be combined when displayed
32  */
33 type ProcessStatusMap = Record<keyof ProgressBarData, ProcessStatusFilter[]>;
34
35 const statusMap: ProcessStatusMap = {
36         [ProcessStatusFilter.COMPLETED]: [ProcessStatusFilter.COMPLETED],
37         [ProcessStatusFilter.RUNNING]: [ProcessStatusFilter.RUNNING],
38         [ProcessStatusFilter.FAILED]: [ProcessStatusFilter.FAILED, ProcessStatusFilter.CANCELLED],
39         [ProcessStatusFilter.QUEUED]: [ProcessStatusFilter.QUEUED, ProcessStatusFilter.ONHOLD],
40 };
41
42 /**
43  * Utility type to hold a pair of associated progress bar status and process status
44  */
45 type ProgressBarStatusPair = {
46     barStatus: keyof ProcessStatusMap;
47     processStatus: ProcessStatusFilter;
48 };
49
50 export const fetchSubprocessProgress = (requestingContainerUuid: string) =>
51     async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<ProgressBarData | undefined> => {
52
53         const requestContainerStatusCount = async (fb: FilterBuilder) => {
54             return await services.containerRequestService.list({
55                 limit: 0,
56                 offset: 0,
57                 filters: fb.getFilters(),
58             });
59         }
60
61         if (requestingContainerUuid) {
62             try {
63                 const baseFilter = new FilterBuilder().addEqual('requesting_container_uuid', requestingContainerUuid).getFilters();
64
65                 // Create return object
66                 let result: ProgressBarData = {
67                     [ProcessStatusFilter.COMPLETED]: 0,
68                     [ProcessStatusFilter.RUNNING]: 0,
69                     [ProcessStatusFilter.FAILED]: 0,
70                     [ProcessStatusFilter.QUEUED]: 0,
71                 }
72
73                 // Create array of promises that returns the status associated with the item count
74                 // Helps to make the requests simultaneously while preserving the association with the status key as a typed key
75                 const promises = (Object.keys(statusMap) as Array<keyof ProcessStatusMap>)
76                     // Split statusMap into pairs of progress bar status and process status
77                     .reduce((acc, curr) => [...acc, ...statusMap[curr].map(processStatus => ({barStatus: curr, processStatus}))], [] as ProgressBarStatusPair[])
78                     .map(async (statusPair: ProgressBarStatusPair): Promise<ProcessStatusBarCount> => {
79                         // For each status pair, request count and return bar status and count
80                         const { barStatus, processStatus } = statusPair;
81                         const filter = buildProcessStatusFilters(new FilterBuilder(baseFilter), processStatus);
82                         const count = (await requestContainerStatusCount(filter)).itemsAvailable;
83                         return {status: barStatus, count};
84                     });
85
86                 // Simultaneously requests each status count and apply them to the return object
87                 (await Promise.all(promises)).forEach((singleResult) => {
88                     result[singleResult.status] += singleResult.count;
89                 });
90                 return result;
91             } catch (e) {
92                 return undefined;
93             }
94         } else {
95             return undefined;
96         }
97     };