+
{displayCase(target)} ({displayCase(environment)})
)}
diff --git a/app/src/js/reducers/execution-status.js b/app/src/js/reducers/execution-status.js
index ee99a1243..7fdc46280 100644
--- a/app/src/js/reducers/execution-status.js
+++ b/app/src/js/reducers/execution-status.js
@@ -1,4 +1,5 @@
import { createReducer } from '@reduxjs/toolkit';
+import get from 'lodash/get';
import {
EXECUTION_STATUS,
EXECUTION_STATUS_INFLIGHT,
@@ -8,9 +9,7 @@ import {
} from '../actions/types';
export const initialState = {
- execution: null,
- executionHistory: null,
- stateMachine: null,
+ data: {},
searchString: null,
inflight: false,
error: false,
@@ -25,13 +24,10 @@ export default createReducer(initialState, {
const { data } = action;
state.inflight = false;
state.error = false;
- state.execution = data.execution;
- state.executionHistory = data.executionHistory;
- state.stateMachine = data.stateMachine;
- state.warning = data.warning;
+ state.data = data;
- if (state.searchString) {
- state.executionHistory.events = data.executionHistory.events.filter(
+ if (state.searchString && get(state, 'data.data.executionHistory.events')) {
+ state.data.data.executionHistory.events = data.data.executionHistory.events.filter(
typeContains(state.searchString)
);
}
diff --git a/app/src/js/reducers/index.js b/app/src/js/reducers/index.js
index 464c799d5..962ea05f9 100644
--- a/app/src/js/reducers/index.js
+++ b/app/src/js/reducers/index.js
@@ -22,6 +22,7 @@ import executionLogs from './execution-logs';
import operations from './operations';
import rules from './rules';
import reconciliationReports from './reconciliation-reports';
+import recoveryStatus from './recovery-status';
import cumulusInstance from './cumulus-instance';
import sidebar from './sidebar';
import sorts from './sort-persist';
@@ -54,6 +55,7 @@ export const reducers = {
operations,
rules,
reconciliationReports,
+ recoveryStatus,
sorts,
locationQueryParams,
};
diff --git a/app/src/js/reducers/recovery-status.js b/app/src/js/reducers/recovery-status.js
new file mode 100644
index 000000000..8c0a5ec28
--- /dev/null
+++ b/app/src/js/reducers/recovery-status.js
@@ -0,0 +1,45 @@
+import { createReducer } from '@reduxjs/toolkit';
+import assignDate from './utils/assign-date';
+
+import {
+ RECOVERY_GRANULE,
+ RECOVERY_GRANULE_INFLIGHT,
+ RECOVERY_GRANULE_ERROR,
+} from '../actions/types';
+
+export const initialState = {
+ list: {
+ data: [],
+ meta: {},
+ params: {},
+ },
+ map: {},
+};
+
+export default createReducer(initialState, {
+ [RECOVERY_GRANULE]: (state, action) => {
+ state.map[action.id] = {
+ data: assignDate(action.data),
+ error: false,
+ inflight: false,
+ };
+ },
+ [RECOVERY_GRANULE_INFLIGHT]: (state, action) => {
+ state.map[action.id] = { inflight: true };
+ },
+ [RECOVERY_GRANULE_ERROR]: (state, action) => {
+ let actionError = {};
+ try {
+ actionError = JSON.parse(action.error);
+ } catch (_) {
+ // empty
+ }
+
+ if (actionError.errorType !== 'NotFound' && actionError.httpStatus !== 404) {
+ state.map[action.id] = {
+ error: action.error,
+ inflight: false,
+ };
+ }
+ },
+});
diff --git a/app/src/js/utils/recovery-status.js b/app/src/js/utils/recovery-status.js
new file mode 100644
index 000000000..d55eb2c48
--- /dev/null
+++ b/app/src/js/utils/recovery-status.js
@@ -0,0 +1,16 @@
+export const getGranuleRecoveryJobStatusFromRecord = (record) => {
+ if (!record) return undefined;
+ const jobStatuses = (record.files || []).map((file) => file.status);
+ // file status may be 'pending', 'staged', 'success', or 'failed'
+ let recoveryStatus = 'failed';
+ if (jobStatuses.length === 0) {
+ recoveryStatus = undefined;
+ } else if (jobStatuses.filter((jobStatus) => jobStatus !== 'success').length === 0) {
+ recoveryStatus = 'completed';
+ } else if (jobStatuses.filter((jobStatus) => !['success', 'failed'].includes(jobStatus)).length > 0) {
+ recoveryStatus = 'running';
+ }
+ return recoveryStatus;
+};
+
+export default getGranuleRecoveryJobStatusFromRecord;
diff --git a/app/src/js/utils/table-config/executions.js b/app/src/js/utils/table-config/executions.js
index fdbd33434..993cd4767 100644
--- a/app/src/js/utils/table-config/executions.js
+++ b/app/src/js/utils/table-config/executions.js
@@ -3,6 +3,7 @@ import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCheckCircle, faTimesCircle } from '@fortawesome/free-solid-svg-icons';
import cloneDeep from 'lodash/cloneDeep';
+import get from 'lodash/get';
import {
displayCase,
seconds,
@@ -14,6 +15,7 @@ import { strings } from '../../components/locale';
import { getPersistentQueryParams } from '../url-helper';
import { getEventDetails } from '../../components/Executions/execution-graph-utils';
import Tooltip from '../../components/Tooltip/tooltip';
+import { getExecutionStatus } from '../../actions';
export const formatEvents = (events) => {
const mutableEvents = cloneDeep(events);
@@ -70,7 +72,7 @@ export const subColumns = [
},
];
-export const tableColumns = [
+export const tableColumns = ({ dispatch }) => ([
{
Header: 'Name',
accessor: 'name',
@@ -116,7 +118,28 @@ export const tableColumns = [
accessor: 'collectionId',
width: 200,
Cell: ({ cell: { value } }) => formatCollectionId(value)
+ },
+ {
+ Header: 'Download Execution',
+ id: 'download',
+ accessor: 'name',
+ Cell: ({ row: { original: { arn } } }) => (// eslint-disable-line react/prop-types
+