Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow selecting multiple metrics on compare page #133

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the case for when it already has the data synced? If so I would just add a simple comment like this:

     return; // already fetched

This also applies to the other instances of this.

}
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 },
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can some basic comments be included to differentiate these two? Looking closely I can see that the bottom one is aggregate.

});
}
} 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
Loading