Skip to content

Commit

Permalink
Add metrics pulldown to compare view
Browse files Browse the repository at this point in the history
Support selection of multiple metrics using the pulldown in the comparison
page. The update occurs when the pulldown closes.

To simplify the management of "available metrics" across multiple selected
runs, which might have entirely different metrics, the reducer no longer
tries to store separate metric selection lists for each run. This also means
that the "default" metrics selection remains when adding another comparison
run, or expanding another row.
  • Loading branch information
dbutenhof committed Nov 14, 2024
1 parent ea19d5a commit ac58188
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 187 deletions.
292 changes: 154 additions & 138 deletions frontend/src/actions/ilabActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,18 +78,22 @@ export const setIlabDateFilter =
appendQueryString({ ...appliedFilters, start_date, end_date }, navigate);
};

export const fetchMetricsInfo = (uid) => async (dispatch) => {
export const fetchMetricsInfo = (uid) => async (dispatch, getState) => {
try {
if (getState().ilab.metrics?.find((i) => i.uid == uid)) {
return;
}
dispatch({ type: TYPES.LOADING });
const response = await API.get(`/api/v1/ilab/runs/${uid}/metrics`);
if (response.status === 200) {
if (
response.data.constructor === Object &&
Object.keys(response.data).length > 0
) {
const metrics = Object.keys(response.data).sort();
dispatch({
type: TYPES.SET_ILAB_METRICS,
payload: { uid, metrics: Object.keys(response.data).sort() },
payload: { uid, metrics },
});
}
}
Expand All @@ -100,8 +104,11 @@ export const fetchMetricsInfo = (uid) => async (dispatch) => {
dispatch({ type: TYPES.COMPLETED });
};

export const fetchPeriods = (uid) => async (dispatch) => {
export const fetchPeriods = (uid) => async (dispatch, getState) => {
try {
if (getState().ilab.periods?.find((i) => i.uid == uid)) {
return;
}
dispatch({ type: TYPES.LOADING });
const response = await API.get(`/api/v1/ilab/runs/${uid}/periods`);
if (response.status === 200) {
Expand All @@ -121,146 +128,147 @@ export const fetchPeriods = (uid) => async (dispatch) => {
dispatch({ type: TYPES.COMPLETED });
};

export const fetchSummaryData =
(uid, metric = null) =>
async (dispatch, getState) => {
try {
const periods = getState().ilab.periods.find((i) => i.uid == uid);
const metrics = getState().ilab.metrics_selected[uid];
dispatch({ type: TYPES.SET_ILAB_SUMMARY_LOADING });
let summaries = [];
periods?.periods?.forEach((p) => {
if (p.is_primary) {
summaries.push({
run: uid,
metric: p.primary_metric,
periods: [p.id],
});
}
if (metrics) {
metrics.forEach((metric) =>
export const fetchSummaryData = (uid) => async (dispatch, getState) => {
try {
const periods = getState().ilab.periods.find((i) => i.uid == uid);
const metrics = getState().ilab.metrics_selected;
const avail_metrics = getState().ilab.metrics;
dispatch({ type: TYPES.SET_ILAB_SUMMARY_LOADING });
let summaries = [];
periods?.periods?.forEach((p) => {
if (p.is_primary) {
summaries.push({
run: uid,
metric: p.primary_metric,
periods: [p.id],
});
}
if (metrics) {
metrics.forEach((metric) => {
if (
avail_metrics.find((m) => m.uid == uid)?.metrics?.includes(metric)
) {
summaries.push({
run: uid,
metric,
aggregate: true,
periods: [p.id],
})
);
}
});
const response = await API.post(
`/api/v1/ilab/runs/multisummary`,
summaries
);
if (response.status === 200) {
dispatch({
type: TYPES.SET_ILAB_SUMMARY_DATA,
payload: { uid, data: response.data },
});
}
});
}
} catch (error) {
console.error(
`ERROR (${error?.response?.status}): ${JSON.stringify(
error?.response?.data
)}`
);
dispatch(showFailureToast());
}
dispatch({ type: TYPES.SET_ILAB_SUMMARY_COMPLETE });
};

export const handleSummaryData =
(uids, metric = null) =>
async (dispatch, getState) => {
try {
const periods = getState().ilab.periods;
const pUids = periods.map((i) => i.uid);
const missingPeriods = uids.filter(function (x) {
return pUids.indexOf(x) < 0;
});
const response = await API.post(
`/api/v1/ilab/runs/multisummary`,
summaries
);
if (response.status === 200) {
dispatch({
type: TYPES.SET_ILAB_SUMMARY_DATA,
payload: { uid, data: response.data },
});
console.log(`Missing periods for ${missingPeriods}`);
await Promise.all(
missingPeriods.map(async (uid) => {
console.log(`Fetching periods for ${uid}`);
await dispatch(fetchPeriods(uid)); // Dispatch each item
})
);
await Promise.all(
uids.map(async (uid) => {
console.log(`Fetching summary data for ${uid}`);
await dispatch(fetchSummaryData(uid, metric));
})
);
} catch (error) {
console.error(`ERROR: ${JSON.stringify(error)}`);
dispatch(showFailureToast());
}
};
} catch (error) {
console.error(
`ERROR (${error?.response?.status}): ${JSON.stringify(
error?.response?.data
)}`
);
dispatch(showFailureToast());
}
dispatch({ type: TYPES.SET_ILAB_SUMMARY_COMPLETE });
};

export const fetchGraphData =
(uid, metric = null) =>
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);
const metrics = getState().ilab.metrics_selected[uid];
dispatch({
type: TYPES.SET_ILAB_GRAPH_DATA,
payload: filterData,
});
const copyData = cloneDeep(filterData);
dispatch({ type: TYPES.GRAPH_LOADING });
let graphs = [];
periods?.periods?.forEach((p) => {
if (p.is_primary) {
graphs.push({ run: uid, metric: p.primary_metric, periods: [p.id] });
}
if (metrics) {
metrics.forEach((metric) =>
export const handleSummaryData = (uids) => async (dispatch, getState) => {
try {
const periods = getState().ilab.periods;
const pUids = periods.map((i) => i.uid);
const missingPeriods = uids.filter(function (x) {
return pUids.indexOf(x) < 0;
});
await Promise.all(
missingPeriods.map(async (uid) => {
await dispatch(fetchPeriods(uid)); // Dispatch each item
})
);
await Promise.all(
uids.map(async (uid) => {
await dispatch(fetchSummaryData(uid));
})
);
} catch (error) {
console.error(`ERROR: ${JSON.stringify(error)}`);
dispatch(showFailureToast());
}
};

export const fetchGraphData = (uid) => 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);
const metrics = getState().ilab.metrics_selected;
const avail_metrics = getState().ilab.metrics;
dispatch({
type: TYPES.SET_ILAB_GRAPH_DATA,
payload: filterData,
});
const copyData = cloneDeep(filterData);
dispatch({ type: TYPES.GRAPH_LOADING });
let graphs = [];
periods?.periods?.forEach((p) => {
if (p.is_primary) {
graphs.push({ run: uid, metric: p.primary_metric, periods: [p.id] });
}
if (metrics) {
metrics.forEach((metric) => {
if (
avail_metrics.find((m) => m.uid == uid)?.metrics?.includes(metric)
) {
graphs.push({
run: uid,
metric,
aggregate: true,
periods: [p.id],
})
);
}
});
const response = await API.post(`/api/v1/ilab/runs/multigraph`, {
name: `graph ${uid}`,
graphs,
});
if (response.status === 200) {
response.data.layout["showlegend"] = true;
response.data.layout["responsive"] = "true";
response.data.layout["autosize"] = "true";
response.data.layout["legend"] = {
orientation: "h",
xanchor: "left",
yanchor: "top",
y: -0.1,
};
copyData.push({
uid,
data: response.data.data,
layout: response.data.layout,
});
dispatch({
type: TYPES.SET_ILAB_GRAPH_DATA,
payload: copyData,
});
}
});
}
} catch (error) {
console.error(
`ERROR (${error?.response?.status}): ${JSON.stringify(
error?.response?.data
)}`
);
dispatch(showFailureToast());
});
const response = await API.post(`/api/v1/ilab/runs/multigraph`, {
name: `graph ${uid}`,
graphs,
});
if (response.status === 200) {
response.data.layout["showlegend"] = true;
response.data.layout["responsive"] = "true";
response.data.layout["autosize"] = "true";
response.data.layout["legend"] = {
orientation: "h",
xanchor: "left",
yanchor: "top",
y: -0.1,
};
copyData.push({
uid,
data: response.data.data,
layout: response.data.layout,
});
dispatch({
type: TYPES.SET_ILAB_GRAPH_DATA,
payload: copyData,
});
}
dispatch({ type: TYPES.GRAPH_COMPLETED });
};
} catch (error) {
console.error(
`ERROR (${error?.response?.status}): ${JSON.stringify(
error?.response?.data
)}`
);
dispatch(showFailureToast());
}
dispatch({ type: TYPES.GRAPH_COMPLETED });
};

export const handleMultiGraph = (uids) => async (dispatch, getState) => {
try {
Expand Down Expand Up @@ -292,6 +300,8 @@ export const fetchMultiGraphData = (uids) => async (dispatch, getState) => {
dispatch({ type: TYPES.LOADING });
const periods = getState().ilab.periods;
const filterPeriods = periods.filter((item) => uids.includes(item.uid));
const get_metrics = getState().ilab.metrics_selected;
const avail_metrics = getState().ilab.metrics;

let graphs = [];
uids.forEach(async (uid) => {
Expand All @@ -304,12 +314,20 @@ export const fetchMultiGraphData = (uids) => async (dispatch, getState) => {
periods: [p.id],
});
}
// graphs.push({
// run: uid,
// metric,
// aggregate: true,
// periods: [p.id],
// });
if (get_metrics) {
get_metrics.forEach((metric) => {
if (
avail_metrics.find((m) => m.uid == uid)?.metrics?.includes(metric)
) {
graphs.push({
run: uid,
metric,
aggregate: true,
periods: [p.id],
});
}
});
}
});
});
console.log(graphs);
Expand Down Expand Up @@ -374,15 +392,13 @@ export const checkIlabJobs = (newPage) => (dispatch, getState) => {
}
};

export const toggleSelectedMetric = (id, metric) => (dispatch, getState) => {
const metrics_selected = cloneDeep(getState().ilab.metrics_selected);
var new_selected = metrics_selected[id] ? metrics_selected[id] : [];
if (new_selected.includes(metric)) {
new_selected = new_selected.filter((m) => m !== metric);
export const toggleSelectedMetric = (metric) => (dispatch, getState) => {
let metrics_selected = getState().ilab.metrics_selected;
if (metrics_selected.includes(metric)) {
metrics_selected = metrics_selected.filter((m) => m !== metric);
} else {
new_selected = [...new_selected, metric];
metrics_selected = [...metrics_selected, metric];
}
metrics_selected[id] = new_selected;
dispatch({
type: TYPES.SET_ILAB_SELECTED_METRICS,
payload: metrics_selected,
Expand Down
Loading

0 comments on commit ac58188

Please sign in to comment.