21077: First pass
authorPeter Amstutz <peter.amstutz@curii.com>
Wed, 18 Oct 2023 21:40:46 +0000 (17:40 -0400)
committerPeter Amstutz <peter.amstutz@curii.com>
Wed, 18 Oct 2023 21:40:46 +0000 (17:40 -0400)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

src/index.tsx
src/store/all-processes-panel/all-processes-panel-middleware-service.ts
src/store/data-explorer/data-explorer-action.ts
src/store/data-explorer/data-explorer-middleware-service.ts
src/store/data-explorer/data-explorer-middleware.ts
src/store/processes/process.ts
src/store/project-panel/project-panel-middleware-service.ts
src/store/subprocess-panel/subprocess-panel-middleware-service.ts
src/websocket/websocket.ts

index d2af0952867dee9b45debda3b57d7971f1b7781d..646dfd4d620060256d169cf81c81a361fce93f16 100644 (file)
@@ -149,7 +149,7 @@ fetchConfig().then(({ config, apiHost }) => {
 
     const services = createServices(config, {
         progressFn: (id, working) => {
-            store.dispatch(progressIndicatorActions.TOGGLE_WORKING({ id, working }));
+            //store.dispatch(progressIndicatorActions.TOGGLE_WORKING({ id, working }));
         },
         errorFn: (id, error, showSnackBar: boolean) => {
             if (showSnackBar) {
index 227d2fa09c6e9617aeb15d34d1593703fbc71813..955d9689afc7f02eb471d0e965ad376cc9af16a4 100644 (file)
@@ -27,13 +27,13 @@ export class AllProcessesPanelMiddlewareService extends DataExplorerMiddlewareSe
         super(id);
     }
 
-    async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+    async requestItems(api: MiddlewareAPI<Dispatch, RootState>, criteriaChanged?: boolean, background?: boolean) {
         const dataExplorer = getDataExplorer(api.getState().dataExplorer, this.getId());
         if (!dataExplorer) {
             api.dispatch(allProcessesPanelDataExplorerIsNotSet());
         } else {
             try {
-                api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
+                if (!background) { api.dispatch(progressIndicatorActions.START_WORKING(this.getId())); }
                 const processItems = await this.services.containerRequestService.list(
                     {
                         ...getParams(dataExplorer),
@@ -41,7 +41,7 @@ export class AllProcessesPanelMiddlewareService extends DataExplorerMiddlewareSe
                         select: containerRequestFieldsNoMounts,
                     });
 
-                api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+                if (!background) { api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId())); }
                 api.dispatch(resourcesActions.SET_RESOURCES(processItems.items));
                 await api.dispatch<any>(loadMissingProcessesInformation(processItems.items));
                 api.dispatch(allProcessesPanelActions.SET_ITEMS({
@@ -51,7 +51,7 @@ export class AllProcessesPanelMiddlewareService extends DataExplorerMiddlewareSe
                     rowsPerPage: processItems.limit
                 }));
             } catch {
-                api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+                if (!background) { api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId())); }
                 api.dispatch(allProcessesPanelActions.SET_ITEMS({
                     items: [],
                     itemsAvailable: 0,
@@ -64,13 +64,13 @@ export class AllProcessesPanelMiddlewareService extends DataExplorerMiddlewareSe
     }
 }
 
-const getParams = ( dataExplorer: DataExplorer ) => ({
+const getParams = (dataExplorer: DataExplorer) => ({
     ...dataExplorerToListParams(dataExplorer),
     order: getOrder<ContainerRequestResource>(dataExplorer),
     filters: getFilters(dataExplorer)
 });
 
-const getFilters = ( dataExplorer: DataExplorer ) => {
+const getFilters = (dataExplorer: DataExplorer) => {
     const columns = dataExplorer.columns as DataColumns<string, ContainerRequestResource>;
     const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
     const activeStatusFilter = Object.keys(statusColumnFilters).find(
index f686c9393c2ce0933b5589ca86d9fdb3c62c8ce0..ea050e609f558a91decb73ac7badd65fe18f7d3f 100644 (file)
@@ -15,7 +15,7 @@ export enum DataTableRequestState {
 export const dataExplorerActions = unionize({
     CLEAR: ofType<{ id: string }>(),
     RESET_PAGINATION: ofType<{ id: string }>(),
-    REQUEST_ITEMS: ofType<{ id: string; criteriaChanged?: boolean }>(),
+    REQUEST_ITEMS: ofType<{ id: string; criteriaChanged?: boolean, background?: boolean }>(),
     REQUEST_STATE: ofType<{ id: string; criteriaChanged?: boolean }>(),
     SET_FETCH_MODE: ofType<{ id: string; fetchMode: DataTableFetchMode }>(),
     SET_COLUMNS: ofType<{ id: string; columns: DataColumns<any, any> }>(),
@@ -36,7 +36,7 @@ export type DataExplorerAction = UnionOf<typeof dataExplorerActions>;
 export const bindDataExplorerActions = (id: string) => ({
     CLEAR: () => dataExplorerActions.CLEAR({ id }),
     RESET_PAGINATION: () => dataExplorerActions.RESET_PAGINATION({ id }),
-    REQUEST_ITEMS: (criteriaChanged?: boolean) => dataExplorerActions.REQUEST_ITEMS({ id, criteriaChanged }),
+    REQUEST_ITEMS: (criteriaChanged?: boolean, background?: boolean) => dataExplorerActions.REQUEST_ITEMS({ id, criteriaChanged, background }),
     SET_FETCH_MODE: (payload: { fetchMode: DataTableFetchMode }) => dataExplorerActions.SET_FETCH_MODE({ ...payload, id }),
     SET_COLUMNS: (payload: { columns: DataColumns<any, any> }) => dataExplorerActions.SET_COLUMNS({ ...payload, id }),
     SET_FILTERS: (payload: { columnName: string; filters: DataTableFilters }) => dataExplorerActions.SET_FILTERS({ ...payload, id }),
index 01964fa48a9f260442205ab14e33a9f5dc9b09f2..e424b5e8165b76dc3851f5b4f8e22ce2ee7d35e7 100644 (file)
@@ -33,7 +33,8 @@ export abstract class DataExplorerMiddlewareService {
 
     abstract requestItems(
         api: MiddlewareAPI<Dispatch, RootState>,
-        criteriaChanged?: boolean
+        criteriaChanged?: boolean,
+        background?: boolean
     ): Promise<void>;
 }
 
index f83b064641ee82f6d7922ba801f4c85fff5b29e4..3404b375a86b3e6a48c779a441a3c89043443754 100644 (file)
@@ -16,98 +16,98 @@ import { DataExplorerMiddlewareService } from './data-explorer-middleware-servic
 
 export const dataExplorerMiddleware =
     (service: DataExplorerMiddlewareService): Middleware =>
-    (api) =>
-    (next) => {
-        const actions = bindDataExplorerActions(service.getId());
+        (api) =>
+            (next) => {
+                const actions = bindDataExplorerActions(service.getId());
 
-        return (action) => {
-            const handleAction =
-                <T extends { id: string }>(handler: (data: T) => void) =>
-                    (data: T) => {
-                        next(action);
-                        if (data.id === service.getId()) {
-                            handler(data);
-                        }
-                    };
-            dataExplorerActions.match(action, {
-                SET_PAGE: handleAction(() => {
-                    api.dispatch(actions.REQUEST_ITEMS(false));
-                }),
-                SET_ROWS_PER_PAGE: handleAction(() => {
-                    api.dispatch(actions.REQUEST_ITEMS(true));
-                }),
-                SET_FILTERS: handleAction(() => {
-                    api.dispatch(actions.RESET_PAGINATION());
-                    api.dispatch(actions.REQUEST_ITEMS(true));
-                }),
-                TOGGLE_SORT: handleAction(() => {
-                    api.dispatch(actions.REQUEST_ITEMS(true));
-                }),
-                SET_EXPLORER_SEARCH_VALUE: handleAction(() => {
-                    api.dispatch(actions.RESET_PAGINATION());
-                    api.dispatch(actions.REQUEST_ITEMS(true));
-                }),
-                REQUEST_ITEMS: handleAction(({ criteriaChanged }) => {
-                    api.dispatch<any>(async (
-                        dispatch: Dispatch,
-                        getState: () => RootState,
-                        services: ServiceRepository
-                    ) => {
-                        while (true) {
-                            let de = getDataExplorer(
-                                getState().dataExplorer,
-                                service.getId()
-                            );
-                            switch (de.requestState) {
-                                case DataTableRequestState.IDLE:
-                                    // Start a new request.
-                                    try {
-                                        dispatch(
-                                            actions.SET_REQUEST_STATE({
-                                                requestState: DataTableRequestState.PENDING,
-                                            })
-                                        );
-                                        await service.requestItems(api, criteriaChanged);
-                                    } catch {
-                                        dispatch(
-                                            actions.SET_REQUEST_STATE({
-                                                requestState: DataTableRequestState.NEED_REFRESH,
-                                            })
-                                        );
-                                    }
-                                    // Now check if the state is still PENDING, if it moved to NEED_REFRESH
-                                    // then we need to reissue requestItems
-                                    de = getDataExplorer(
+                return (action) => {
+                    const handleAction =
+                        <T extends { id: string }>(handler: (data: T) => void) =>
+                            (data: T) => {
+                                next(action);
+                                if (data.id === service.getId()) {
+                                    handler(data);
+                                }
+                            };
+                    dataExplorerActions.match(action, {
+                        SET_PAGE: handleAction(() => {
+                            api.dispatch(actions.REQUEST_ITEMS(false));
+                        }),
+                        SET_ROWS_PER_PAGE: handleAction(() => {
+                            api.dispatch(actions.REQUEST_ITEMS(true));
+                        }),
+                        SET_FILTERS: handleAction(() => {
+                            api.dispatch(actions.RESET_PAGINATION());
+                            api.dispatch(actions.REQUEST_ITEMS(true));
+                        }),
+                        TOGGLE_SORT: handleAction(() => {
+                            api.dispatch(actions.REQUEST_ITEMS(true));
+                        }),
+                        SET_EXPLORER_SEARCH_VALUE: handleAction(() => {
+                            api.dispatch(actions.RESET_PAGINATION());
+                            api.dispatch(actions.REQUEST_ITEMS(true));
+                        }),
+                        REQUEST_ITEMS: handleAction(({ criteriaChanged, background }) => {
+                            api.dispatch<any>(async (
+                                dispatch: Dispatch,
+                                getState: () => RootState,
+                                services: ServiceRepository
+                            ) => {
+                                while (true) {
+                                    let de = getDataExplorer(
                                         getState().dataExplorer,
                                         service.getId()
                                     );
-                                    const complete =
-                                        de.requestState === DataTableRequestState.PENDING;
-                                    dispatch(
-                                        actions.SET_REQUEST_STATE({
-                                            requestState: DataTableRequestState.IDLE,
-                                        })
-                                    );
-                                    if (complete) {
-                                        return;
+                                    switch (de.requestState) {
+                                        case DataTableRequestState.IDLE:
+                                            // Start a new request.
+                                            try {
+                                                dispatch(
+                                                    actions.SET_REQUEST_STATE({
+                                                        requestState: DataTableRequestState.PENDING,
+                                                    })
+                                                );
+                                                await service.requestItems(api, criteriaChanged, background);
+                                            } catch {
+                                                dispatch(
+                                                    actions.SET_REQUEST_STATE({
+                                                        requestState: DataTableRequestState.NEED_REFRESH,
+                                                    })
+                                                );
+                                            }
+                                            // Now check if the state is still PENDING, if it moved to NEED_REFRESH
+                                            // then we need to reissue requestItems
+                                            de = getDataExplorer(
+                                                getState().dataExplorer,
+                                                service.getId()
+                                            );
+                                            const complete =
+                                                de.requestState === DataTableRequestState.PENDING;
+                                            dispatch(
+                                                actions.SET_REQUEST_STATE({
+                                                    requestState: DataTableRequestState.IDLE,
+                                                })
+                                            );
+                                            if (complete) {
+                                                return;
+                                            }
+                                            break;
+                                        case DataTableRequestState.PENDING:
+                                            // State is PENDING, move it to NEED_REFRESH so that when the current request finishes it starts a new one.
+                                            dispatch(
+                                                actions.SET_REQUEST_STATE({
+                                                    requestState: DataTableRequestState.NEED_REFRESH,
+                                                })
+                                            );
+                                            return;
+                                        case DataTableRequestState.NEED_REFRESH:
+                                            // Nothing to do right now.
+                                            return;
                                     }
-                                    break;
-                                case DataTableRequestState.PENDING:
-                                    // State is PENDING, move it to NEED_REFRESH so that when the current request finishes it starts a new one.
-                                    dispatch(
-                                        actions.SET_REQUEST_STATE({
-                                            requestState: DataTableRequestState.NEED_REFRESH,
-                                        })
-                                    );
-                                    return;
-                                case DataTableRequestState.NEED_REFRESH:
-                                    // Nothing to do right now.
-                                    return;
-                            }
-                        }
+                                }
+                            });
+                        }),
+                        default: () => next(action),
                     });
-                }),
-                default: () => next(action),
-            });
-        };
-    };
+                };
+            };
index 526629cd024b759112df06e41782f990fb2d29ec..1063d0bd487f87c33c0ec13f6d84695db3ecad35 100644 (file)
@@ -129,15 +129,21 @@ export const getProcessStatus = ({ containerRequest, container }: Process): Proc
         case containerRequest.containerUuid && !container:
             return ProcessStatus.UNKNOWN;
 
+        case containerRequest.state === ContainerRequestState.UNCOMMITTED:
+            return ProcessStatus.DRAFT;
+
+        case containerRequest.state === ContainerRequestState.FINAL &&
+            container?.state === ContainerState.RUNNING:
+            // It's right about to be completed but we haven't
+            // gotten the updated container record yet
+            return ProcessStatus.RUNNING;
+
         case containerRequest.state === ContainerRequestState.FINAL &&
             container?.state !== ContainerState.COMPLETE:
             // Request was finalized before its container started (or the
             // container was cancelled)
             return ProcessStatus.CANCELLED;
 
-        case containerRequest.state === ContainerRequestState.UNCOMMITTED:
-            return ProcessStatus.DRAFT;
-
         case container && container.state === ContainerState.COMPLETE:
             if (container?.exitCode === 0) {
                 if (containerRequest && container.finishedAt) {
index 7204993b5c2f9545077ff15243518df539a4fb2f..09b39afb2bd3918265b9d807d9e9046795c5bdde 100644 (file)
@@ -41,7 +41,7 @@ export class ProjectPanelMiddlewareService extends DataExplorerMiddlewareService
         super(id);
     }
 
-    async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+    async requestItems(api: MiddlewareAPI<Dispatch, RootState>, criteriaChanged?: boolean, background?: boolean) {
         const state = api.getState();
         const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
         const projectUuid = getProjectPanelCurrentUuid(state);
@@ -52,7 +52,7 @@ export class ProjectPanelMiddlewareService extends DataExplorerMiddlewareService
             api.dispatch(projectPanelDataExplorerIsNotSet());
         } else {
             try {
-                api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
+                if (!background) { api.dispatch(progressIndicatorActions.START_WORKING(this.getId())); }
                 const response = await this.services.groupsService.contents(projectUuid, getParams(dataExplorer, !!isProjectTrashed));
                 const resourceUuids = response.items.map(item => item.uuid);
                 api.dispatch<any>(updateFavorites(resourceUuids));
@@ -71,7 +71,7 @@ export class ProjectPanelMiddlewareService extends DataExplorerMiddlewareService
                 );
                 api.dispatch(couldNotFetchProjectContents());
             } finally {
-                api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+                if (!background) { api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId())); }
             }
         }
     }
index 986c6ebde6c3b06d515a01d81dbab05129dc815d..5124c8346a6951fe656cf0ae255038a7cfc344bd 100644 (file)
@@ -26,19 +26,19 @@ export class SubprocessMiddlewareService extends DataExplorerMiddlewareService {
         super(id);
     }
 
-    async requestItems(api: MiddlewareAPI<Dispatch, RootState>) {
+    async requestItems(api: MiddlewareAPI<Dispatch, RootState>, criteriaChanged?: boolean, background?: boolean) {
         const state = api.getState();
         const parentContainerRequestUuid = state.processPanel.containerRequestUuid;
         if (parentContainerRequestUuid === "") { return; }
         const dataExplorer = getDataExplorer(state.dataExplorer, this.getId());
 
         try {
-            api.dispatch(progressIndicatorActions.START_WORKING(this.getId()));
+            if (!background) { api.dispatch(progressIndicatorActions.START_WORKING(this.getId())); }
             const parentContainerRequest = await this.services.containerRequestService.get(parentContainerRequestUuid);
             if (parentContainerRequest.containerUuid) {
                 const containerRequests = await this.services.containerRequestService.list(
                     {
-                        ...getParams(dataExplorer, parentContainerRequest) ,
+                        ...getParams(dataExplorer, parentContainerRequest),
                         select: containerRequestFieldsNoMounts
                     });
                 api.dispatch(updateResources(containerRequests.items));
@@ -46,9 +46,9 @@ export class SubprocessMiddlewareService extends DataExplorerMiddlewareService {
                 // Populate the actual user view
                 api.dispatch(setItems(containerRequests));
             }
-            api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+            if (!background) { api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId())); }
         } catch {
-            api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId()));
+            if (!background) { api.dispatch(progressIndicatorActions.PERSIST_STOP_WORKING(this.getId())); }
             api.dispatch(couldNotFetchSubprocesses());
         }
     }
@@ -65,27 +65,27 @@ export const getParams = (
 export const getFilters = (
     dataExplorer: DataExplorer,
     parentContainerRequest: ContainerRequestResource) => {
-        const columns = dataExplorer.columns as DataColumns<string, ProcessResource>;
-        const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
-        const activeStatusFilter = Object.keys(statusColumnFilters).find(
-            filterName => statusColumnFilters[filterName].selected
-        ) || ProcessStatusFilter.ALL;
+    const columns = dataExplorer.columns as DataColumns<string, ProcessResource>;
+    const statusColumnFilters = getDataExplorerColumnFilters(columns, 'Status');
+    const activeStatusFilter = Object.keys(statusColumnFilters).find(
+        filterName => statusColumnFilters[filterName].selected
+    ) || ProcessStatusFilter.ALL;
 
-        // Get all the subprocess' container requests and containers.
-        const fb = new FilterBuilder().addEqual('requesting_container_uuid', parentContainerRequest.containerUuid);
-        const statusFilters = buildProcessStatusFilters(fb, activeStatusFilter).getFilters();
+    // Get all the subprocess' container requests and containers.
+    const fb = new FilterBuilder().addEqual('requesting_container_uuid', parentContainerRequest.containerUuid);
+    const statusFilters = buildProcessStatusFilters(fb, activeStatusFilter).getFilters();
 
-        const nameFilters = dataExplorer.searchValue
-            ? new FilterBuilder()
-                .addILike("name", dataExplorer.searchValue)
-                .getFilters()
-            : '';
+    const nameFilters = dataExplorer.searchValue
+        ? new FilterBuilder()
+            .addILike("name", dataExplorer.searchValue)
+            .getFilters()
+        : '';
 
-        return joinFilters(
-            nameFilters,
-            statusFilters
-        );
-    };
+    return joinFilters(
+        nameFilters,
+        statusFilters
+    );
+};
 
 export const setItems = (listResults: ListResults<ProcessResource>) =>
     subprocessPanelActions.SET_ITEMS({
index a7be6ba1f9bee63471436bf4c15c6893ef7ca164..1b74b11f3fa665601fdf75d4aa9fc7b808623242 100644 (file)
@@ -46,7 +46,7 @@ const messageListener = (store: RootStore) => (message: ResourceEventMessage) =>
                     }
                     const proc = getProcess(state.processPanel.containerRequestUuid)(state.resources);
                     if (proc && proc.container && proc.container.uuid === message.properties["new_attributes"]["requesting_container_uuid"]) {
-                        store.dispatch(subprocessPanelActions.REQUEST_ITEMS());
+                        store.dispatch(subprocessPanelActions.REQUEST_ITEMS(false, true));
                         return;
                     }
                 }
@@ -57,16 +57,16 @@ const messageListener = (store: RootStore) => (message: ResourceEventMessage) =>
                     const subproc = getSubprocesses(state.processPanel.containerRequestUuid)(state.resources);
                     for (const sb of subproc) {
                         if (sb.containerRequest.uuid === message.objectUuid || (sb.container && sb.container.uuid === message.objectUuid)) {
-                            store.dispatch(subprocessPanelActions.REQUEST_ITEMS());
+                            store.dispatch(subprocessPanelActions.REQUEST_ITEMS(false, true));
                             break;
                         }
                     }
                 }
                 if (matchAllProcessesRoute(location)) {
-                    store.dispatch(allProcessesPanelActions.REQUEST_ITEMS());
+                    store.dispatch(allProcessesPanelActions.REQUEST_ITEMS(false, true));
                 }
                 if (matchProjectRoute(location) && message.objectOwnerUuid === getProjectPanelCurrentUuid(state)) {
-                    store.dispatch(projectPanelActions.REQUEST_ITEMS());
+                    store.dispatch(projectPanelActions.REQUEST_ITEMS(false, true));
                 }
                 return;
             default: