From 15bd0a142e05885897183234941f31da413ae2ab Mon Sep 17 00:00:00 2001 From: Ken Hibino Date: Thu, 21 Jan 2021 06:59:46 -0800 Subject: [PATCH] Add redux actions and reducer for pending task delete/archive --- ui/src/actions/tasksActions.ts | 286 ++++++++++++++++++++++++++++- ui/src/api.ts | 63 +++++++ ui/src/reducers/snackbarReducer.ts | 48 +++++ ui/src/reducers/tasksReducer.ts | 162 ++++++++++++++++ 4 files changed, 556 insertions(+), 3 deletions(-) diff --git a/ui/src/actions/tasksActions.ts b/ui/src/actions/tasksActions.ts index 7fa4314..5661d9d 100644 --- a/ui/src/actions/tasksActions.ts +++ b/ui/src/actions/tasksActions.ts @@ -41,6 +41,12 @@ import { runArchivedTask, runRetryTask, runScheduledTask, + deletePendingTask, + batchDeletePendingTasks, + deleteAllPendingTasks, + archivePendingTask, + batchArchivePendingTasks, + archiveAllPendingTasks, } from "../api"; import { Dispatch } from "redux"; @@ -82,6 +88,12 @@ export const RUN_RETRY_TASK_ERROR = "RUN_RETRY_TASK_ERROR"; export const RUN_ARCHIVED_TASK_BEGIN = "RUN_ARCHIVED_TASK_BEGIN"; export const RUN_ARCHIVED_TASK_SUCCESS = "RUN_ARCHIVED_TASK_SUCCESS"; export const RUN_ARCHIVED_TASK_ERROR = "RUN_ARCHIVED_TASK_ERROR"; +export const DELETE_PENDING_TASK_BEGIN = "DELETE_PENDING_TASK_BEGIN"; +export const DELETE_PENDING_TASK_SUCCESS = "DELETE_PENDING_TASK_SUCCESS"; +export const DELETE_PENDING_TASK_ERROR = "DELETE_PENDING_TASK_ERROR"; +export const ARCHIVE_PENDING_TASK_BEGIN = "ARCHIVE_PENDING_TASK_BEGIN"; +export const ARCHIVE_PENDING_TASK_SUCCESS = "ARCHIVE_PENDING_TASK_SUCCESS"; +export const ARCHIVE_PENDING_TASK_ERROR = "ARCHIVE_PENDING_TASK_ERROR"; export const DELETE_SCHEDULED_TASK_BEGIN = "DELETE_SCHEDULED_TASK_BEGIN"; export const DELETE_SCHEDULED_TASK_SUCCESS = "DELETE_SCHEDULED_TASK_SUCCESS"; export const DELETE_SCHEDULED_TASK_ERROR = "DELETE_SCHEDULED_TASK_ERROR"; @@ -91,6 +103,28 @@ export const ARCHIVE_SCHEDULED_TASK_ERROR = "ARCHIVE_SCHEDULED_TASK_ERROR"; export const ARCHIVE_RETRY_TASK_BEGIN = "ARCHIVE_RETRY_TASK_BEGIN"; export const ARCHIVE_RETRY_TASK_SUCCESS = "ARCHIVE_RETRY_TASK_SUCCESS"; export const ARCHIVE_RETRY_TASK_ERROR = "ARCHIVE_RETRY_TASK_ERROR"; +export const BATCH_ARCHIVE_PENDING_TASKS_BEGIN = + "BATCH_ARCHIVE_PENDING_TASKS_BEGIN"; +export const BATCH_ARCHIVE_PENDING_TASKS_SUCCESS = + "BATCH_ARCHIVE_PENDING_TASKS_SUCCESS"; +export const BATCH_ARCHIVE_PENDING_TASKS_ERROR = + "BATCH_RUN_PENDING_TASKS_ERROR"; +export const BATCH_DELETE_PENDING_TASKS_BEGIN = + "BATCH_DELETE_PENDING_TASKS_BEGIN"; +export const BATCH_DELETE_PENDING_TASKS_SUCCESS = + "BATCH_DELETE_PENDING_TASKS_SUCCESS"; +export const BATCH_DELETE_PENDING_TASKS_ERROR = + "BATCH_DELETE_PENDING_TASKS_ERROR"; +export const DELETE_ALL_PENDING_TASKS_BEGIN = "DELETE_ALL_PENDING_TASKS_BEGIN"; +export const DELETE_ALL_PENDING_TASKS_SUCCESS = + "DELETE_ALL_PENDING_TASKS_SUCCESS"; +export const DELETE_ALL_PENDING_TASKS_ERROR = "DELETE_ALL_PENDING_TASKS_ERROR"; +export const ARCHIVE_ALL_PENDING_TASKS_BEGIN = + "ARCHIVE_ALL_PENDING_TASKS_BEGIN"; +export const ARCHIVE_ALL_PENDING_TASKS_SUCCESS = + "ARCHIVE_ALL_PENDING_TASKS_SUCCESS"; +export const ARCHIVE_ALL_PENDING_TASKS_ERROR = + "ARCHIVE_ALL_PENDING_TASKS_ERROR"; export const BATCH_RUN_SCHEDULED_TASKS_BEGIN = "BATCH_RUN_SCHEDULED_TASKS_BEGIN"; export const BATCH_RUN_SCHEDULED_TASKS_SUCCESS = @@ -313,6 +347,114 @@ interface BatchCancelActiveTasksErrorAction { error: string; } +interface DeletePendingTaskBeginAction { + type: typeof DELETE_PENDING_TASK_BEGIN; + queue: string; + taskKey: string; +} + +interface DeletePendingTaskSuccessAction { + type: typeof DELETE_PENDING_TASK_SUCCESS; + queue: string; + taskKey: string; +} + +interface DeletePendingTaskErrorAction { + type: typeof DELETE_PENDING_TASK_ERROR; + queue: string; + taskKey: string; + error: string; +} + +interface BatchDeletePendingTasksBeginAction { + type: typeof BATCH_DELETE_PENDING_TASKS_BEGIN; + queue: string; + taskKeys: string[]; +} + +interface BatchDeletePendingTasksSuccessAction { + type: typeof BATCH_DELETE_PENDING_TASKS_SUCCESS; + queue: string; + payload: BatchDeleteTasksResponse; +} + +interface BatchDeletePendingTasksErrorAction { + type: typeof BATCH_DELETE_PENDING_TASKS_ERROR; + queue: string; + taskKeys: string[]; + error: string; +} + +interface DeleteAllPendingTasksBeginAction { + type: typeof DELETE_ALL_PENDING_TASKS_BEGIN; + queue: string; +} + +interface DeleteAllPendingTasksSuccessAction { + type: typeof DELETE_ALL_PENDING_TASKS_SUCCESS; + queue: string; +} + +interface DeleteAllPendingTasksErrorAction { + type: typeof DELETE_ALL_PENDING_TASKS_ERROR; + queue: string; + error: string; +} + +interface ArchivePendingTaskBeginAction { + type: typeof ARCHIVE_PENDING_TASK_BEGIN; + queue: string; + taskKey: string; +} + +interface ArchivePendingTaskSuccessAction { + type: typeof ARCHIVE_PENDING_TASK_SUCCESS; + queue: string; + taskKey: string; +} + +interface ArchivePendingTaskErrorAction { + type: typeof ARCHIVE_PENDING_TASK_ERROR; + queue: string; + taskKey: string; + error: string; +} + +interface BatchArchivePendingTasksBeginAction { + type: typeof BATCH_ARCHIVE_PENDING_TASKS_BEGIN; + queue: string; + taskKeys: string[]; +} + +interface BatchArchivePendingTasksSuccessAction { + type: typeof BATCH_ARCHIVE_PENDING_TASKS_SUCCESS; + queue: string; + payload: BatchArchiveTasksResponse; +} + +interface BatchArchivePendingTasksErrorAction { + type: typeof BATCH_ARCHIVE_PENDING_TASKS_ERROR; + queue: string; + taskKeys: string[]; + error: string; +} + +interface ArchiveAllPendingTasksBeginAction { + type: typeof ARCHIVE_ALL_PENDING_TASKS_BEGIN; + queue: string; +} + +interface ArchiveAllPendingTasksSuccessAction { + type: typeof ARCHIVE_ALL_PENDING_TASKS_SUCCESS; + queue: string; +} + +interface ArchiveAllPendingTasksErrorAction { + type: typeof ARCHIVE_ALL_PENDING_TASKS_ERROR; + queue: string; + error: string; +} + interface RunScheduledTaskBeginAction { type: typeof RUN_SCHEDULED_TASK_BEGIN; queue: string; @@ -771,6 +913,24 @@ export type TasksActionTypes = | BatchCancelActiveTasksBeginAction | BatchCancelActiveTasksSuccessAction | BatchCancelActiveTasksErrorAction + | DeletePendingTaskBeginAction + | DeletePendingTaskSuccessAction + | DeletePendingTaskErrorAction + | BatchDeletePendingTasksBeginAction + | BatchDeletePendingTasksSuccessAction + | BatchDeletePendingTasksErrorAction + | DeleteAllPendingTasksBeginAction + | DeleteAllPendingTasksSuccessAction + | DeleteAllPendingTasksErrorAction + | ArchivePendingTaskBeginAction + | ArchivePendingTaskSuccessAction + | ArchivePendingTaskErrorAction + | BatchArchivePendingTasksBeginAction + | BatchArchivePendingTasksSuccessAction + | BatchArchivePendingTasksErrorAction + | ArchiveAllPendingTasksBeginAction + | ArchiveAllPendingTasksSuccessAction + | ArchiveAllPendingTasksErrorAction | RunScheduledTaskBeginAction | RunScheduledTaskSuccessAction | RunScheduledTaskErrorAction @@ -1051,6 +1211,24 @@ export function runRetryTaskAsync(queue: string, taskKey: string) { }; } +export function archivePendingTaskAsync(queue: string, taskKey: string) { + return async (dispatch: Dispatch) => { + dispatch({ type: ARCHIVE_PENDING_TASK_BEGIN, queue, taskKey }); + try { + await archivePendingTask(queue, taskKey); + dispatch({ type: ARCHIVE_PENDING_TASK_SUCCESS, queue, taskKey }); + } catch (error) { + console.error("archivePendingTaskAsync: ", error); + dispatch({ + type: ARCHIVE_PENDING_TASK_ERROR, + error: `Could not archive task: ${taskKey}`, + queue, + taskKey, + }); + } + }; +} + export function archiveScheduledTaskAsync(queue: string, taskKey: string) { return async (dispatch: Dispatch) => { dispatch({ type: ARCHIVE_SCHEDULED_TASK_BEGIN, queue, taskKey }); @@ -1105,6 +1283,49 @@ export function runArchivedTaskAsync(queue: string, taskKey: string) { }; } +export function deletePendingTaskAsync(queue: string, taskKey: string) { + return async (dispatch: Dispatch) => { + dispatch({ type: DELETE_PENDING_TASK_BEGIN, queue, taskKey }); + try { + await deletePendingTask(queue, taskKey); + dispatch({ type: DELETE_PENDING_TASK_SUCCESS, queue, taskKey }); + } catch (error) { + console.error("deletePendingTaskAsync: ", error); + dispatch({ + type: DELETE_PENDING_TASK_ERROR, + error: `Could not delete task: ${taskKey}`, + queue, + taskKey, + }); + } + }; +} + +export function batchDeletePendingTasksAsync( + queue: string, + taskKeys: string[] +) { + return async (dispatch: Dispatch) => { + dispatch({ type: BATCH_DELETE_PENDING_TASKS_BEGIN, queue, taskKeys }); + try { + const response = await batchDeletePendingTasks(queue, taskKeys); + dispatch({ + type: BATCH_DELETE_PENDING_TASKS_SUCCESS, + queue: queue, + payload: response, + }); + } catch (error) { + console.error("batchDeletePendingTasksAsync: ", error); + dispatch({ + type: BATCH_DELETE_PENDING_TASKS_ERROR, + error: `Could not batch delete tasks: ${taskKeys}`, + queue, + taskKeys, + }); + } + }; +} + export function deleteScheduledTaskAsync(queue: string, taskKey: string) { return async (dispatch: Dispatch) => { dispatch({ type: DELETE_SCHEDULED_TASK_BEGIN, queue, taskKey }); @@ -1195,6 +1416,65 @@ export function batchArchiveScheduledTasksAsync( }; } +export function batchArchivePendingTasksAsync( + queue: string, + taskKeys: string[] +) { + return async (dispatch: Dispatch) => { + dispatch({ type: BATCH_ARCHIVE_PENDING_TASKS_BEGIN, queue, taskKeys }); + try { + const response = await batchArchivePendingTasks(queue, taskKeys); + dispatch({ + type: BATCH_ARCHIVE_PENDING_TASKS_SUCCESS, + queue: queue, + payload: response, + }); + } catch (error) { + console.error("batchArchivePendingTasksAsync: ", error); + dispatch({ + type: BATCH_ARCHIVE_PENDING_TASKS_ERROR, + error: `Could not batch archive tasks: ${taskKeys}`, + queue, + taskKeys, + }); + } + }; +} + +export function archiveAllPendingTasksAsync(queue: string) { + return async (dispatch: Dispatch) => { + dispatch({ type: ARCHIVE_ALL_PENDING_TASKS_BEGIN, queue }); + try { + await archiveAllPendingTasks(queue); + dispatch({ type: ARCHIVE_ALL_PENDING_TASKS_SUCCESS, queue }); + } catch (error) { + console.error("archiveAllPendingTasksAsync: ", error); + dispatch({ + type: ARCHIVE_ALL_PENDING_TASKS_ERROR, + error: `Could not archive all pending tasks`, + queue, + }); + } + }; +} + +export function deleteAllPendingTasksAsync(queue: string) { + return async (dispatch: Dispatch) => { + dispatch({ type: DELETE_ALL_PENDING_TASKS_BEGIN, queue }); + try { + await deleteAllPendingTasks(queue); + dispatch({ type: DELETE_ALL_PENDING_TASKS_SUCCESS, queue }); + } catch (error) { + console.error("deleteAllPendingTasksAsync: ", error); + dispatch({ + type: DELETE_ALL_PENDING_TASKS_ERROR, + error: `Could not delete all pending tasks`, + queue, + }); + } + }; +} + export function deleteAllScheduledTasksAsync(queue: string) { return async (dispatch: Dispatch) => { dispatch({ type: DELETE_ALL_SCHEDULED_TASKS_BEGIN, queue }); @@ -1231,14 +1511,14 @@ export function runAllScheduledTasksAsync(queue: string) { export function archiveAllScheduledTasksAsync(queue: string) { return async (dispatch: Dispatch) => { - dispatch({ type: RUN_ALL_SCHEDULED_TASKS_BEGIN, queue }); + dispatch({ type: ARCHIVE_ALL_SCHEDULED_TASKS_BEGIN, queue }); try { await archiveAllScheduledTasks(queue); - dispatch({ type: RUN_ALL_SCHEDULED_TASKS_SUCCESS, queue }); + dispatch({ type: ARCHIVE_ALL_SCHEDULED_TASKS_SUCCESS, queue }); } catch (error) { console.error("archiveAllScheduledTasksAsync: ", error); dispatch({ - type: RUN_ALL_SCHEDULED_TASKS_ERROR, + type: ARCHIVE_ALL_SCHEDULED_TASKS_ERROR, error: `Could not archive all scheduled tasks`, queue, }); diff --git a/ui/src/api.ts b/ui/src/api.ts index b6a7eb2..8267938 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -247,6 +247,7 @@ export interface ActiveTask extends BaseTask { export interface PendingTask extends BaseTask { id: string; + key: string; queue: string; } @@ -459,6 +460,68 @@ export async function listArchivedTasks( return resp.data; } +export async function archivePendingTask( + qname: string, + taskKey: string +): Promise { + await axios({ + method: "post", + url: `${BASE_URL}/queues/${qname}/pending_tasks/${taskKey}:archive`, + }); +} + +export async function batchArchivePendingTasks( + qname: string, + taskKeys: string[] +): Promise { + const resp = await axios({ + method: "post", + url: `${BASE_URL}/queues/${qname}/pending_tasks:batch_archive`, + data: { + task_keys: taskKeys, + }, + }); + return resp.data; +} + +export async function archiveAllPendingTasks(qname: string): Promise { + await axios({ + method: "post", + url: `${BASE_URL}/queues/${qname}/pending_tasks:archive_all`, + }); +} + +export async function deletePendingTask( + qname: string, + taskKey: string +): Promise { + await axios({ + method: "delete", + url: `${BASE_URL}/queues/${qname}/pending_tasks/${taskKey}`, + }); +} + +export async function batchDeletePendingTasks( + qname: string, + taskKeys: string[] +): Promise { + const resp = await axios({ + method: "post", + url: `${BASE_URL}/queues/${qname}/pending_tasks:batch_delete`, + data: { + task_keys: taskKeys, + }, + }); + return resp.data; +} + +export async function deleteAllPendingTasks(qname: string): Promise { + await axios({ + method: "delete", + url: `${BASE_URL}/queues/${qname}/pending_tasks:delete_all`, + }); +} + export async function runScheduledTask( qname: string, taskKey: string diff --git a/ui/src/reducers/snackbarReducer.ts b/ui/src/reducers/snackbarReducer.ts index e6cb8d8..ca2380e 100644 --- a/ui/src/reducers/snackbarReducer.ts +++ b/ui/src/reducers/snackbarReducer.ts @@ -30,6 +30,12 @@ import { RUN_RETRY_TASK_SUCCESS, RUN_SCHEDULED_TASK_SUCCESS, TasksActionTypes, + ARCHIVE_PENDING_TASK_SUCCESS, + DELETE_PENDING_TASK_SUCCESS, + BATCH_ARCHIVE_PENDING_TASKS_SUCCESS, + BATCH_DELETE_PENDING_TASKS_SUCCESS, + ARCHIVE_ALL_PENDING_TASKS_SUCCESS, + DELETE_ALL_PENDING_TASKS_SUCCESS, } from "../actions/tasksActions"; interface SnackbarState { @@ -89,6 +95,12 @@ function snackbarReducer( message: `Archived task is now pending`, }; + case ARCHIVE_PENDING_TASK_SUCCESS: + return { + isOpen: true, + message: `Pending task is now archived`, + }; + case ARCHIVE_SCHEDULED_TASK_SUCCESS: return { isOpen: true, @@ -101,6 +113,12 @@ function snackbarReducer( message: `Retry task is now archived`, }; + case DELETE_PENDING_TASK_SUCCESS: + return { + isOpen: true, + message: `Pending task deleted`, + }; + case DELETE_SCHEDULED_TASK_SUCCESS: return { isOpen: true, @@ -117,6 +135,24 @@ function snackbarReducer( }; } + case BATCH_ARCHIVE_PENDING_TASKS_SUCCESS: { + const n = action.payload.archived_keys.length; + return { + isOpen: true, + message: `${n} pending ${ + n === 1 ? "task is" : "tasks are" + } now archived`, + }; + } + + case BATCH_DELETE_PENDING_TASKS_SUCCESS: { + const n = action.payload.deleted_keys.length; + return { + isOpen: true, + message: `${n} pending ${n === 1 ? "task" : "tasks"} deleted`, + }; + } + case BATCH_ARCHIVE_SCHEDULED_TASKS_SUCCESS: { const n = action.payload.archived_keys.length; return { @@ -135,6 +171,18 @@ function snackbarReducer( }; } + case ARCHIVE_ALL_PENDING_TASKS_SUCCESS: + return { + isOpen: true, + message: "All pending tasks are now archived", + }; + + case DELETE_ALL_PENDING_TASKS_SUCCESS: + return { + isOpen: true, + message: "All pending tasks deleted", + }; + case RUN_ALL_SCHEDULED_TASKS_SUCCESS: return { isOpen: true, diff --git a/ui/src/reducers/tasksReducer.ts b/ui/src/reducers/tasksReducer.ts index cf8e998..78a7e8a 100644 --- a/ui/src/reducers/tasksReducer.ts +++ b/ui/src/reducers/tasksReducer.ts @@ -96,6 +96,24 @@ import { CANCEL_ALL_ACTIVE_TASKS_BEGIN, CANCEL_ALL_ACTIVE_TASKS_SUCCESS, CANCEL_ALL_ACTIVE_TASKS_ERROR, + ARCHIVE_PENDING_TASK_BEGIN, + DELETE_PENDING_TASK_BEGIN, + ARCHIVE_PENDING_TASK_SUCCESS, + DELETE_PENDING_TASK_SUCCESS, + ARCHIVE_PENDING_TASK_ERROR, + DELETE_PENDING_TASK_ERROR, + ARCHIVE_ALL_PENDING_TASKS_BEGIN, + DELETE_ALL_PENDING_TASKS_BEGIN, + ARCHIVE_ALL_PENDING_TASKS_SUCCESS, + DELETE_ALL_PENDING_TASKS_SUCCESS, + ARCHIVE_ALL_PENDING_TASKS_ERROR, + DELETE_ALL_PENDING_TASKS_ERROR, + BATCH_ARCHIVE_PENDING_TASKS_BEGIN, + BATCH_DELETE_PENDING_TASKS_BEGIN, + BATCH_ARCHIVE_PENDING_TASKS_SUCCESS, + BATCH_DELETE_PENDING_TASKS_SUCCESS, + BATCH_ARCHIVE_PENDING_TASKS_ERROR, + BATCH_DELETE_PENDING_TASKS_ERROR, } from "../actions/tasksActions"; import { ActiveTask, @@ -143,6 +161,8 @@ interface TasksState { }; pendingTasks: { loading: boolean; + batchActionPending: boolean; + allActionPending: boolean; error: string; data: PendingTask[]; }; @@ -179,6 +199,8 @@ const initialState: TasksState = { }, pendingTasks: { loading: false, + batchActionPending: false, + allActionPending: false, error: "", data: [], }, @@ -259,6 +281,7 @@ function tasksReducer( return { ...state, pendingTasks: { + ...state.pendingTasks, loading: false, error: "", data: action.payload.tasks, @@ -521,6 +544,145 @@ function tasksReducer( }; } + case ARCHIVE_PENDING_TASK_BEGIN: + case DELETE_PENDING_TASK_BEGIN: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + data: state.pendingTasks.data.map((task) => { + if (task.key !== action.taskKey) { + return task; + } + return { ...task, requestPending: true }; + }), + }, + }; + + case ARCHIVE_PENDING_TASK_SUCCESS: + case DELETE_PENDING_TASK_SUCCESS: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + data: state.pendingTasks.data.filter( + (task) => task.key !== action.taskKey + ), + }, + }; + + case ARCHIVE_PENDING_TASK_ERROR: + case DELETE_PENDING_TASK_ERROR: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + data: state.pendingTasks.data.map((task) => { + if (task.key !== action.taskKey) { + return task; + } + return { ...task, requestPending: false }; + }), + }, + }; + + case ARCHIVE_ALL_PENDING_TASKS_BEGIN: + case DELETE_ALL_PENDING_TASKS_BEGIN: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + allActionPending: true, + }, + }; + + case ARCHIVE_ALL_PENDING_TASKS_SUCCESS: + case DELETE_ALL_PENDING_TASKS_SUCCESS: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + allActionPending: false, + data: [], + }, + }; + + case ARCHIVE_ALL_PENDING_TASKS_ERROR: + case DELETE_ALL_PENDING_TASKS_ERROR: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + allActionPending: false, + }, + }; + + case BATCH_ARCHIVE_PENDING_TASKS_BEGIN: + case BATCH_DELETE_PENDING_TASKS_BEGIN: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + batchActionPending: true, + data: state.pendingTasks.data.map((task) => { + if (!action.taskKeys.includes(task.key)) { + return task; + } + return { + ...task, + requestPending: true, + }; + }), + }, + }; + + case BATCH_ARCHIVE_PENDING_TASKS_SUCCESS: { + const newData = state.pendingTasks.data.filter( + (task) => !action.payload.archived_keys.includes(task.key) + ); + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + batchActionPending: false, + data: newData, + }, + }; + } + + case BATCH_DELETE_PENDING_TASKS_SUCCESS: { + const newData = state.pendingTasks.data.filter( + (task) => !action.payload.deleted_keys.includes(task.key) + ); + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + batchActionPending: false, + data: newData, + }, + }; + } + + case BATCH_ARCHIVE_PENDING_TASKS_ERROR: + case BATCH_DELETE_PENDING_TASKS_ERROR: + return { + ...state, + pendingTasks: { + ...state.pendingTasks, + batchActionPending: false, + data: state.pendingTasks.data.map((task) => { + if (!action.taskKeys.includes(task.key)) { + return task; + } + return { + ...task, + requestPending: false, + }; + }), + }, + }; + case RUN_SCHEDULED_TASK_BEGIN: case ARCHIVE_SCHEDULED_TASK_BEGIN: case DELETE_SCHEDULED_TASK_BEGIN: