1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
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, joinFilters } from 'services/api/filter-builder';
10 import { ProgressBarStatus, ProgressBarCounts } from 'components/subprocess-progress-bar/subprocess-progress-bar';
11 import { ProcessStatusFilter, buildProcessStatusFilters } from 'store/resource-type-filters/resource-type-filters';
12 import { Process, isProcessRunning } from 'store/processes/process';
13 import { ProjectResource } from 'models/project';
15 export const SUBPROCESS_PANEL_ID = "subprocessPanel";
16 export const SUBPROCESS_ATTRIBUTES_DIALOG = 'subprocessAttributesDialog';
17 export const subprocessPanelActions = bindDataExplorerActions(SUBPROCESS_PANEL_ID);
19 export const loadSubprocessPanel = () =>
20 (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository) => {
21 dispatch(subprocessPanelActions.REQUEST_ITEMS());
25 * Holds a ProgressBarData status type and process count result
27 type ProcessStatusCount = {
28 status: keyof ProgressBarCounts;
33 * Associates each of the limited progress bar segment types with an array of
34 * ProcessStatusFilterTypes to be combined when displayed
36 type ProcessStatusMap = Record<keyof ProgressBarCounts, ProcessStatusFilter[]>;
38 const statusMap: ProcessStatusMap = {
39 [ProcessStatusFilter.COMPLETED]: [ProcessStatusFilter.COMPLETED],
40 [ProcessStatusFilter.RUNNING]: [ProcessStatusFilter.RUNNING],
41 [ProcessStatusFilter.FAILED]: [ProcessStatusFilter.FAILED, ProcessStatusFilter.CANCELLED],
42 [ProcessStatusFilter.QUEUED]: [ProcessStatusFilter.QUEUED, ProcessStatusFilter.ONHOLD],
46 * Utility type to hold a pair of associated progress bar status and process status
48 type ProgressBarStatusPair = {
49 barStatus: keyof ProcessStatusMap;
50 processStatus: ProcessStatusFilter;
53 const isProcess = (resource: Process | ProjectResource | undefined): resource is Process => {
54 return !!resource && 'containerRequest' in resource;
57 export const fetchProcessProgressBarStatus = (parentResource: Process | ProjectResource, typeFilter?: string) =>
58 async (dispatch: Dispatch, getState: () => RootState, services: ServiceRepository): Promise<ProgressBarStatus | undefined> => {
59 const requestContainerStatusCount = async (fb: FilterBuilder) => {
60 return await services.containerRequestService.list({
63 filters: fb.getFilters(),
68 if (isProcess(parentResource)) {
69 baseFilter = new FilterBuilder().addEqual('requesting_container_uuid', parentResource.containerRequest.containerUuid).getFilters();
71 baseFilter = new FilterBuilder().addEqual('owner_uuid', parentResource.uuid).getFilters();
75 baseFilter = joinFilters(baseFilter, typeFilter);
80 // Create return object
81 let result: ProgressBarCounts = {
82 [ProcessStatusFilter.COMPLETED]: 0,
83 [ProcessStatusFilter.RUNNING]: 0,
84 [ProcessStatusFilter.FAILED]: 0,
85 [ProcessStatusFilter.QUEUED]: 0,
88 // Create array of promises that returns the status associated with the item count
89 // Helps to make the requests simultaneously while preserving the association with the status key as a typed key
90 const promises = (Object.keys(statusMap) as Array<keyof ProcessStatusMap>)
91 // Split statusMap into pairs of progress bar status and process status
92 .reduce((acc, curr) => [...acc, ...statusMap[curr].map(processStatus => ({barStatus: curr, processStatus}))], [] as ProgressBarStatusPair[])
93 .map(async (statusPair: ProgressBarStatusPair): Promise<ProcessStatusCount> => {
94 // For each status pair, request count and return bar status and count
95 const { barStatus, processStatus } = statusPair;
96 const filter = buildProcessStatusFilters(new FilterBuilder(baseFilter), processStatus);
97 const count = (await requestContainerStatusCount(filter)).itemsAvailable;
98 return {status: barStatus, count};
101 // Simultaneously requests each status count and apply them to the return object
102 (await Promise.all(promises)).forEach((singleResult) => {
103 result[singleResult.status] += singleResult.count;
106 let isRunning = result[ProcessStatusFilter.RUNNING] + result[ProcessStatusFilter.QUEUED] > 0;
108 if (isProcess(parentResource)) {
109 isRunning = isProcessRunning(parentResource);
112 return {counts: result, isRunning};