diff --git a/ui/src/actions/schedulerEntriesActions.ts b/ui/src/actions/schedulerEntriesActions.ts index cfe4e1d..4df0132 100644 --- a/ui/src/actions/schedulerEntriesActions.ts +++ b/ui/src/actions/schedulerEntriesActions.ts @@ -1,10 +1,21 @@ import { Dispatch } from "@reduxjs/toolkit"; -import { listSchedulerEntries, ListSchedulerEntriesResponse } from "../api"; +import { + listSchedulerEnqueueEvents, + ListSchedulerEnqueueEventsResponse, + listSchedulerEntries, + ListSchedulerEntriesResponse, +} from "../api"; // List of scheduler-entry related action types. export const LIST_SCHEDULER_ENTRIES_BEGIN = "LIST_SCHEDULER_ENTRIES_BEGIN"; export const LIST_SCHEDULER_ENTRIES_SUCCESS = "LIST_SCHEDULER_ENTRIES_SUCCESS"; export const LIST_SCHEDULER_ENTRIES_ERROR = "LIST_SCHEDULER_ENTRIES_ERROR"; +export const LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN = + "LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN"; +export const LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS = + "LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS"; +export const LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR = + "LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR"; interface ListSchedulerEntriesBeginAction { type: typeof LIST_SCHEDULER_ENTRIES_BEGIN; @@ -20,11 +31,31 @@ interface ListSchedulerEntriesErrorAction { error: string; // error description } +interface ListSchedulerEnqueueEventBeginAction { + type: typeof LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN; + entryId: string; +} + +interface ListSchedulerEnqueueEventSuccessAction { + type: typeof LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS; + entryId: string; + payload: ListSchedulerEnqueueEventsResponse; +} + +interface ListSchedulerEnqueueEventErrorAction { + type: typeof LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR; + entryId: string; + error: string; +} + // Union of all scheduler-entry related actions. export type SchedulerEntriesActionTypes = | ListSchedulerEntriesBeginAction | ListSchedulerEntriesSuccessAction - | ListSchedulerEntriesErrorAction; + | ListSchedulerEntriesErrorAction + | ListSchedulerEnqueueEventBeginAction + | ListSchedulerEnqueueEventSuccessAction + | ListSchedulerEnqueueEventErrorAction; export function listSchedulerEntriesAsync() { return async (dispatch: Dispatch) => { @@ -44,3 +75,24 @@ export function listSchedulerEntriesAsync() { } }; } + +export function listSchedulerEnqueueEventsAsync(entryId: string) { + return async (dispatch: Dispatch) => { + dispatch({ type: LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN, entryId }); + try { + const response = await listSchedulerEnqueueEvents(entryId); + dispatch({ + type: LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS, + payload: response, + entryId, + }); + } catch (error) { + console.error("listSchedulerEnqueueEventsAsync: ", error); + dispatch({ + type: LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR, + error: `Could not get enqueue events for entry: ${entryId}`, + entryId, + }); + } + }; +} diff --git a/ui/src/api.ts b/ui/src/api.ts index a57cb25..a65095f 100644 --- a/ui/src/api.ts +++ b/ui/src/api.ts @@ -41,6 +41,10 @@ export interface ListSchedulerEntriesResponse { entries: SchedulerEntry[]; } +export interface ListSchedulerEnqueueEventsResponse { + events: SchedulerEnqueueEvent[]; +} + export interface BatchCancelTasksResponse { canceled_ids: string[]; error_ids: string[]; @@ -136,6 +140,11 @@ export interface SchedulerEntry { prev_enqueue_at?: string; } +export interface SchedulerEnqueueEvent { + task_id: string; + enqueued_at: string; +} + export interface PaginationOptions extends Record { size?: number; // size of the page page?: number; // page number (1 being the first page) @@ -539,3 +548,13 @@ export async function listSchedulerEntries(): Promise { + const resp = await axios({ + method: "get", + url: `${BASE_URL}/scheduler_entries/${entryId}/enqueue_events`, + }); + return resp.data; +} diff --git a/ui/src/reducers/schedulerEntriesReducer.ts b/ui/src/reducers/schedulerEntriesReducer.ts index 7c907b8..7d8d299 100644 --- a/ui/src/reducers/schedulerEntriesReducer.ts +++ b/ui/src/reducers/schedulerEntriesReducer.ts @@ -1,21 +1,35 @@ import { + LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN, + LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR, + LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS, LIST_SCHEDULER_ENTRIES_BEGIN, LIST_SCHEDULER_ENTRIES_ERROR, LIST_SCHEDULER_ENTRIES_SUCCESS, SchedulerEntriesActionTypes, } from "../actions/schedulerEntriesActions"; -import { SchedulerEntry } from "../api"; +import { SchedulerEnqueueEvent, SchedulerEntry } from "../api"; interface SchedulerEntriesState { loading: boolean; data: SchedulerEntry[]; error: string; // error description + enqueueEventsByEntryId: { + [entryId: string]: { data: SchedulerEnqueueEvent[]; loading: boolean }; + }; +} + +function getEnqueueEventsEntry( + state: SchedulerEntriesState, + entryId: string +): { data: SchedulerEnqueueEvent[]; loading: boolean } { + return state.enqueueEventsByEntryId[entryId] || { data: [], loading: false }; } const initialState: SchedulerEntriesState = { loading: false, data: [], error: "", + enqueueEventsByEntryId: {}, }; function schedulerEntriesReducer( @@ -30,6 +44,7 @@ function schedulerEntriesReducer( }; case LIST_SCHEDULER_ENTRIES_SUCCESS: return { + ...state, error: "", loading: false, data: action.payload.entries, @@ -41,6 +56,45 @@ function schedulerEntriesReducer( loading: false, error: action.error, }; + case LIST_SCHEDULER_ENQUEUE_EVENTS_BEGIN: { + const entry = getEnqueueEventsEntry(state, action.entryId); + return { + ...state, + enqueueEventsByEntryId: { + ...state.enqueueEventsByEntryId, + [action.entryId]: { + ...entry, + loading: true, + }, + }, + }; + } + case LIST_SCHEDULER_ENQUEUE_EVENTS_SUCCESS: { + const entry = getEnqueueEventsEntry(state, action.entryId); + return { + ...state, + enqueueEventsByEntryId: { + ...state.enqueueEventsByEntryId, + [action.entryId]: { + loading: false, + data: [...entry.data, ...action.payload.events], + }, + }, + }; + } + case LIST_SCHEDULER_ENQUEUE_EVENTS_ERROR: { + const entry = getEnqueueEventsEntry(state, action.entryId); + return { + ...state, + enqueueEventsByEntryId: { + ...state.enqueueEventsByEntryId, + [action.entryId]: { + ...entry, + loading: false, + }, + }, + }; + } default: return state; }