diff --git a/backend/app/services/crucible_svc.py b/backend/app/services/crucible_svc.py index a756d0e4..1edb76f7 100644 --- a/backend/app/services/crucible_svc.py +++ b/backend/app/services/crucible_svc.py @@ -716,7 +716,7 @@ def _get_metric_ids( response["names"] = {n: sorted(v) for n, v in names.items() if v and len(v) > 1} response["periods"] = list(periods) raise HTTPException( - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=[response] + status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=response ) def _build_timestamp_range_filters( diff --git a/frontend/src/actions/ilabActions.js b/frontend/src/actions/ilabActions.js index e80ac651..45275bbc 100644 --- a/frontend/src/actions/ilabActions.js +++ b/frontend/src/actions/ilabActions.js @@ -89,9 +89,27 @@ export const fetchMetricsInfo = (uid) => async (dispatch) => { dispatch({ type: TYPES.COMPLETED }); }; +export const fetchPeriods = (uid) => async (dispatch) => { + try { + dispatch({ type: TYPES.LOADING }); + const response = await API.get(`/api/v1/ilab/runs/${uid}/periods`); + if (response.status === 200) { + dispatch({ + type: TYPES.SET_ILAB_PERIODS, + payload: { uid, periods: response.data }, + }); + } + } catch (error) { + console.error(error); + dispatch(showFailureToast(error?.response?.data?.detail)); + } + dispatch({ type: TYPES.COMPLETED }); +}; + export const fetchGraphData = (uid, metric, primary_metric) => async (dispatch, getState) => { try { + const periods = getState().ilab.periods.find((i) => i.uid == uid); const graphData = cloneDeep(getState().ilab.graphData); const filterData = graphData.filter((i) => i.uid !== uid); dispatch({ @@ -100,9 +118,8 @@ export const fetchGraphData = }); const copyData = cloneDeep(filterData); dispatch({ type: TYPES.GRAPH_LOADING }); - const periods = await API.get(`/api/v1/ilab/runs/${uid}/periods`); let graphs = []; - periods.data.forEach((p) => { + periods?.periods?.forEach((p) => { graphs.push({ metric: p.primary_metric, periods: [p.id] }); graphs.push({ metric, @@ -127,8 +144,16 @@ export const fetchGraphData = }); } } catch (error) { - console.error(error); - dispatch(showToast("danger", "Graph error", error.data)); + var detail = error?.response?.data?.detail; + var str; + if (typeof detail == "string") { + str = detail; + } else if (typeof detail == "object" && typeof detail?.message == "string") { + str = detail.message; + } else { + str = JSON.stringify(detail); + } + dispatch(showFailureToast(str)); } dispatch({ type: TYPES.GRAPH_COMPLETED }); }; @@ -161,11 +186,6 @@ export const checkIlabJobs = (newPage) => (dispatch, getState) => { export const setSelectedMetrics = (id, metrics) => (dispatch, getState) => { const metrics_selected = cloneDeep(getState().ilab.metrics_selected); - // if (id in metrics_selected) { - // metrics_selected[id] = metrics; - // } else { - // metrics_selected[id] = metrics; - // } metrics_selected[id] = metrics; dispatch({ type: TYPES.SET_ILAB_SELECTED_METRICS, diff --git a/frontend/src/actions/toastActions.js b/frontend/src/actions/toastActions.js index 574487f1..a0fddabc 100644 --- a/frontend/src/actions/toastActions.js +++ b/frontend/src/actions/toastActions.js @@ -2,11 +2,11 @@ import * as TYPES from "./types"; import { uid } from "@/utils/helper"; -export const showFailureToast = () => async (dispatch) => { +export const showFailureToast = (message = null) => async (dispatch) => { const toast = { variant: "danger", title: "Something went wrong", - message: "Please try again later", + message: message ? message : "Please try again later", }; dispatch(showToast(toast.variant, toast.title, toast.message)); }; diff --git a/frontend/src/actions/types.js b/frontend/src/actions/types.js index e4739422..b4137839 100644 --- a/frontend/src/actions/types.js +++ b/frontend/src/actions/types.js @@ -87,3 +87,4 @@ export const SET_ILAB_PAGE = "SET_ILAB_PAGE"; export const SET_ILAB_PAGE_OPTIONS = "SET_ILAB_PAGE_OPTIONS"; export const SET_ILAB_METRICS = "SET_ILAB_METRICS"; export const SET_ILAB_SELECTED_METRICS = "SET_ILAB_SELECTED_METRICS"; +export const SET_ILAB_PERIODS = "SET_ILAB_PERIODS"; diff --git a/frontend/src/components/templates/ILab/index.jsx b/frontend/src/components/templates/ILab/index.jsx index 7a836563..8085c5f5 100644 --- a/frontend/src/components/templates/ILab/index.jsx +++ b/frontend/src/components/templates/ILab/index.jsx @@ -17,7 +17,7 @@ import { Thead, Tr, } from "@patternfly/react-table"; -import { fetchILabJobs, fetchMetricsInfo } from "@/actions/ilabActions"; +import { fetchILabJobs, fetchMetricsInfo, fetchPeriods } from "@/actions/ilabActions"; import { formatDateTime, uid } from "@/utils/helper"; import { useDispatch, useSelector } from "react-redux"; import { useEffect, useState } from "react"; @@ -58,6 +58,7 @@ const ILab = () => { : otherExpandedRunNames; }); if (isExpanding) { + dispatch(fetchPeriods(run.id)); dispatch(fetchMetricsInfo(run.id)); // dispatch(fetchGraphData(run.id, run?.primary_metrics[0])); } diff --git a/frontend/src/reducers/ilabReducer.js b/frontend/src/reducers/ilabReducer.js index a4e5ec50..1ceaea40 100644 --- a/frontend/src/reducers/ilabReducer.js +++ b/frontend/src/reducers/ilabReducer.js @@ -11,6 +11,7 @@ const initialState = { size: 10, offset: 1, metrics: [], + periods: [], metrics_selected: {}, }; const ILabReducer = (state = initialState, action = {}) => { @@ -40,6 +41,8 @@ const ILabReducer = (state = initialState, action = {}) => { return { ...state, page: payload.page, perPage: payload.perPage }; case TYPES.SET_ILAB_METRICS: return { ...state, metrics: [...state.metrics, payload] }; + case TYPES.SET_ILAB_PERIODS: + return { ...state, periods: [...state.periods, payload] }; case TYPES.SET_ILAB_SELECTED_METRICS: return { ...state,