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

Add support for multi-run graphing in ilab / Crucible backend #120

Closed
wants to merge 29 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4094cc9
Add ILAB / Crucible support to CPT backend
dbutenhof Aug 21, 2024
e6c8ee0
UI code updates
MVarshini Sep 23, 2024
5e735a7
Improve periodic graph names.
dbutenhof Sep 23, 2024
505903b
Documentation and cleanup
dbutenhof Sep 30, 2024
4ccd603
Allow overriding graph color
dbutenhof Oct 1, 2024
de0accc
Some (self) review cleanup
dbutenhof Oct 3, 2024
ad48906
Move periods query to action/reducer
dbutenhof Oct 3, 2024
5671d77
Cleanup OpenSearch connections
dbutenhof Oct 4, 2024
a49fc65
Try to remove a couple of incidental changes
dbutenhof Oct 7, 2024
1d5783d
Undoing a few more ancillary changes
dbutenhof Oct 7, 2024
f20e45d
Review feedback
dbutenhof Oct 9, 2024
a959fe6
Pagination and Date filter issue
MVarshini Oct 10, 2024
79151ea
Rewrite param consolidation
dbutenhof Oct 10, 2024
8b75d5f
Add framework for UI multi-run comparison
dbutenhof Oct 9, 2024
c8cd597
Some UI cleanup
dbutenhof Oct 10, 2024
3b0b190
Debug unhandled exceptions
dbutenhof Oct 11, 2024
b32a606
Fix multigraph bug
dbutenhof Oct 11, 2024
2148311
Support for per-iteration parameters.
dbutenhof Oct 11, 2024
312eebf
comparison
MVarshini Oct 11, 2024
0d7592a
render graph
MVarshini Oct 15, 2024
e056d62
Pagination for Graphs
MVarshini Oct 15, 2024
659d820
Support relative timescale graphs
dbutenhof Oct 15, 2024
e25b82e
pagination data
MVarshini Oct 15, 2024
993a4fe
Multi run comparison adjustments
dbutenhof Oct 17, 2024
de38738
A few tweaks
dbutenhof Oct 17, 2024
25fe58f
closing of graph accordion
MVarshini Oct 18, 2024
eed488f
Adjustments
dbutenhof Oct 18, 2024
606f468
conflict resolve
MVarshini Oct 18, 2024
e755221
multiple APIs to fetch periods and icon to display more info
MVarshini Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
comparison
  • Loading branch information
MVarshini committed Oct 15, 2024
commit 312eebf4a85e5d43a73a8fb9b1c5612f42255d7a
114 changes: 61 additions & 53 deletions frontend/src/actions/ilabActions.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as API_ROUTES from "@/utils/apiConstants";
import * as TYPES from "./types.js";

import { cloneDeep, isEqual } from "lodash";

import API from "@/utils/axiosInstance";
import { appendQueryString } from "@/utils/helper";
import { cloneDeep } from "lodash";
import { showFailureToast } from "@/actions/toastActions";

export const fetchILabJobs =
@@ -122,7 +123,8 @@ export const fetchPeriods = (uid) => async (dispatch) => {
};

export const fetchGraphData =
(uid, metric = null) => async (dispatch, getState) => {
(uid, metric = null) =>
async (dispatch, getState) => {
try {
const periods = getState().ilab.periods.find((i) => i.uid == uid);
const graphData = cloneDeep(getState().ilab.graphData);
@@ -171,61 +173,64 @@ export const fetchGraphData =
dispatch({ type: TYPES.GRAPH_COMPLETED });
};

export const fetchMultiGraphData =
(uids, metric = null) => async (dispatch, getState) => {
try {
const graphData = cloneDeep(getState().ilab.multiGraphData);
const filterData = graphData.filter((i) => !isEqual(i.uids, uids));
dispatch({
type: TYPES.SET_ILAB_MULTIGRAPH_DATA,
payload: filterData,
});
const copyData = cloneDeep(filterData);
dispatch({ type: TYPES.GRAPH_LOADING });
uids.forEach((uid) => {
const periods = getState().ilab.periods.find((i) => i.uid == uid);
let graphs = [];
periods?.periods?.forEach((p) => {
graphs.push({
run: uid,
metric: p.primary_metric,
periods: [p.id],
});
if (metric) {
graphs.push({
run: uid,
metric,
aggregate: true,
periods: [p.id],
});
}
export const fetchMultiGraphData = (uids) => async (dispatch, getState) => {
try {
const graphData = cloneDeep(getState().ilab.multiGraphData);
const filterData = graphData.filter((i) => !isEqual(i.uids, uids));
dispatch({
type: TYPES.SET_ILAB_MULTIGRAPH_DATA,
payload: filterData,
});
const copyData = cloneDeep(filterData);
dispatch({ type: TYPES.GRAPH_LOADING });

let graphs = [];
uids.forEach(async (uid) => {
// if (!periods) {
await dispatch(fetchPeriods(uid));
//}

const periods = getState().ilab.periods.find((i) => i.uid == uid);
periods?.periods?.forEach((p) => {
graphs.push({
run: uid,
metric: p.primary_metric,
periods: [p.id],
});
// graphs.push({
// run: uid,
// metric,
// aggregate: true,
// periods: [p.id],
// });
});
const response = await API.post(`/api/v1/ilab/runs/multigraph`, {
name: "comparison",
graphs,
});
console.log(graphs);
const response = await API.post(`/api/v1/ilab/runs/multigraph`, {
name: "comparison",
graphs,
});
if (response.status === 200) {
copyData.push({
uids,
data: response.data.data,
layout: response.data.layout,
});
dispatch({
type: TYPES.SET_ILAB_MULTIGRAPH_DATA,
payload: copyData,
});
if (response.status === 200) {
copyData.push({
uids,
data: response.data.data,
layout: response.data.layout,
});
dispatch({
type: TYPES.SET_ILAB_MULTIGRAPH_DATA,
payload: copyData,
});
}
} catch (error) {
console.error(
`ERROR (${error?.response?.status}): ${JSON.stringify(
error?.response?.data
)}`
);
dispatch(showFailureToast());
}
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 setIlabPage = (pageNo) => ({
type: TYPES.SET_ILAB_PAGE,
@@ -269,3 +274,6 @@ export const tableReCalcValues = () => (dispatch, getState) => {
const endIdx = page !== 1 ? page * perPage - 1 : perPage;
dispatch(sliceIlabTableRows(startIdx, endIdx));
};
export const toggleComparisonSwitch = () => ({
type: TYPES.TOGGLE_COMPARISON_SWITCH,
});
1 change: 1 addition & 0 deletions frontend/src/actions/types.js
Original file line number Diff line number Diff line change
@@ -90,3 +90,4 @@ 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";
export const SET_ILAB_INIT_JOBS = "SET_ILAB_INIT_JOBS";
export const TOGGLE_COMPARISON_SWITCH = "TOGGLE_COMPARISON_SWITCH";
17 changes: 17 additions & 0 deletions frontend/src/components/organisms/TableFilters/index.jsx
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import "./index.less";
import {
Chip,
ChipGroup,
Switch,
Toolbar,
ToolbarContent,
ToolbarItem,
@@ -39,6 +40,8 @@ const TableFilter = (props) => {
setColumns,
selectedFilters,
updateSelectedFilter,
onSwitchChange,
isSwitchChecked,
} = props;

const category =
@@ -123,6 +126,18 @@ const TableFilter = (props) => {
</ToolbarItem>
)}
</ToolbarContent>
{type === "ilab" && (
<ToolbarContent id="comparison-switch">
<ToolbarItem>
<Switch
label="Comparison"
isChecked={isSwitchChecked}
onChange={onSwitchChange}
ouiaId="Comparsion Switch"
/>
</ToolbarItem>
</ToolbarContent>
)}
</Toolbar>
{appliedFilters &&
Object.keys(appliedFilters).length > 0 &&
@@ -154,5 +169,7 @@ TableFilter.propTypes = {
selectedFilters: PropTypes.array,
updateSelectedFilter: PropTypes.func,
navigation: PropTypes.func,
isSwitchChecked: PropTypes.bool,
onSwitchChange: PropTypes.func,
};
export default TableFilter;
4 changes: 4 additions & 0 deletions frontend/src/components/organisms/TableFilters/index.less
Original file line number Diff line number Diff line change
@@ -11,4 +11,8 @@
.to-text {
padding: 5px 0;
}
#comparison-switch {
margin-left: auto;
align-content: center;
}
}
86 changes: 86 additions & 0 deletions frontend/src/components/templates/ILab/IlabCompareComponent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
Button,
Menu,
MenuContent,
MenuItem,
MenuList,
Title,
} from "@patternfly/react-core";

import PropTypes from "prop-types";
import { fetchMultiGraphData } from "@/actions/ilabActions.js";
import { uid } from "@/utils/helper";
import { useDispatch } from "react-redux";
import { useState } from "react";

const IlabCompareComponent = (props) => {
const { data } = props;

const dispatch = useDispatch();
const [selectedItems, setSelectedItems] = useState([]);
const onSelect = (_event, itemId) => {
const item = itemId;
if (selectedItems.includes(item)) {
setSelectedItems(selectedItems.filter((id) => id !== item));
} else {
setSelectedItems([...selectedItems, item]);
}
};
return (
<div className="comparison-container">
<div className="metrics-container">
<Title headingLevel="h3" className="title">
Metrics
</Title>
<Button
className="compare-btn"
isDisabled={selectedItems.length < 2}
isBlock
onClick={() => dispatch(fetchMultiGraphData(selectedItems))}
>
Comapre
</Button>
{/* <List isPlain isBordered>
{data.map((item) => {
return (
// <ListItem ></ListItem>
<Checkbox
key={uid()}
isLabelWrapped
label={item.primary_metrics[0]}
/>
);
})}

</List> */}
<Menu onSelect={onSelect} selected={selectedItems}>
<MenuContent>
<MenuList>
{data.map((item) => {
return (
<MenuItem
key={uid()}
hasCheckbox
itemId={item.id}
isSelected={selectedItems.includes(item.id)}
>
{item.primary_metrics[0]}
</MenuItem>
);
})}
</MenuList>
</MenuContent>
</Menu>
</div>

<Title headingLevel="h3" className="title">
Chart
</Title>
</div>
);
};

IlabCompareComponent.propTypes = {
data: PropTypes.array,
};
export default IlabCompareComponent;
Loading