From ec8bd9fb639ed1e8b72d724f96cbc0811d2a303f Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Mon, 2 Sep 2024 13:57:48 +0200 Subject: [PATCH 01/11] Added Graph calibration page with Cytoscape + small refactor --- frontend/package-lock.json | 7 + frontend/package.json | 1 + .../components/CalibrationGraphList.tsx | 28 ---- .../GraphLibrary.module.scss} | 0 .../api/GraphLibraryApi.tsx} | 11 +- .../CytoscapeGraph/CytoscapeGraph.module.scss | 0 .../CytoscapeGraph/CytoscapeGraph.tsx | 4 +- .../CytoscapeGraph/config/Cytoscape.ts | 0 .../GraphElement/GraphElement.module.scss} | 0 .../components/GraphElement/GraphElement.tsx} | 34 ++-- .../components/GraphElement/GraphSearch.tsx} | 4 +- .../GraphLibrary/components/GraphList.tsx | 28 ++++ .../GraphStatus/GraphStatus.module.scss | 49 ++++++ .../components/GraphStatus/GraphStatus.tsx | 46 +++++ .../MeasurementElement.module.scss | 60 +++++++ .../MeasurementElement/MeasurementElement.tsx | 58 +++++++ .../MeasurementElementGraph.module.scss | 61 +++++++ .../MeasurementElementGraph.tsx | 37 +++++ .../MeasurementElementList.module.scss | 3 + .../MeasurementElementList.tsx | 19 +++ .../MeasurementElementParameters.module.scss | 21 +++ .../MeasurementElementParameters.tsx | 93 +++++++++++ .../MeasurementHistory.module.scss | 36 ++++ .../MeasurementHistory/MeasurementHistory.tsx | 51 ++++++ .../context/GraphStatusContext.tsx | 157 ++++++++++++++++++ .../context/GraphContext.tsx} | 51 +++--- .../index.tsx | 20 +-- .../Nodes/components/Results/Results.tsx | 10 +- frontend/src/modules/common/ParameterList.tsx | 20 +-- frontend/src/modules/common/Parameters.tsx | 10 +- frontend/src/routing/ModulesRegistry.ts | 44 +++-- frontend/src/utils/api/apiRoutes.ts | 1 + 32 files changed, 846 insertions(+), 118 deletions(-) delete mode 100644 frontend/src/modules/CalibrationGraph/components/CalibrationGraphList.tsx rename frontend/src/modules/{CalibrationGraph/CalibrationGraph.module.scss => GraphLibrary/GraphLibrary.module.scss} (100%) rename frontend/src/modules/{CalibrationGraph/api/CalibrationsAPI.tsx => GraphLibrary/api/GraphLibraryApi.tsx} (68%) rename frontend/src/modules/{CalibrationGraph => GraphLibrary}/components/CytoscapeGraph/CytoscapeGraph.module.scss (100%) rename frontend/src/modules/{CalibrationGraph => GraphLibrary}/components/CytoscapeGraph/CytoscapeGraph.tsx (94%) rename frontend/src/modules/{CalibrationGraph => GraphLibrary}/components/CytoscapeGraph/config/Cytoscape.ts (100%) rename frontend/src/modules/{CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.module.scss => GraphLibrary/components/GraphElement/GraphElement.module.scss} (100%) rename frontend/src/modules/{CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.tsx => GraphLibrary/components/GraphElement/GraphElement.tsx} (79%) rename frontend/src/modules/{CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphSearch.tsx => GraphLibrary/components/GraphElement/GraphSearch.tsx} (78%) create mode 100644 frontend/src/modules/GraphLibrary/components/GraphList.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx create mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx rename frontend/src/modules/{CalibrationGraph/context/CalibrationGraphContext.tsx => GraphLibrary/context/GraphContext.tsx} (57%) rename frontend/src/modules/{CalibrationGraph => GraphLibrary}/index.tsx (52%) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6a8a5a33..eb94cd67 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -47,6 +47,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.14", + "@types/cytoscape": "^3.21.7", "@types/jsonpath": "^0.2.4", "@types/node": "^20.12.7", "@types/react": "^18.2.67", @@ -1302,6 +1303,12 @@ "@types/node": "*" } }, + "node_modules/@types/cytoscape": { + "version": "3.21.7", + "resolved": "https://registry.npmjs.org/@types/cytoscape/-/cytoscape-3.21.7.tgz", + "integrity": "sha512-dP4UByJtfu5GjMJuv58yCIRxjCp4cP0Wp+Qd46L3Gom0hcV4OPmSOLqt83vArNcYRZLFCAyAk+lcC8oqQtcsqw==", + "dev": true + }, "node_modules/@types/eslint": { "version": "8.56.10", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz", diff --git a/frontend/package.json b/frontend/package.json index fc9e7ce5..c63805d9 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -29,6 +29,7 @@ "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", "@mui/material": "^5.15.14", + "@types/cytoscape": "^3.21.7", "@types/jsonpath": "^0.2.4", "@types/node": "^20.12.7", "@types/react": "^18.2.67", diff --git a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphList.tsx b/frontend/src/modules/CalibrationGraph/components/CalibrationGraphList.tsx deleted file mode 100644 index 4618fccc..00000000 --- a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphList.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -// eslint-disable-next-line css-modules/no-unused-class -import styles from "../CalibrationGraph.module.scss"; -import { CalibrationGraphElement } from "./CalibrationGraphElement/CalibrationGraphElement"; -import { NodeMap } from "../../Nodes/components/NodeElement/NodeElement"; -import { useCalibrationGraphContext } from "../context/CalibrationGraphContext"; -import { InputParameter } from "../../common/Parameters"; - -export interface CalibrationGraphWorkflow { - name?: string; - title?: string; - description: string; - parameters?: InputParameter; - nodes?: NodeMap; - connectivity?: string[][]; -} - -export const CalibrationGraphList: React.FC = () => { - const { allCalibrationGraphs } = useCalibrationGraphContext(); - if (!allCalibrationGraphs || Object.entries(allCalibrationGraphs).length === 0) return
No calibration graphs
; - return ( -
- {Object.entries(allCalibrationGraphs ?? {}).map(([key, graph]) => { - return ; - })} -
- ); -}; diff --git a/frontend/src/modules/CalibrationGraph/CalibrationGraph.module.scss b/frontend/src/modules/GraphLibrary/GraphLibrary.module.scss similarity index 100% rename from frontend/src/modules/CalibrationGraph/CalibrationGraph.module.scss rename to frontend/src/modules/GraphLibrary/GraphLibrary.module.scss diff --git a/frontend/src/modules/CalibrationGraph/api/CalibrationsAPI.tsx b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx similarity index 68% rename from frontend/src/modules/CalibrationGraph/api/CalibrationsAPI.tsx rename to frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx index 0cc5721c..a054b3bf 100644 --- a/frontend/src/modules/CalibrationGraph/api/CalibrationsAPI.tsx +++ b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx @@ -1,9 +1,10 @@ import Api, { BASIC_HEADERS } from "../../../utils/api"; import { Res } from "../../../common/interfaces/Api"; -import { ALL_GRAPHS, GET_WORKFLOW_GRAPH, SUBMIT_WORKFLOW_RUN } from "../../../utils/api/apiRoutes"; +import { ALL_GRAPHS, GET_EXECUTION_HISTORY, GET_WORKFLOW_GRAPH, SUBMIT_WORKFLOW_RUN } from "../../../utils/api/apiRoutes"; import { API_METHODS } from "../../../common/enums/Api"; +import { Measurement } from "../components/GraphStatus/context/GraphStatusContext"; -export class CalibrationsApi extends Api { +export class GraphLibraryApi extends Api { constructor() { super(); } @@ -26,6 +27,12 @@ export class CalibrationsApi extends Api { }); } + static fetchExecutionHistory(): Promise> { + return this._fetch(this.api(GET_EXECUTION_HISTORY()), API_METHODS.GET, { + headers: BASIC_HEADERS, + }); + } + static submitWorkflow(name: string, workflow: unknown): Promise> { return this._fetch(this.api(SUBMIT_WORKFLOW_RUN()), API_METHODS.POST, { headers: BASIC_HEADERS, diff --git a/frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/CytoscapeGraph.module.scss b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss similarity index 100% rename from frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/CytoscapeGraph.module.scss rename to frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss diff --git a/frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/CytoscapeGraph.tsx b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.tsx similarity index 94% rename from frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/CytoscapeGraph.tsx rename to frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.tsx index 4bf05e1f..dc2e3756 100644 --- a/frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/CytoscapeGraph.tsx +++ b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.tsx @@ -3,7 +3,7 @@ import { useEffect, useRef } from "react"; import { CytoscapeLayout } from "./config/Cytoscape"; import styles from "./CytoscapeGraph.module.scss"; -import { useCalibrationGraphContext } from "../../context/CalibrationGraphContext"; +import { useGraphContext } from "../../context/GraphContext"; cytoscape.warnings(false); @@ -12,7 +12,7 @@ interface IProps { } export default function CytoscapeGraph({ elements }: IProps) { - const { setSelectedNodeNameInWorkflow } = useCalibrationGraphContext(); + const { setSelectedNodeNameInWorkflow } = useGraphContext(); const cy = useRef(); const divRef = useRef(null); diff --git a/frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/config/Cytoscape.ts b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/config/Cytoscape.ts similarity index 100% rename from frontend/src/modules/CalibrationGraph/components/CytoscapeGraph/config/Cytoscape.ts rename to frontend/src/modules/GraphLibrary/components/CytoscapeGraph/config/Cytoscape.ts diff --git a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.module.scss b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.module.scss similarity index 100% rename from frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.module.scss rename to frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.module.scss diff --git a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx similarity index 79% rename from frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.tsx rename to frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx index 00685999..a5a0d2ee 100644 --- a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx @@ -1,22 +1,23 @@ import React from "react"; // eslint-disable-next-line css-modules/no-unused-class -import styles from "../CalibrationGraphElement/CalibrationGraphElement.module.scss"; +import styles from "./GraphElement.module.scss"; import { PlayIcon } from "../../../../ui-lib/Icons/PlayIcon"; import { classNames } from "../../../../utils/classnames"; import { InputParameter, Parameters, SingleParameter } from "../../../common/Parameters"; -import { CalibrationGraphWorkflow } from "../CalibrationGraphList"; +import { GraphWorkflow } from "../GraphList"; import { useSelectionContext } from "../../../common/context/SelectionContext"; import { Checkbox } from "@mui/material"; import InputField from "../../../../DEPRECATED_components/common/Input/InputField"; import { ParameterList } from "../../../common/ParameterList"; -import { useCalibrationGraphContext } from "../../context/CalibrationGraphContext"; +import { useGraphContext } from "../../context/GraphContext"; import CytoscapeGraph from "../CytoscapeGraph/CytoscapeGraph"; -import { CalibrationsApi } from "../../api/CalibrationsAPI"; +import { GraphLibraryApi } from "../../api/GraphLibraryApi"; import { NodeDTO } from "../../../Nodes/components/NodeElement/NodeElement"; +import { useFlexLayoutContext } from "../../../../routing/flexLayout/FlexLayoutContext"; export interface ICalibrationGraphElementProps { calibrationGraphKey?: string; - calibrationGraph: CalibrationGraphWorkflow; + calibrationGraph: GraphWorkflow; } interface TransformedGraph { @@ -24,12 +25,12 @@ interface TransformedGraph { nodes: { [key: string]: { parameters: InputParameter } }; } -export const CalibrationGraphElement: React.FC = ({ calibrationGraphKey, calibrationGraph }) => { +export const GraphElement: React.FC = ({ calibrationGraphKey, calibrationGraph }) => { const { selectedItemName, setSelectedItemName } = useSelectionContext(); - const { workflowGraphElements, setSelectedWorkflowName, allCalibrationGraphs, setAllCalibrationGraphs, selectedWorkflowName } = - useCalibrationGraphContext(); + const { workflowGraphElements, setSelectedWorkflowName, allGraphs, setAllGraphs, selectedWorkflowName } = useGraphContext(); + const { openTab } = useFlexLayoutContext(); - const updateParameter = (paramKey: string, newValue: boolean | number | string, workflow?: NodeDTO | CalibrationGraphWorkflow) => { + const updateParameter = (paramKey: string, newValue: boolean | number | string, workflow?: NodeDTO | GraphWorkflow) => { const updatedParameters = { ...workflow?.parameters, [paramKey]: { @@ -38,21 +39,21 @@ export const CalibrationGraphElement: React.FC = }, }; - if (selectedWorkflowName && allCalibrationGraphs?.[selectedWorkflowName]) { + if (selectedWorkflowName && allGraphs?.[selectedWorkflowName]) { const updatedWorkflow = { - ...allCalibrationGraphs[selectedWorkflowName], + ...allGraphs[selectedWorkflowName], parameters: updatedParameters, }; const updatedCalibrationGraphs = { - ...allCalibrationGraphs, + ...allGraphs, [selectedWorkflowName]: updatedWorkflow, }; - setAllCalibrationGraphs(updatedCalibrationGraphs); + setAllGraphs(updatedCalibrationGraphs); } }; - const getInputElement = (key: string, parameter: SingleParameter, node?: NodeDTO | CalibrationGraphWorkflow) => { + const getInputElement = (key: string, parameter: SingleParameter, node?: NodeDTO | GraphWorkflow) => { switch (parameter.type) { case "boolean": return ( @@ -75,7 +76,7 @@ export const CalibrationGraphElement: React.FC = } }; const transformDataForSubmit = () => { - const input = allCalibrationGraphs?.[selectedWorkflowName ?? ""]; + const input = allGraphs?.[selectedWorkflowName ?? ""]; const workflowParameters = input?.parameters; const transformParameters = (params?: InputParameter) => { let transformedParams = {}; @@ -102,7 +103,8 @@ export const CalibrationGraphElement: React.FC = const handleSubmit = async () => { if (selectedWorkflowName) { - CalibrationsApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); + GraphLibraryApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); + openTab("graph-status"); } }; diff --git a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphSearch.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphSearch.tsx similarity index 78% rename from frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphSearch.tsx rename to frontend/src/modules/GraphLibrary/components/GraphElement/GraphSearch.tsx index 3a314ae5..cdd512e5 100644 --- a/frontend/src/modules/CalibrationGraph/components/CalibrationGraphElement/CalibrationGraphSearch.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphSearch.tsx @@ -1,11 +1,11 @@ import React from "react"; // eslint-disable-next-line css-modules/no-unused-class -import styles from "../CalibrationGraphElement/CalibrationGraphElement.module.scss"; +import styles from "./GraphElement.module.scss"; import InputField from "../../../../DEPRECATED_components/common/Input/InputField"; import { SearchIcon } from "../../../../ui-lib/Icons/SearchIcon"; import { IconType } from "../../../../common/interfaces/InputProps"; -export const CalibrationGraphSearch: React.FC = () => { +export const GraphSearch: React.FC = () => { return (
}> diff --git a/frontend/src/modules/GraphLibrary/components/GraphList.tsx b/frontend/src/modules/GraphLibrary/components/GraphList.tsx new file mode 100644 index 00000000..1b31c9e0 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphList.tsx @@ -0,0 +1,28 @@ +import React from "react"; +// eslint-disable-next-line css-modules/no-unused-class +import styles from "../GraphLibrary.module.scss"; +import { GraphElement } from "./GraphElement/GraphElement"; +import { NodeMap } from "../../Nodes/components/NodeElement/NodeElement"; +import { useGraphContext } from "../context/GraphContext"; +import { InputParameter } from "../../common/Parameters"; + +export interface GraphWorkflow { + name?: string; + title?: string; + description: string; + parameters?: InputParameter; + nodes?: NodeMap; + connectivity?: string[][]; +} + +export const GraphList: React.FC = () => { + const { allGraphs } = useGraphContext(); + if (!allGraphs || Object.entries(allGraphs).length === 0) return
No calibration graphs
; + return ( +
+ {Object.entries(allGraphs ?? {}).map(([key, graph]) => { + return ; + })} +
+ ); +}; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss new file mode 100644 index 00000000..78fb5b69 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss @@ -0,0 +1,49 @@ +@import "../../../../assets/styles/variables"; +@import "../../../../assets/styles/base"; + +.wrapper { + height: 100%; + width: 100%; + display: flex; + background: var(--background-color); + border-radius: var(--border-radius); +} + + +.upperContainer { + color: rgb(217 213 212); +} + +.resultsContainer { + display: flex; + flex-direction: column; + width: 50%; + overflow: hidden; + flex-grow: 1; + color: rgb(217 213 212); + margin-left: 20px; + margin-right: 20px; + height: calc(100% - 20px); + background-color: var(--background-color); +} + +//.titleWrapper { +// display: flex;display +// justify-content: space-between;justify-content +//} +// +//.listWrapper { +// flex-grow: 1;flex-grow +// border: 2px solid var(--border-color);border +// padding: 0 2px 2px;padding; +// background-color: var(--popup-background);background-color +// max-width: 100%;max-width +// overflow: scroll;overflow +//} +// +//.dot {height +// width: 5px;width +// background-color: #bbb;background-color +// border-radius: 50%;border-radius +// display: inline-block;display +//} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx new file mode 100644 index 00000000..46334455 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx @@ -0,0 +1,46 @@ +import React from "react"; +// eslint-disable-next-line css-modules/no-unused-class +import styles from "./GraphStatus.module.scss"; +import { GraphStatusContextProvider, useGraphStatusContext } from "./context/GraphStatusContext"; +import PageName from "../../../../DEPRECATED_components/common/Page/PageName"; +import { Results } from "../../../Nodes/components/Results/Results"; +import { MeasurementHistory } from "./components/MeasurementHistory/MeasurementHistory"; +import { MeasurementElementGraph } from "./components/MeasurementElementGraph/MeasurementElementGraph"; +import { SelectionContextProvider } from "../../../common/context/SelectionContext"; +import { GraphContextProvider } from "../../context/GraphContext"; + +const GraphStatus = () => { + const heading = "Run calibration graph"; + const { allMeasurements, selectedMeasurement, result, diffData } = useGraphStatusContext(); + + // useEffect(() => { + // console.log("aaaa", selectedMeasurement); + // a(); + // }, [selectedMeasurement]); + + return ( +
+
+
+ {heading} +
+ + +
+
+ + +
+
+ ); +}; + +export default () => ( + + + + + + + +); diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss new file mode 100644 index 00000000..a0234a2c --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss @@ -0,0 +1,60 @@ +.rowWrapper { + justify-content: space-between; + font-style: normal; + font-weight: 500; + border: 2px solid var(--border-color); + border-radius: 7px; + padding: 10px; + margin-top: 2px; + margin-bottom: 2px; +} + +.nodeSelected { + background-color: var(--selected-node); +} + +.row { + display: flex; + justify-content: space-between; + flex: 1; + flex-direction: row; + padding-bottom: 10px; +} + +.rectangle { + height: 15px; + width: 15px; + background-color: #807e7e; + display: inline-block; +} + +.titleOrName { + display: flex; + flex: 1; + font-size: 18px; + align-items: center; + padding-bottom: 20px; + gap: 5px; +} + +.description { + align-content: center; + font-size: 14px; + width: 100%; + padding: 15px; +} + +.lowerRow { + display: flex; + gap: 10px; + + .left { + + //width: 50%; + } + + .right { + + //width: 50%; + } +} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx new file mode 100644 index 00000000..76134880 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx @@ -0,0 +1,58 @@ +import React from "react"; +import styles from "./MeasurementElement.module.scss"; +import { Measurement, MeasurementParameter, useGraphStatusContext } from "../../context/GraphStatusContext"; +import { classNames } from "../../../../../../utils/classnames"; +import { useSelectionContext } from "../../../../../common/context/SelectionContext"; +import { MeasurementElementParameters } from "../MeasurementElementParameters/MeasurementElementParameters"; + +export const MeasurementElement: React.FC<{ element: Measurement }> = ({ element }) => { + const { selectedItemName, setSelectedItemName } = useSelectionContext(); + // const { isNodeRunning, setRunningNodeInfo, setIsNodeRunning, setRunningNode, allNodes, setAllNodes } = useNodesContext(); + const { fetchResultsAndDiffData, setResult, setDiffData } = useGraphStatusContext(); + + const formatDateTime = (dateTimeString: string) => { + const [date, time] = dateTimeString.split("T"); + const [timeWithoutMilliseconds] = time.split("."); + return `${date} ${timeWithoutMilliseconds}`; + }; + return ( +
{ + setSelectedItemName(element.snapshot_idx ? element.snapshot_idx.toString() : element.name?.toString()); + if (element.snapshot_idx) { + console.log(element.snapshot_idx); + fetchResultsAndDiffData(element.snapshot_idx); + } else { + setResult({}); + setDiffData({}); + } + }} + > +
+
+
#{element.snapshot_idx} {element.name} +
+
{element.description}
+
+ {selectedItemName && (selectedItemName === element.snapshot_idx?.toString() || selectedItemName === element.name) && ( +
+
+
Status:
+
Run start: {formatDateTime(element.run_start)}
+
Run duration: {element.run_duration}s
+
+
+ + +
+
+ )} +
+ ); +}; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss new file mode 100644 index 00000000..c602358e --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss @@ -0,0 +1,61 @@ +.wrapper { + padding-bottom: 10px; + +} + +.title { + padding: 7px; + font-size: 18px; +} + +.insideWrapper { + height: 100%; + justify-content: space-between; + font-style: normal; + font-weight: 500; + border-radius: 7px; + padding: 10px; + margin-top: 2px; + margin-bottom: 2px; + border: 1px solid var(--border-color); + background-color: var(--popup-background); +} + +.upperContainer { + display: flex; + align-items: center; +} + +.lowerContainer { + height: 100%; +} + +.lowerUpperContainer { + display: flex; + width: 100%; + height: auto; + min-height: 20%; + padding-bottom: 10px; +} + +.lowerUpperLeftContainer { + width: 50%; +} + +.lowerUpperRightContainer { + width: 50%; +} + +.lowerLowerContainer { + display: flex; + width: 100%; + height: 100%; +} + +.lowerLowerLeftContainer { + width: 50%; +} + +.lowerLowerRightContainer { + width: 50%; +} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx new file mode 100644 index 00000000..9a26e223 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import styles from "./MeasurementElementGraph.module.scss"; +import { useGraphContext } from "../../../../context/GraphContext"; +import { GraphList } from "../../../GraphList"; + +export const MeasurementElementGraph: React.FC = () => { + const title = "Calibration Graph Progress"; + const { workflowGraphElements } = useGraphContext(); + + return ( +
+
{title}
+
+
+
+
+
Graph progress: 2/4 nodes completed
+
Run duration: 3m 6s
+
+
+
Graph parameters
+
Qubits: q0, q2, q3
+
Orchestrator parameters
+
Skip failed: True
+
+
+
+ + {/*
left
*/} + {/*
right
*/} + {/**/} +
+
+
+
+ ); +}; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.module.scss new file mode 100644 index 00000000..a19fd414 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.module.scss @@ -0,0 +1,3 @@ +.wrapper { + width: 100%; +} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.tsx new file mode 100644 index 00000000..1410c58d --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementList/MeasurementElementList.tsx @@ -0,0 +1,19 @@ +import React from "react"; +import { IMeasurementHistoryListProps } from "../MeasurementHistory/MeasurementHistory"; +import styles from "./MeasurementElementList.module.scss"; +import { MeasurementElement } from "../MeasurementElement/MeasurementElement"; + +export const MeasurementElementList: React.FC = ({ listOfMeasurements }) => { + return ( + <> +
+ {(listOfMeasurements ?? []).map((el, index) => ( + // className={styles.elementWrapper} +
+ +
+ ))} +
+ + ); +}; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss new file mode 100644 index 00000000..6307400b --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss @@ -0,0 +1,21 @@ +.parameterTitle { + font-size: 14px; + height: 25px; + display: flex; +} + +.title { + font-size: 16px; + height: 25px; + display: flex; +} + +.sectionWrapper { + padding-left: 18px; + padding-bottom: 5px; +} + +.arrowIconWrapper { + margin-top: -3px; + padding-right: 5px; +} diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx new file mode 100644 index 00000000..d881b3a3 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx @@ -0,0 +1,93 @@ +import React from "react"; +import { MeasurementParameter, useGraphStatusContext } from "../../context/GraphStatusContext"; +import styles from "../MeasurementElementParameters/MeasurementElementParameters.module.scss"; +import { ArrowIcon } from "../../../../../../ui-lib/Icons/ArrowIcon"; + +export const MeasurementElementParameters: React.FC<{ + title: string; + parameters: MeasurementParameter; +}> = ({ title, parameters }) => { + const { selectedMeasurement } = useGraphStatusContext(); + const [expanded, setExpanded] = React.useState(true); + // useEffect(() => { + // if (measurementId === (selectedMeasurement?.snapshot_idx?.toString() ?? selectedMeasurement?.name?.toString())) { + // setExpanded(true); + // } else { + // setExpanded(false); + // } + // }, [selectedMeasurement]); + + return ( +
+
+
{ + setExpanded(!expanded); + }} + > + +
+
{title}
+
+ {expanded && ( +
+ {Object.entries(parameters ?? {}).map(([key, value]) => ( +
+ {key}: {value} +
+ ))} +
+ )} +
+ ); +}; +// export const MeasurementElementParameters: React.FC = ({ +// parametersExpanded = false, +// show = false, +// showTitle = true, +// title, +// currentItem, +// }) => { +// // const { selectedNodeNameInWorkflow } = useSelectionContext(); +// const [expanded, setExpanded] = React.useState(true); +// // const [expanded, setExpanded] = React.useState(selectedNodeNameInWorkflow === title ?? parametersExpanded); +// +// // useEffect(() => { +// // if (selectedNodeNameInWorkflow === title) { +// // setExpanded(true); +// // } else { +// // setExpanded(false); +// // } +// // }, [selectedNodeNameInWorkflow]); +// +// return ( +//
+// {showTitle && Object.entries(currentItem?.parameters ?? {}).length > 0 && ( +//
+//
{ +// setExpanded(!expanded); +// }} +// > +// +//
+// {title ?? "Parameters"} +//
+// )} +// {expanded && ( +//
+//
Status: Finished
+//
Run start: {currentItem.]}
+//
+// )} +// {Object.entries(currentItem?.parameters ?? {}).map(([key, parameter]) => ( +//
+//
{key}:
+//
{getInputElement(key, parameter, currentItem)}
+//
+// ))} +//
+// ); +// }; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss new file mode 100644 index 00000000..38b17622 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss @@ -0,0 +1,36 @@ +.wrapper { + height: auto; + justify-content: space-between; + font-style: normal; + font-weight: 500; +} + +.titleRow { + display: flex; + align-items: center; + padding: 5px; + font-size: 18px; +} + +.title { + font-size: 18px; +} + +.contentContainer { + border: 1px solid var(--border-color); + background-color: var(--popup-background); + border-radius: 7px; + padding: 10px; + margin-top: 2px; + margin-bottom: 2px; +} + +.upperContainer { + display: flex; + align-items: center; +} + +.lowerContainer { + display: flex; + align-items: center; +} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx new file mode 100644 index 00000000..5c58ecda --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx @@ -0,0 +1,51 @@ +import React from "react"; + +import styles from "./MeasurementHistory.module.scss"; +import { Measurement } from "../../context/GraphStatusContext"; +import { MeasurementElementList } from "../MeasurementElementList/MeasurementElementList"; +import LoaderPage from "../../../../../../ui-lib/loader/LoaderPage"; + +// eslint-disable-next-line css-modules/no-unused-class + +export interface IMeasurementHistoryListProps { + title?: string; + listOfMeasurements?: Measurement[]; +} + +export const MeasurementHistory: React.FC = ({ title = "Execution history", listOfMeasurements }) => { + if (!listOfMeasurements) { + return ( +
+ +
+ ); + } + return ( +
+
+
{title}
+ {/*
*/} + {/* */} + {/* Track latest*/} + {/*
*/} +
+ {listOfMeasurements && ( +
+
+
+ +
+
+ )} +
+ ); + // return ( + // listOfMeasurements && ( + //
+ // {Object.entries(listOfMeasurements).map(([key, node]) => { + // return ; + // })} + //
+ // ) + // ); +}; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx new file mode 100644 index 00000000..77daa562 --- /dev/null +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx @@ -0,0 +1,157 @@ +import React, { Dispatch, SetStateAction, useContext, useEffect, useState } from "react"; +import { ElementDefinition } from "cytoscape"; +import noop from "../../../../../common/helpers"; +import { GraphLibraryApi } from "../../../api/GraphLibraryApi"; +import { SnapshotsApi } from "../../../../Snapshots/api/SnapshotsApi"; +import { Res } from "../../../../../common/interfaces/Api"; + +interface GraphProviderProps { + children: React.JSX.Element; +} + +export interface MeasurementParameter { + [key: string]: string | number; +} + +export interface Measurement { + snapshot_idx?: number; + name?: string; + description?: string; + outcomes: object; + parameters: MeasurementParameter; + run_start: string; + run_end: string; + run_duration: number; +} + +interface IGraphContext { + allMeasurements?: Measurement[]; + setAllMeasurements: (array: Measurement[] | undefined) => void; + + selectedMeasurement?: Measurement; + setSelectedMeasurement: (measurement: Measurement) => void; + + workflowGraphElements?: ElementDefinition[]; + setWorkflowGraphElements: Dispatch>; + + diffData: unknown | undefined; + setDiffData: Dispatch>; + + result: unknown | undefined; + setResult: Dispatch>; + fetchResultsAndDiffData: (snapshotId: number) => void; +} + +const GraphContext = React.createContext({ + allMeasurements: undefined, + setAllMeasurements: noop, + + selectedMeasurement: undefined, + setSelectedMeasurement: noop, + + workflowGraphElements: undefined, + setWorkflowGraphElements: noop, + + diffData: {}, + setDiffData: () => {}, + + result: {}, + setResult: () => {}, + + fetchResultsAndDiffData: () => {}, +}); + +export const useGraphStatusContext = () => useContext(GraphContext); + +export const GraphStatusContextProvider = (props: GraphProviderProps): React.ReactElement => { + const [allMeasurements, setAllMeasurements] = useState(undefined); + const [selectedMeasurement, setSelectedMeasurement] = useState(undefined); + const [workflowGraphElements, setWorkflowGraphElements] = useState(undefined); + const [diffData, setDiffData] = useState(undefined); + const [result, setResult] = useState(undefined); + + const fetchAllMeasurements = async () => { + const response = await GraphLibraryApi.fetchExecutionHistory(); + if (response.isOk) { + if (response.result && response.result.items) { + setAllMeasurements(response.result.items); + // setAllMeasurements( + // response.result.items.filter((item) => { + // if (item.snapshot_idx) { + // return item; + // } + // }) + // ); + } + } else if (response.error) { + console.log(response.error); + } + }; + + const fetchResultsAndDiffData = (snapshotId: number) => { + const id1 = snapshotId.toString(); + const id2 = snapshotId - 1 >= 0 ? (snapshotId - 1).toString() : "0"; + console.log(id1, id2); + SnapshotsApi.fetchSnapshotResult(id1) + .then((promise: Res) => { + if (promise.result) { + setResult(promise?.result); + } else { + setResult(undefined); + } + }) + .catch((e) => { + console.log(e); + }); + if (id1 !== id2) { + SnapshotsApi.fetchSnapshotUpdate(id2, id1) + .then((promise: Res) => { + if (promise.result) { + setDiffData(promise?.result); + } else { + setDiffData({}); + } + }) + .catch((e) => { + console.log(e); + }); + } else { + setDiffData({}); + } + }; + useEffect(() => { + fetchAllMeasurements(); + }, []); + + useEffect(() => { + const checkInterval = setInterval(async () => fetchAllMeasurements(), 1500); + return () => clearInterval(checkInterval); + }, []); + + // useEffect(() => { + // if (selectedMeasurementName) { + // // fetchMeasurement(selectedMeasurementName); + // setSelectedMeasurement(allMeasurements?.[selectedMeasurementName]); + // } + // }, [selectedMeasurementName]); + + return ( + + {props.children} + + ); +}; diff --git a/frontend/src/modules/CalibrationGraph/context/CalibrationGraphContext.tsx b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx similarity index 57% rename from frontend/src/modules/CalibrationGraph/context/CalibrationGraphContext.tsx rename to frontend/src/modules/GraphLibrary/context/GraphContext.tsx index 63df4935..7f870cd2 100644 --- a/frontend/src/modules/CalibrationGraph/context/CalibrationGraphContext.tsx +++ b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx @@ -1,22 +1,22 @@ import React, { Dispatch, SetStateAction, useContext, useEffect, useState } from "react"; import noop from "../../../common/helpers"; -import { CalibrationGraphWorkflow } from "../components/CalibrationGraphList"; -import { CalibrationsApi } from "../api/CalibrationsAPI"; +import { GraphWorkflow } from "../components/GraphList"; +import { GraphLibraryApi } from "../api/GraphLibraryApi"; import { ElementDefinition } from "cytoscape"; -interface CalibrationGraphProviderProps { +interface GraphProviderProps { children: React.JSX.Element; } -export interface CalibrationGraphMap { - [key: string]: CalibrationGraphWorkflow; +export interface GraphMap { + [key: string]: GraphWorkflow; } -interface ICalibrationGraphContext { - allCalibrationGraphs?: CalibrationGraphMap; - setAllCalibrationGraphs: (array: CalibrationGraphMap | undefined) => void; - selectedWorkflow?: CalibrationGraphWorkflow; - setSelectedWorkflow: (workflow: CalibrationGraphWorkflow) => void; +interface IGraphContext { + allGraphs?: GraphMap; + setAllGraphs: (array: GraphMap | undefined) => void; + selectedWorkflow?: GraphWorkflow; + setSelectedWorkflow: (workflow: GraphWorkflow) => void; selectedWorkflowName?: string; setSelectedWorkflowName: (workflowName: string | undefined) => void; selectedNodeNameInWorkflow?: string; @@ -25,9 +25,9 @@ interface ICalibrationGraphContext { setWorkflowGraphElements: Dispatch>; } -const CalibrationGraphContext = React.createContext({ - allCalibrationGraphs: undefined, - setAllCalibrationGraphs: noop, +const GraphContext = React.createContext({ + allGraphs: undefined, + setAllGraphs: noop, selectedWorkflow: undefined, setSelectedWorkflow: noop, @@ -42,31 +42,32 @@ const CalibrationGraphContext = React.createContext({ setWorkflowGraphElements: noop, }); -export const useCalibrationGraphContext = () => useContext(CalibrationGraphContext); +export const useGraphContext = () => useContext(GraphContext); -export const CalibrationGraphContextProvider = (props: CalibrationGraphProviderProps): React.ReactElement => { - const [allCalibrationGraphs, setAllCalibrationGraphs] = useState(undefined); - const [selectedWorkflow, setSelectedWorkflow] = useState(undefined); +export const GraphContextProvider = (props: GraphProviderProps): React.ReactElement => { + const [allGraphs, setAllGraphs] = useState(undefined); + const [selectedWorkflow, setSelectedWorkflow] = useState(undefined); const [selectedWorkflowName, setSelectedWorkflowName] = useState(undefined); const [selectedNodeNameInWorkflow, setSelectedNodeNameInWorkflow] = useState(undefined); const [workflowGraphElements, setWorkflowGraphElements] = useState(undefined); const fetchAllCalibrationGraphs = async () => { - const response = await CalibrationsApi.fetchAllGraphs(); + const response = await GraphLibraryApi.fetchAllGraphs(); if (response.isOk) { - setAllCalibrationGraphs(response.result! as CalibrationGraphMap); + setAllGraphs(response.result! as GraphMap); } else if (response.error) { console.log(response.error); } }; const fetchWorkflowGraph = async (nodeName: string) => { - const response = await CalibrationsApi.fetchGraph(nodeName); + const response = await GraphLibraryApi.fetchGraph(nodeName); if (response.isOk) { setWorkflowGraphElements(response.result! as ElementDefinition[]); } else if (response.error) { console.log(response.error); } }; + useEffect(() => { fetchAllCalibrationGraphs(); }, []); @@ -74,15 +75,15 @@ export const CalibrationGraphContextProvider = (props: CalibrationGraphProviderP useEffect(() => { if (selectedWorkflowName) { fetchWorkflowGraph(selectedWorkflowName); - setSelectedWorkflow(allCalibrationGraphs?.[selectedWorkflowName]); + setSelectedWorkflow(allGraphs?.[selectedWorkflowName]); } }, [selectedWorkflowName]); return ( - {props.children} - + ); }; diff --git a/frontend/src/modules/CalibrationGraph/index.tsx b/frontend/src/modules/GraphLibrary/index.tsx similarity index 52% rename from frontend/src/modules/CalibrationGraph/index.tsx rename to frontend/src/modules/GraphLibrary/index.tsx index 18fb254c..a2fda841 100644 --- a/frontend/src/modules/CalibrationGraph/index.tsx +++ b/frontend/src/modules/GraphLibrary/index.tsx @@ -1,13 +1,13 @@ import React from "react"; // eslint-disable-next-line css-modules/no-unused-class -import styles from "../CalibrationGraph/CalibrationGraph.module.scss"; -import { CalibrationGraphContextProvider } from "./context/CalibrationGraphContext"; +import styles from "./GraphLibrary.module.scss"; +import { GraphContextProvider } from "./context/GraphContext"; import PageName from "../../DEPRECATED_components/common/Page/PageName"; -import { CalibrationGraphList } from "./components/CalibrationGraphList"; -import { CalibrationGraphSearch } from "./components/CalibrationGraphElement/CalibrationGraphSearch"; +import { GraphList } from "./components/GraphList"; +import { GraphSearch } from "./components/GraphElement/GraphSearch"; import { SelectionContextProvider } from "../common/context/SelectionContext"; -const CalibrationGraph = () => { +const GraphLibrary = () => { const heading = "Run calibration graph"; return (
@@ -15,17 +15,17 @@ const CalibrationGraph = () => {
{heading}
- - + +
); }; export default () => ( - + - + - + ); diff --git a/frontend/src/modules/Nodes/components/Results/Results.tsx b/frontend/src/modules/Nodes/components/Results/Results.tsx index 2fbfd2de..340914eb 100644 --- a/frontend/src/modules/Nodes/components/Results/Results.tsx +++ b/frontend/src/modules/Nodes/components/Results/Results.tsx @@ -3,12 +3,16 @@ import { JSONEditor } from "../../../Data"; import { useNodesContext } from "../../context/NodesContext"; import styles from "./Results.module.scss"; -export const Results: React.FC = () => { - const { results } = useNodesContext(); +export const Results: React.FC<{ title?: string; jsonObject?: unknown }> = ({ title, jsonObject }) => { + let jsonData = jsonObject; + if (!jsonObject) { + const { results } = useNodesContext(); + jsonData = results; + } return (
- +
); }; diff --git a/frontend/src/modules/common/ParameterList.tsx b/frontend/src/modules/common/ParameterList.tsx index 95c80a40..27744247 100644 --- a/frontend/src/modules/common/ParameterList.tsx +++ b/frontend/src/modules/common/ParameterList.tsx @@ -3,8 +3,8 @@ import { NodeDTO, NodeMap } from "../Nodes/components/NodeElement/NodeElement"; import { InputParameter, Parameters, SingleParameter } from "./Parameters"; import { Checkbox } from "@mui/material"; import InputField from "../../DEPRECATED_components/common/Input/InputField"; -import { useCalibrationGraphContext } from "../CalibrationGraph/context/CalibrationGraphContext"; -import { CalibrationGraphWorkflow } from "../CalibrationGraph/components/CalibrationGraphList"; +import { useGraphContext } from "../GraphLibrary/context/GraphContext"; +import { GraphWorkflow } from "../GraphLibrary/components/GraphList"; interface IProps { showParameters: boolean; @@ -12,8 +12,8 @@ interface IProps { } export const ParameterList: React.FC = ({ showParameters = false, mapOfItems }) => { - const { allCalibrationGraphs, setAllCalibrationGraphs, selectedWorkflowName } = useCalibrationGraphContext(); - const updateParameter = (paramKey: string, newValue: boolean | number | string, node?: NodeDTO | CalibrationGraphWorkflow) => { + const { allGraphs, setAllGraphs, selectedWorkflowName } = useGraphContext(); + const updateParameter = (paramKey: string, newValue: boolean | number | string, node?: NodeDTO | GraphWorkflow) => { const updatedParameters = { ...node?.parameters, [paramKey]: { @@ -23,27 +23,27 @@ export const ParameterList: React.FC = ({ showParameters = false, mapOfI }; const changedNode = { ...(node as NodeDTO), parameters: updatedParameters as InputParameter }; const nodeName = node?.name; - if (nodeName && selectedWorkflowName && allCalibrationGraphs?.[selectedWorkflowName]) { + if (nodeName && selectedWorkflowName && allGraphs?.[selectedWorkflowName]) { const changedNodeSInWorkflow = { - ...allCalibrationGraphs[selectedWorkflowName].nodes, + ...allGraphs[selectedWorkflowName].nodes, [nodeName]: changedNode, }; const updatedWorkflow = { - ...allCalibrationGraphs[selectedWorkflowName], + ...allGraphs[selectedWorkflowName], nodes: changedNodeSInWorkflow, }; const updatedCalibrationGraphs = { - ...allCalibrationGraphs, + ...allGraphs, [selectedWorkflowName]: updatedWorkflow, }; - setAllCalibrationGraphs(updatedCalibrationGraphs); + setAllGraphs(updatedCalibrationGraphs); } }; - const getInputElement = (key: string, parameter: SingleParameter, node?: NodeDTO | CalibrationGraphWorkflow) => { + const getInputElement = (key: string, parameter: SingleParameter, node?: NodeDTO | GraphWorkflow) => { switch (parameter.type) { case "boolean": return ( diff --git a/frontend/src/modules/common/Parameters.tsx b/frontend/src/modules/common/Parameters.tsx index 754dbe6b..32d95bb7 100644 --- a/frontend/src/modules/common/Parameters.tsx +++ b/frontend/src/modules/common/Parameters.tsx @@ -3,16 +3,16 @@ import { classNames } from "../../utils/classnames"; import styles from "./Parameters.module.scss"; import { NodeDTO } from "../Nodes/components/NodeElement/NodeElement"; import { ArrowIcon } from "../../ui-lib/Icons/ArrowIcon"; -import { CalibrationGraphWorkflow } from "../CalibrationGraph/components/CalibrationGraphList"; -import { useCalibrationGraphContext } from "../CalibrationGraph/context/CalibrationGraphContext"; +import { GraphWorkflow } from "../GraphLibrary/components/GraphList"; +import { useGraphContext } from "../GraphLibrary/context/GraphContext"; interface IProps { parametersExpanded?: boolean; show: boolean; showTitle: boolean; title?: string; - currentItem?: NodeDTO | CalibrationGraphWorkflow; - getInputElement: (key: string, parameter: SingleParameter, node?: NodeDTO | CalibrationGraphWorkflow) => React.JSX.Element; + currentItem?: NodeDTO | GraphWorkflow; + getInputElement: (key: string, parameter: SingleParameter, node?: NodeDTO | GraphWorkflow) => React.JSX.Element; } export interface SingleParameter { @@ -33,7 +33,7 @@ export const Parameters: React.FC = ({ currentItem, getInputElement, }) => { - const { selectedNodeNameInWorkflow } = useCalibrationGraphContext(); + const { selectedNodeNameInWorkflow } = useGraphContext(); const [expanded, setExpanded] = React.useState(selectedNodeNameInWorkflow === title ?? parametersExpanded); useEffect(() => { diff --git a/frontend/src/routing/ModulesRegistry.ts b/frontend/src/routing/ModulesRegistry.ts index f5297e99..fcbf9c3c 100644 --- a/frontend/src/routing/ModulesRegistry.ts +++ b/frontend/src/routing/ModulesRegistry.ts @@ -7,20 +7,21 @@ import Project from "../modules/Project"; import { ProjectIcon } from "../ui-lib/Icons/ProjectIcon"; import Nodes from "../modules/Nodes"; import { ExperimentsIcon } from "../ui-lib/Icons/ExperimentsIcon"; -import CalibrationGraph from "../modules/CalibrationGraph"; +import CalibrationGraph from "../modules/GraphLibrary"; import { CalibrationIcon } from "../ui-lib/Icons/CalibrationIcon"; +import GraphStatus from "../modules/GraphLibrary/components/GraphStatus/GraphStatus"; const DATA_KEY: ModuleKey = "data"; const NODES_KEY: ModuleKey = "nodes"; const PROJECT_TAB: ModuleKey = "project"; -const CALIBRATION: ModuleKey = "calibration"; +const GRAPH_LIBRARY: ModuleKey = "graph-library"; +const GRAPH_STATUS: ModuleKey = "graph-status"; export type ModuleKey = | "components" | "notebook" | "dashboard" | "project" - | "calibration" | "data" | "nodes" | "experiments" @@ -28,7 +29,9 @@ export type ModuleKey = | "jobs" | "docs" | "getting-started" - | "admin-settings"; + | "admin-settings" + | "graph-library" + | "graph-status"; export type Module = { keyId: ModuleKey; @@ -62,7 +65,28 @@ export const ModulesRegistry: Array = [ path: "nodes", Component: Nodes, menuItem: { - title: "Nodes", + title: "Node library", + icon: ExperimentsIcon, + dataCy: cyKeys.NODES_TAB, + }, + }, + + { + keyId: GRAPH_LIBRARY, + path: "GRAPH_LIBRARY", + Component: CalibrationGraph, + menuItem: { + title: "Graph library", + icon: CalibrationIcon, + dataCy: cyKeys.CALIBRATION_TAB, + }, + }, + { + keyId: GRAPH_STATUS, + path: "graph-status", + Component: GraphStatus, + menuItem: { + title: "Graph Status", icon: ExperimentsIcon, dataCy: cyKeys.NODES_TAB, }, @@ -77,16 +101,6 @@ export const ModulesRegistry: Array = [ dataCy: cyKeys.DATA_TAB, }, }, - { - keyId: CALIBRATION, - path: "calibration", - Component: CalibrationGraph, - menuItem: { - title: "Calibration", - icon: CalibrationIcon, - dataCy: cyKeys.CALIBRATION_TAB, - }, - }, ]; const modulesMap: { [key: string]: Module } = {}; diff --git a/frontend/src/utils/api/apiRoutes.ts b/frontend/src/utils/api/apiRoutes.ts index 3869c05e..5f95a620 100644 --- a/frontend/src/utils/api/apiRoutes.ts +++ b/frontend/src/utils/api/apiRoutes.ts @@ -22,6 +22,7 @@ export const GET_NODE = () => "execution/get_node"; export const ALL_GRAPHS = () => "execution/get_graphs"; export const GET_GRAPH = () => "execution/get_graph"; export const GET_WORKFLOW_GRAPH = () => "execution/get_graph/cytoscape"; +export const GET_EXECUTION_HISTORY = () => "execution/last_run/workflow/execution_history"; export const SUBMIT_NODE_RUN = () => "execution/submit/node"; export const SUBMIT_WORKFLOW_RUN = () => "execution/submit/workflow"; export const GET_LAST_RUN = () => "execution/last_run/"; From e6fd5287c07b72a2634c0c1babec2abcc4649b36 Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Mon, 9 Sep 2024 12:05:25 +0200 Subject: [PATCH 02/11] Lint fix --- .../GraphLibrary/components/GraphList.tsx | 2 +- .../GraphStatus/GraphStatus.module.scss | 25 +++++++-------- .../components/GraphStatus/GraphStatus.tsx | 10 ++---- .../MeasurementElement.module.scss | 2 -- .../MeasurementElementGraph.module.scss | 20 ++++++------ .../MeasurementElementGraph.tsx | 2 -- .../MeasurementElementParameters.tsx | 3 +- .../GraphLibrary/context/GraphContext.tsx | 32 +++++++++++++++++++ 8 files changed, 58 insertions(+), 38 deletions(-) diff --git a/frontend/src/modules/GraphLibrary/components/GraphList.tsx b/frontend/src/modules/GraphLibrary/components/GraphList.tsx index 1b31c9e0..715ad90f 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphList.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphList.tsx @@ -11,7 +11,7 @@ export interface GraphWorkflow { title?: string; description: string; parameters?: InputParameter; - nodes?: NodeMap; + nodes?: NodeMap[]; connectivity?: string[][]; } diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss index 78fb5b69..c6a42a98 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss @@ -28,22 +28,21 @@ } //.titleWrapper { -// display: flex;display -// justify-content: space-between;justify-content +// display: flex;displaydisplay +// justify-content: space-between;justify-contentjustify-content //} // -//.listWrapper { -// flex-grow: 1;flex-grow -// border: 2px solid var(--border-color);border -// padding: 0 2px 2px;padding; -// background-color: var(--popup-background);background-color -// max-width: 100%;max-width -// overflow: scroll;overflow +//.listWrapper {flex-growflex-grow +// border: 2px solid var(--border-color);borderborder +// padding: 0 2px 2px;paddingpadding; +// background-color: var(--popup-background);background-colorbackground-color +// max-width: 100%;max-widthmax-width +// overflow: scroll;overflowoverflow //} // //.dot {height -// width: 5px;width -// background-color: #bbb;background-color -// border-radius: 50%;border-radius -// display: inline-block;display +// width: 5px;widthwidth +// background-color: #bbb;background-colorbackground-color +// border-radius: 50%;border-radiusborder-radius +// display: inline-block;displaydisplay //} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx index 46334455..0aa646a0 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx @@ -11,17 +11,11 @@ import { GraphContextProvider } from "../../context/GraphContext"; const GraphStatus = () => { const heading = "Run calibration graph"; - const { allMeasurements, selectedMeasurement, result, diffData } = useGraphStatusContext(); - - // useEffect(() => { - // console.log("aaaa", selectedMeasurement); - // a(); - // }, [selectedMeasurement]); - + const { allMeasurements, result, diffData } = useGraphStatusContext(); return (
-
+
{heading}
diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss index a0234a2c..1538ce7d 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.module.scss @@ -49,12 +49,10 @@ gap: 10px; .left { - //width: 50%; } .right { - //width: 50%; } } \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss index c602358e..f8bd2f95 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss @@ -21,10 +21,10 @@ background-color: var(--popup-background); } -.upperContainer { - display: flex; - align-items: center; -} +//.upperContainer { +// display: flex;display +// align-items: center;align-items +//} .lowerContainer { height: 100%; @@ -52,10 +52,10 @@ height: 100%; } -.lowerLowerLeftContainer { - width: 50%; -} +//.lowerLowerLeftContainer { +// width: 50%;width +//} -.lowerLowerRightContainer { - width: 50%; -} \ No newline at end of file +//.lowerLowerRightContainer { +// width: 50%;width +//} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx index 9a26e223..6e602f3d 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx @@ -1,11 +1,9 @@ import React from "react"; import styles from "./MeasurementElementGraph.module.scss"; -import { useGraphContext } from "../../../../context/GraphContext"; import { GraphList } from "../../../GraphList"; export const MeasurementElementGraph: React.FC = () => { const title = "Calibration Graph Progress"; - const { workflowGraphElements } = useGraphContext(); return (
diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx index d881b3a3..fc1fcf9d 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { MeasurementParameter, useGraphStatusContext } from "../../context/GraphStatusContext"; +import { MeasurementParameter } from "../../context/GraphStatusContext"; import styles from "../MeasurementElementParameters/MeasurementElementParameters.module.scss"; import { ArrowIcon } from "../../../../../../ui-lib/Icons/ArrowIcon"; @@ -7,7 +7,6 @@ export const MeasurementElementParameters: React.FC<{ title: string; parameters: MeasurementParameter; }> = ({ title, parameters }) => { - const { selectedMeasurement } = useGraphStatusContext(); const [expanded, setExpanded] = React.useState(true); // useEffect(() => { // if (measurementId === (selectedMeasurement?.snapshot_idx?.toString() ?? selectedMeasurement?.name?.toString())) { diff --git a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx index 7f870cd2..beea96ad 100644 --- a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx +++ b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx @@ -51,6 +51,38 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem const [selectedNodeNameInWorkflow, setSelectedNodeNameInWorkflow] = useState(undefined); const [workflowGraphElements, setWorkflowGraphElements] = useState(undefined); + // const removeTargetsNameAndQubits = (someObject: NodeDTO, propertyName: string, tempValue?: string) => { + // let newParams = { ...someObject?.parameters }; + // Object.entries(newParams).forEach(([key, value]) => { + // if (value?.default === tempValue) { + // delete newParams[key]; + // } + // if (key === propertyName) { + // delete newParams[key]; + // } + // }); + // + // someObject.parameters = newParams; + // return someObject; + // }; + + // const fetchAllCalibrationGraphs = async () => { + // const response = await GraphLibraryApi.fetchAllGraphs(); + // if (response.isOk) { + // let allGraphs: GraphMap | undefined = response.result! as GraphMap; + // let temp: GraphMap | undefined = response.result! as GraphMap; + // Object.entries(allGraphs).forEach(([key, graph]) => { + // Object.entries(graph?.nodes as NodeMap[]).forEach(([key2, node]) => { + // node[key2] = removeTargetsNameAndQubits(node[key2], "targets_name", "qubits"); + // }); + // }); + // console.log("response.result", response.result); + // setAllGraphs(response.result! as GraphMap); + // } else if (response.error) { + // console.log(response.error); + // } + // }; + const fetchAllCalibrationGraphs = async () => { const response = await GraphLibraryApi.fetchAllGraphs(); if (response.isOk) { From b7c34eb9726368cca658091d67c5c4b865eb34b4 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Mon, 9 Sep 2024 13:50:31 +0200 Subject: [PATCH 03/11] Feat: Reverse execution history --- frontend/src/utils/api/apiRoutes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/api/apiRoutes.ts b/frontend/src/utils/api/apiRoutes.ts index 92adbca3..e486c6bc 100644 --- a/frontend/src/utils/api/apiRoutes.ts +++ b/frontend/src/utils/api/apiRoutes.ts @@ -23,7 +23,7 @@ export const GET_NODE = () => "execution/get_node"; export const ALL_GRAPHS = () => "execution/get_graphs"; export const GET_GRAPH = () => "execution/get_graph"; export const GET_WORKFLOW_GRAPH = () => "execution/get_graph/cytoscape"; -export const GET_EXECUTION_HISTORY = () => "execution/last_run/workflow/execution_history"; +export const GET_EXECUTION_HISTORY = () => "execution/last_run/workflow/execution_history?reverse=true"; export const SUBMIT_NODE_RUN = () => "execution/submit/node"; export const SUBMIT_WORKFLOW_RUN = () => "execution/submit/workflow"; export const GET_LAST_RUN = () => "execution/last_run/"; From a01c263ebb67d27038e7b1cb8565f9e431e753db Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Tue, 10 Sep 2024 08:55:50 +0200 Subject: [PATCH 04/11] Redirect to GraphStatus page when there is no error in the response when submitting the workflow --- frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx | 2 +- .../GraphLibrary/components/GraphElement/GraphElement.tsx | 6 ++++-- frontend/src/modules/GraphLibrary/components/GraphList.tsx | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx index a054b3bf..a022d88c 100644 --- a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx +++ b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx @@ -33,7 +33,7 @@ export class GraphLibraryApi extends Api { }); } - static submitWorkflow(name: string, workflow: unknown): Promise> { + static submitWorkflow(name: string, workflow: unknown): Promise> { return this._fetch(this.api(SUBMIT_WORKFLOW_RUN()), API_METHODS.POST, { headers: BASIC_HEADERS, body: JSON.stringify(workflow), diff --git a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx index a5a0d2ee..39e74a94 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx @@ -103,8 +103,10 @@ export const GraphElement: React.FC = ({ calibrat const handleSubmit = async () => { if (selectedWorkflowName) { - GraphLibraryApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); - openTab("graph-status"); + const response = await GraphLibraryApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); + if (response.isOk) { + openTab("graph-status"); + } } }; diff --git a/frontend/src/modules/GraphLibrary/components/GraphList.tsx b/frontend/src/modules/GraphLibrary/components/GraphList.tsx index 715ad90f..1b31c9e0 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphList.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphList.tsx @@ -11,7 +11,7 @@ export interface GraphWorkflow { title?: string; description: string; parameters?: InputParameter; - nodes?: NodeMap[]; + nodes?: NodeMap; connectivity?: string[][]; } From ed178cdc6aebcf94737f10b86b1d16a24b986f93 Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Tue, 10 Sep 2024 09:31:40 +0200 Subject: [PATCH 05/11] Added and error message section on GraphLibrary page --- .../components/GraphElement/GraphElement.tsx | 9 ++++- .../GraphElementErrorWrapper.module.scss | 24 ++++++++++++ .../GraphElementErrorWrapper.tsx | 38 +++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 frontend/src/modules/GraphLibrary/components/GraphElementErrorWrapper/GraphElementErrorWrapper.module.scss create mode 100644 frontend/src/modules/GraphLibrary/components/GraphElementErrorWrapper/GraphElementErrorWrapper.tsx diff --git a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx index 39e74a94..24a8f5ea 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; // eslint-disable-next-line css-modules/no-unused-class import styles from "./GraphElement.module.scss"; import { PlayIcon } from "../../../../ui-lib/Icons/PlayIcon"; @@ -14,6 +14,7 @@ import CytoscapeGraph from "../CytoscapeGraph/CytoscapeGraph"; import { GraphLibraryApi } from "../../api/GraphLibraryApi"; import { NodeDTO } from "../../../Nodes/components/NodeElement/NodeElement"; import { useFlexLayoutContext } from "../../../../routing/flexLayout/FlexLayoutContext"; +import { GraphElementErrorWrapper } from "../GraphElementErrorWrapper/GraphElementErrorWrapper"; export interface ICalibrationGraphElementProps { calibrationGraphKey?: string; @@ -26,6 +27,7 @@ interface TransformedGraph { } export const GraphElement: React.FC = ({ calibrationGraphKey, calibrationGraph }) => { + const [errorObject, setErrorObject] = useState(undefined); const { selectedItemName, setSelectedItemName } = useSelectionContext(); const { workflowGraphElements, setSelectedWorkflowName, allGraphs, setAllGraphs, selectedWorkflowName } = useGraphContext(); const { openTab } = useFlexLayoutContext(); @@ -103,9 +105,13 @@ export const GraphElement: React.FC = ({ calibrat const handleSubmit = async () => { if (selectedWorkflowName) { + console.log("transformDataForSubmit()", transformDataForSubmit()); const response = await GraphLibraryApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); + console.log("response", response); if (response.isOk) { openTab("graph-status"); + } else { + setErrorObject(response.error); } } }; @@ -134,6 +140,7 @@ export const GraphElement: React.FC = ({ calibrat
+ = ({ errorObject }) => { + const [expanded, setExpanded] = React.useState(!!errorObject); + + useEffect(() => { + if (errorObject) { + setExpanded(true); + } else { + setExpanded(false); + } + }, [errorObject]); + + return ( +
+ {errorObject !== undefined && ( +
+
{ + setExpanded(!expanded); + }} + > + +
+ {"Error"} +
+ )} + {expanded &&
{JSON.stringify(errorObject)}
} +
+ ); +}; From e8435468301a992d8fc1eb832cce94141a54d169 Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Tue, 10 Sep 2024 09:38:32 +0200 Subject: [PATCH 06/11] Removed unused console.logs --- .../GraphLibrary/components/GraphElement/GraphElement.tsx | 2 -- .../components/MeasurementElement/MeasurementElement.tsx | 1 - .../components/GraphStatus/context/GraphStatusContext.tsx | 1 - .../src/modules/Nodes/components/NodeElement/NodeElement.tsx | 1 - 4 files changed, 5 deletions(-) diff --git a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx index 24a8f5ea..79f112bc 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx @@ -105,9 +105,7 @@ export const GraphElement: React.FC = ({ calibrat const handleSubmit = async () => { if (selectedWorkflowName) { - console.log("transformDataForSubmit()", transformDataForSubmit()); const response = await GraphLibraryApi.submitWorkflow(selectedWorkflowName, transformDataForSubmit()); - console.log("response", response); if (response.isOk) { openTab("graph-status"); } else { diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx index 76134880..82ed9ff7 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx @@ -26,7 +26,6 @@ export const MeasurementElement: React.FC<{ element: Measurement }> = ({ element onClick={() => { setSelectedItemName(element.snapshot_idx ? element.snapshot_idx.toString() : element.name?.toString()); if (element.snapshot_idx) { - console.log(element.snapshot_idx); fetchResultsAndDiffData(element.snapshot_idx); } else { setResult({}); diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx index 77daa562..15369dd5 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx @@ -91,7 +91,6 @@ export const GraphStatusContextProvider = (props: GraphProviderProps): React.Rea const fetchResultsAndDiffData = (snapshotId: number) => { const id1 = snapshotId.toString(); const id2 = snapshotId - 1 >= 0 ? (snapshotId - 1).toString() : "0"; - console.log(id1, id2); SnapshotsApi.fetchSnapshotResult(id1) .then((promise: Res) => { if (promise.result) { diff --git a/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx b/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx index f0eefdb8..ed93e4f7 100644 --- a/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx +++ b/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx @@ -83,7 +83,6 @@ export const NodeElement: React.FC<{ nodeKey: string; node: NodeDTO }> = ({ node setRunningNode(node); const result = await NodesApi.submitNodeParameters(node.name, transformInputParameters(node.parameters as InputParameter)); if (result.isOk) { - console.log("result", result); setRunningNodeInfo({ timestampOfRun: formatDate(new Date()), status: "running" }); } else { const errorWithDetails = result.error as NodeStatusErrorWithDetails; From 2fe1d1c7079a94c3f0d42aa89e6b3c912a7100a6 Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Tue, 10 Sep 2024 10:18:37 +0200 Subject: [PATCH 07/11] Remove targets_name from workflow graph and property with targets_name value from nodes (and targets_name property) --- .../GraphLibrary/context/GraphContext.tsx | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx index beea96ad..3ce35f57 100644 --- a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx +++ b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx @@ -3,6 +3,7 @@ import noop from "../../../common/helpers"; import { GraphWorkflow } from "../components/GraphList"; import { GraphLibraryApi } from "../api/GraphLibraryApi"; import { ElementDefinition } from "cytoscape"; +import { InputParameter } from "../../common/Parameters"; interface GraphProviderProps { children: React.JSX.Element; @@ -51,46 +52,60 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem const [selectedNodeNameInWorkflow, setSelectedNodeNameInWorkflow] = useState(undefined); const [workflowGraphElements, setWorkflowGraphElements] = useState(undefined); - // const removeTargetsNameAndQubits = (someObject: NodeDTO, propertyName: string, tempValue?: string) => { - // let newParams = { ...someObject?.parameters }; - // Object.entries(newParams).forEach(([key, value]) => { - // if (value?.default === tempValue) { - // delete newParams[key]; - // } - // if (key === propertyName) { - // delete newParams[key]; - // } - // }); - // - // someObject.parameters = newParams; - // return someObject; - // }; - - // const fetchAllCalibrationGraphs = async () => { - // const response = await GraphLibraryApi.fetchAllGraphs(); - // if (response.isOk) { - // let allGraphs: GraphMap | undefined = response.result! as GraphMap; - // let temp: GraphMap | undefined = response.result! as GraphMap; - // Object.entries(allGraphs).forEach(([key, graph]) => { - // Object.entries(graph?.nodes as NodeMap[]).forEach(([key2, node]) => { - // node[key2] = removeTargetsNameAndQubits(node[key2], "targets_name", "qubits"); - // }); - // }); - // console.log("response.result", response.result); - // setAllGraphs(response.result! as GraphMap); - // } else if (response.error) { - // console.log(response.error); - // } - // }; + const updateObject = (obj: GraphWorkflow): GraphWorkflow => { + const modifyParameters = (parameters?: InputParameter, isNodeLevel: boolean = false): InputParameter | undefined => { + if (parameters?.targets_name) { + if (isNodeLevel) { + const targetKey = parameters.targets_name.default?.toString(); + + if (targetKey && parameters.targets_name.default) { + const { targets_name, [targetKey]: _, ...rest } = parameters; + return rest; + } + const { targets_name, ...rest } = parameters; + return rest; + } else { + const { targets_name, ...rest } = parameters; + return rest; + } + } + return parameters; + }; + + obj.parameters = modifyParameters(obj.parameters, false); + + if (obj.nodes) { + Object.keys(obj.nodes).forEach((nodeKey) => { + const node = obj.nodes![nodeKey]; + node.parameters = modifyParameters(node.parameters, true); + }); + } + + return obj; + }; + + const updateAllGraphs = (allFetchedGraphs: GraphMap): GraphMap => { + const updatedGraphs: GraphMap = {}; + + Object.entries(allFetchedGraphs).forEach(([key, graph]) => { + updatedGraphs[key] = updateObject(graph); + }); + + return updatedGraphs; + }; const fetchAllCalibrationGraphs = async () => { const response = await GraphLibraryApi.fetchAllGraphs(); if (response.isOk) { - setAllGraphs(response.result! as GraphMap); + const allFetchedGraphs = response.result! as GraphMap; + const updatedGraphs = updateAllGraphs(allFetchedGraphs); + + setAllGraphs(updatedGraphs); } else if (response.error) { console.log(response.error); } }; + const fetchWorkflowGraph = async (nodeName: string) => { const response = await GraphLibraryApi.fetchGraph(nodeName); if (response.isOk) { From 46e36b07df6f862f90946291054c6bf169b3d99a Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Wed, 11 Sep 2024 18:20:38 +0200 Subject: [PATCH 08/11] Big fix for Graph Status page and other --- .../GraphLibrary/api/GraphLibraryApi.tsx | 22 ++++- .../CytoscapeGraph/CytoscapeGraph.module.scss | 5 +- .../components/GraphElement/GraphElement.tsx | 4 +- .../GraphLibrary/components/GraphList.tsx | 2 +- .../GraphStatus/GraphStatus.module.scss | 25 +---- .../components/GraphStatus/GraphStatus.tsx | 7 +- .../MeasurementElement/MeasurementElement.tsx | 8 +- .../MeasurementElementGraph.module.scss | 8 +- .../MeasurementElementGraph.tsx | 32 ++++--- .../MeasurementElementParameters.tsx | 92 ------------------- .../MeasurementHistory.module.scss | 8 +- .../MeasurementHistory/MeasurementHistory.tsx | 26 ++---- .../context/GraphStatusContext.tsx | 11 +-- .../GraphLibrary/context/GraphContext.tsx | 62 ++++++++++++- .../components/NodeElement/NodeElement.tsx | 2 +- .../modules/Nodes/context/NodesContext.tsx | 4 +- .../GlobalElementParameters.module.scss} | 0 .../GlobalElementParameters.tsx | 36 ++++++++ .../common/{ => Parameters}/ParameterList.tsx | 8 +- .../{ => Parameters}/Parameters.module.scss | 0 .../common/{ => Parameters}/Parameters.tsx | 10 +- frontend/src/utils/api/apiRoutes.ts | 25 ++--- 22 files changed, 194 insertions(+), 203 deletions(-) delete mode 100644 frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx rename frontend/src/modules/{GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss => common/GlobalElementParameters/GlobalElementParameters.module.scss} (100%) create mode 100644 frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx rename frontend/src/modules/common/{ => Parameters}/ParameterList.tsx (88%) rename frontend/src/modules/common/{ => Parameters}/Parameters.module.scss (100%) rename frontend/src/modules/common/{ => Parameters}/Parameters.tsx (85%) diff --git a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx index a022d88c..56b8e338 100644 --- a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx +++ b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx @@ -1,6 +1,12 @@ import Api, { BASIC_HEADERS } from "../../../utils/api"; import { Res } from "../../../common/interfaces/Api"; -import { ALL_GRAPHS, GET_EXECUTION_HISTORY, GET_WORKFLOW_GRAPH, SUBMIT_WORKFLOW_RUN } from "../../../utils/api/apiRoutes"; +import { + ALL_GRAPHS, + GET_EXECUTION_HISTORY, + GET_LAST_RUN_WORKFLOW_STATUS, + GET_WORKFLOW_GRAPH, + SUBMIT_WORKFLOW_RUN, +} from "../../../utils/api/apiRoutes"; import { API_METHODS } from "../../../common/enums/Api"; import { Measurement } from "../components/GraphStatus/context/GraphStatusContext"; @@ -27,17 +33,23 @@ export class GraphLibraryApi extends Api { }); } + static submitWorkflow(name: string, workflow: unknown): Promise> { + return this._fetch(this.api(SUBMIT_WORKFLOW_RUN()), API_METHODS.POST, { + headers: BASIC_HEADERS, + body: JSON.stringify(workflow), + queryParams: { name }, + }); + } + static fetchExecutionHistory(): Promise> { return this._fetch(this.api(GET_EXECUTION_HISTORY()), API_METHODS.GET, { headers: BASIC_HEADERS, }); } - static submitWorkflow(name: string, workflow: unknown): Promise> { - return this._fetch(this.api(SUBMIT_WORKFLOW_RUN()), API_METHODS.POST, { + static fetchLastWorkflowStatus(): Promise> { + return this._fetch(this.api(GET_LAST_RUN_WORKFLOW_STATUS()), API_METHODS.GET, { headers: BASIC_HEADERS, - body: JSON.stringify(workflow), - queryParams: { name }, }); } } diff --git a/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss index 027542b3..1b351f4e 100644 --- a/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss +++ b/frontend/src/modules/GraphLibrary/components/CytoscapeGraph/CytoscapeGraph.module.scss @@ -2,10 +2,11 @@ @import "../../../../assets/styles/base"; .wrapper { - width: auto; - height: 100%; + min-height: 20%; background: var(--background-color); border-radius: var(--border-radius); margin-left: 10px; margin-right: 10px; + width: 100%; + height: 400px; } diff --git a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx index 79f112bc..76eb049c 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphElement/GraphElement.tsx @@ -3,12 +3,12 @@ import React, { useState } from "react"; import styles from "./GraphElement.module.scss"; import { PlayIcon } from "../../../../ui-lib/Icons/PlayIcon"; import { classNames } from "../../../../utils/classnames"; -import { InputParameter, Parameters, SingleParameter } from "../../../common/Parameters"; +import { InputParameter, Parameters, SingleParameter } from "../../../common/Parameters/Parameters"; import { GraphWorkflow } from "../GraphList"; import { useSelectionContext } from "../../../common/context/SelectionContext"; import { Checkbox } from "@mui/material"; import InputField from "../../../../DEPRECATED_components/common/Input/InputField"; -import { ParameterList } from "../../../common/ParameterList"; +import { ParameterList } from "../../../common/Parameters/ParameterList"; import { useGraphContext } from "../../context/GraphContext"; import CytoscapeGraph from "../CytoscapeGraph/CytoscapeGraph"; import { GraphLibraryApi } from "../../api/GraphLibraryApi"; diff --git a/frontend/src/modules/GraphLibrary/components/GraphList.tsx b/frontend/src/modules/GraphLibrary/components/GraphList.tsx index 1b31c9e0..db872719 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphList.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphList.tsx @@ -4,7 +4,7 @@ import styles from "../GraphLibrary.module.scss"; import { GraphElement } from "./GraphElement/GraphElement"; import { NodeMap } from "../../Nodes/components/NodeElement/NodeElement"; import { useGraphContext } from "../context/GraphContext"; -import { InputParameter } from "../../common/Parameters"; +import { InputParameter } from "../../common/Parameters/Parameters"; export interface GraphWorkflow { name?: string; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss index c6a42a98..4146b4a9 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss @@ -9,6 +9,11 @@ border-radius: var(--border-radius); } +.graphContainer { + flex: 1; + align-content: center; + width: 60%; +} .upperContainer { color: rgb(217 213 212); @@ -26,23 +31,3 @@ height: calc(100% - 20px); background-color: var(--background-color); } - -//.titleWrapper { -// display: flex;displaydisplay -// justify-content: space-between;justify-contentjustify-content -//} -// -//.listWrapper {flex-growflex-grow -// border: 2px solid var(--border-color);borderborder -// padding: 0 2px 2px;paddingpadding; -// background-color: var(--popup-background);background-colorbackground-color -// max-width: 100%;max-widthmax-width -// overflow: scroll;overflowoverflow -//} -// -//.dot {height -// width: 5px;widthwidth -// background-color: #bbb;background-colorbackground-color -// border-radius: 50%;border-radiusborder-radius -// display: inline-block;displaydisplay -//} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx index 0aa646a0..7e417416 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.tsx @@ -7,18 +7,21 @@ import { Results } from "../../../Nodes/components/Results/Results"; import { MeasurementHistory } from "./components/MeasurementHistory/MeasurementHistory"; import { MeasurementElementGraph } from "./components/MeasurementElementGraph/MeasurementElementGraph"; import { SelectionContextProvider } from "../../../common/context/SelectionContext"; -import { GraphContextProvider } from "../../context/GraphContext"; +import { GraphContextProvider, useGraphContext } from "../../context/GraphContext"; const GraphStatus = () => { const heading = "Run calibration graph"; + const { workflowGraphElements } = useGraphContext(); const { allMeasurements, result, diffData } = useGraphStatusContext(); + return (
{heading}
- + {workflowGraphElements && } +
diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx index 82ed9ff7..0e8c76ea 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElement/MeasurementElement.tsx @@ -1,9 +1,9 @@ import React from "react"; import styles from "./MeasurementElement.module.scss"; -import { Measurement, MeasurementParameter, useGraphStatusContext } from "../../context/GraphStatusContext"; +import { GlobalParameterStructure, Measurement, useGraphStatusContext } from "../../context/GraphStatusContext"; import { classNames } from "../../../../../../utils/classnames"; import { useSelectionContext } from "../../../../../common/context/SelectionContext"; -import { MeasurementElementParameters } from "../MeasurementElementParameters/MeasurementElementParameters"; +import { GlobalElementParameters } from "../../../../../common/GlobalElementParameters/GlobalElementParameters"; export const MeasurementElement: React.FC<{ element: Measurement }> = ({ element }) => { const { selectedItemName, setSelectedItemName } = useSelectionContext(); @@ -47,8 +47,8 @@ export const MeasurementElement: React.FC<{ element: Measurement }> = ({ element
Run duration: {element.run_duration}s
- - + +
)} diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss index f8bd2f95..7ee11723 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss @@ -22,8 +22,8 @@ } //.upperContainer { -// display: flex;display -// align-items: center;align-items +// display: flex;displaydisplaydisplay +// align-items: center;align-itemsalign-itemsalign-items //} .lowerContainer { @@ -53,9 +53,9 @@ } //.lowerLowerLeftContainer { -// width: 50%;width +// width: 50%;widthwidthwidth //} //.lowerLowerRightContainer { -// width: 50%;width +// width: 50%;widthwidthwidth //} \ No newline at end of file diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx index 6e602f3d..790f4d9b 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx @@ -1,10 +1,20 @@ import React from "react"; import styles from "./MeasurementElementGraph.module.scss"; -import { GraphList } from "../../../GraphList"; +import CytoscapeGraph from "../../../CytoscapeGraph/CytoscapeGraph"; +import cytoscape from "cytoscape"; +import { useGraphContext } from "../../../../context/GraphContext"; +import { GlobalElementParameters } from "../../../../../common/GlobalElementParameters/GlobalElementParameters"; -export const MeasurementElementGraph: React.FC = () => { - const title = "Calibration Graph Progress"; +interface IProps { + workflowGraphElements: cytoscape.ElementDefinition[]; + active?: boolean; + nodesCompleted?: number; + runDuration?: number; +} +export const MeasurementElementGraph: React.FC = ({ workflowGraphElements }) => { + const title = "Calibration Graph Progress"; + const { lastRunInfo } = useGraphContext(); return (
{title}
@@ -12,21 +22,17 @@ export const MeasurementElementGraph: React.FC = () => {
-
Graph progress: 2/4 nodes completed
-
Run duration: 3m 6s
+
Status: {lastRunInfo?.active ? "running" : "finished"}
+
Graph progress: {lastRunInfo?.nodesCompleted} nodes completed
+
Run duration: {lastRunInfo?.runDuration}
-
Graph parameters
-
Qubits: q0, q2, q3
-
Orchestrator parameters
-
Skip failed: True
+ +
- - {/*
left
*/} - {/*
right
*/} - {/**/} +
diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx deleted file mode 100644 index fc1fcf9d..00000000 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from "react"; -import { MeasurementParameter } from "../../context/GraphStatusContext"; -import styles from "../MeasurementElementParameters/MeasurementElementParameters.module.scss"; -import { ArrowIcon } from "../../../../../../ui-lib/Icons/ArrowIcon"; - -export const MeasurementElementParameters: React.FC<{ - title: string; - parameters: MeasurementParameter; -}> = ({ title, parameters }) => { - const [expanded, setExpanded] = React.useState(true); - // useEffect(() => { - // if (measurementId === (selectedMeasurement?.snapshot_idx?.toString() ?? selectedMeasurement?.name?.toString())) { - // setExpanded(true); - // } else { - // setExpanded(false); - // } - // }, [selectedMeasurement]); - - return ( -
-
-
{ - setExpanded(!expanded); - }} - > - -
-
{title}
-
- {expanded && ( -
- {Object.entries(parameters ?? {}).map(([key, value]) => ( -
- {key}: {value} -
- ))} -
- )} -
- ); -}; -// export const MeasurementElementParameters: React.FC = ({ -// parametersExpanded = false, -// show = false, -// showTitle = true, -// title, -// currentItem, -// }) => { -// // const { selectedNodeNameInWorkflow } = useSelectionContext(); -// const [expanded, setExpanded] = React.useState(true); -// // const [expanded, setExpanded] = React.useState(selectedNodeNameInWorkflow === title ?? parametersExpanded); -// -// // useEffect(() => { -// // if (selectedNodeNameInWorkflow === title) { -// // setExpanded(true); -// // } else { -// // setExpanded(false); -// // } -// // }, [selectedNodeNameInWorkflow]); -// -// return ( -//
-// {showTitle && Object.entries(currentItem?.parameters ?? {}).length > 0 && ( -//
-//
{ -// setExpanded(!expanded); -// }} -// > -// -//
-// {title ?? "Parameters"} -//
-// )} -// {expanded && ( -//
-//
Status: Finished
-//
Run start: {currentItem.]}
-//
-// )} -// {Object.entries(currentItem?.parameters ?? {}).map(([key, parameter]) => ( -//
-//
{key}:
-//
{getInputElement(key, parameter, currentItem)}
-//
-// ))} -//
-// ); -// }; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss index 38b17622..ea312a8d 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.module.scss @@ -25,10 +25,10 @@ margin-bottom: 2px; } -.upperContainer { - display: flex; - align-items: center; -} +//.upperContainer { +// display: flex;display +// align-items: center;align-items +//} .lowerContainer { display: flex; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx index 5c58ecda..557f3b5b 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementHistory/MeasurementHistory.tsx @@ -1,9 +1,7 @@ import React from "react"; - import styles from "./MeasurementHistory.module.scss"; import { Measurement } from "../../context/GraphStatusContext"; import { MeasurementElementList } from "../MeasurementElementList/MeasurementElementList"; -import LoaderPage from "../../../../../../ui-lib/loader/LoaderPage"; // eslint-disable-next-line css-modules/no-unused-class @@ -13,13 +11,6 @@ export interface IMeasurementHistoryListProps { } export const MeasurementHistory: React.FC = ({ title = "Execution history", listOfMeasurements }) => { - if (!listOfMeasurements) { - return ( -
- -
- ); - } return (
@@ -29,23 +20,18 @@ export const MeasurementHistory: React.FC = ({ tit {/* Track latest*/} {/*
*/}
- {listOfMeasurements && ( + {listOfMeasurements && listOfMeasurements?.length > 0 && (
-
)} + {(!listOfMeasurements || listOfMeasurements?.length === 0) && ( +
+
No measurements found
+
+ )} ); - // return ( - // listOfMeasurements && ( - //
- // {Object.entries(listOfMeasurements).map(([key, node]) => { - // return ; - // })} - //
- // ) - // ); }; diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx index 15369dd5..63e74c51 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/context/GraphStatusContext.tsx @@ -9,7 +9,7 @@ interface GraphProviderProps { children: React.JSX.Element; } -export interface MeasurementParameter { +export interface GlobalParameterStructure { [key: string]: string | number; } @@ -18,7 +18,7 @@ export interface Measurement { name?: string; description?: string; outcomes: object; - parameters: MeasurementParameter; + parameters: GlobalParameterStructure; run_start: string; run_end: string; run_duration: number; @@ -75,13 +75,6 @@ export const GraphStatusContextProvider = (props: GraphProviderProps): React.Rea if (response.isOk) { if (response.result && response.result.items) { setAllMeasurements(response.result.items); - // setAllMeasurements( - // response.result.items.filter((item) => { - // if (item.snapshot_idx) { - // return item; - // } - // }) - // ); } } else if (response.error) { console.log(response.error); diff --git a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx index 3ce35f57..9a59a3e2 100644 --- a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx +++ b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx @@ -3,12 +3,21 @@ import noop from "../../../common/helpers"; import { GraphWorkflow } from "../components/GraphList"; import { GraphLibraryApi } from "../api/GraphLibraryApi"; import { ElementDefinition } from "cytoscape"; -import { InputParameter } from "../../common/Parameters"; +import { InputParameter } from "../../common/Parameters/Parameters"; +import { NodesApi } from "../../Nodes/api/NodesAPI"; +import { StatusResponseType } from "../../Nodes/context/NodesContext"; interface GraphProviderProps { children: React.JSX.Element; } +interface LastRunInfo { + workflowName?: string; + active?: boolean; + nodesCompleted?: number; + runDuration?: number; +} + export interface GraphMap { [key: string]: GraphWorkflow; } @@ -24,6 +33,8 @@ interface IGraphContext { setSelectedNodeNameInWorkflow: (nodeName: string | undefined) => void; workflowGraphElements?: ElementDefinition[]; setWorkflowGraphElements: Dispatch>; + lastRunInfo?: LastRunInfo; + setLastRunInfo: Dispatch>; } const GraphContext = React.createContext({ @@ -41,6 +52,9 @@ const GraphContext = React.createContext({ workflowGraphElements: undefined, setWorkflowGraphElements: noop, + + lastRunInfo: undefined, + setLastRunInfo: noop, }); export const useGraphContext = () => useContext(GraphContext); @@ -51,6 +65,21 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem const [selectedWorkflowName, setSelectedWorkflowName] = useState(undefined); const [selectedNodeNameInWorkflow, setSelectedNodeNameInWorkflow] = useState(undefined); const [workflowGraphElements, setWorkflowGraphElements] = useState(undefined); + const [lastRunInfo, setLastRunInfo] = useState(undefined); + + const fetchLastRunInfo = async () => { + const lastRunResponse = await NodesApi.fetchLastRunInfo(); + if (lastRunResponse && lastRunResponse.isOk) { + const lastRunResponseResult = lastRunResponse.result as StatusResponseType; + if (lastRunResponseResult && lastRunResponseResult.status !== "error") { + setLastRunInfo({ workflowName: (lastRunResponse.result as { name: string }).name }); + } else { + console.log("last run status was error"); + } + } else { + console.log("lastRunResponse was ", lastRunResponse); + } + }; const updateObject = (obj: GraphWorkflow): GraphWorkflow => { const modifyParameters = (parameters?: InputParameter, isNodeLevel: boolean = false): InputParameter | undefined => { @@ -59,12 +88,15 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem const targetKey = parameters.targets_name.default?.toString(); if (targetKey && parameters.targets_name.default) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { targets_name, [targetKey]: _, ...rest } = parameters; return rest; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { targets_name, ...rest } = parameters; return rest; } else { + // eslint-disable-next-line @typescript-eslint/no-unused-vars const { targets_name, ...rest } = parameters; return rest; } @@ -115,10 +147,31 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem } }; + const fetchLastRunWorkflowStatus = async () => { + const response = await GraphLibraryApi.fetchLastWorkflowStatus(); + if (response.isOk) { + setLastRunInfo({ + ...lastRunInfo, + active: response.result?.active, + nodesCompleted: response.result?.nodes_completed, + runDuration: response.result?.run_duration, + }); + } else if (response.error) { + console.log(response.error); + } + }; + useEffect(() => { fetchAllCalibrationGraphs(); + fetchLastRunInfo(); }, []); + useEffect(() => { + if (lastRunInfo?.workflowName) { + fetchWorkflowGraph(lastRunInfo?.workflowName); + } + }, [lastRunInfo]); + useEffect(() => { if (selectedWorkflowName) { fetchWorkflowGraph(selectedWorkflowName); @@ -126,6 +179,11 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem } }, [selectedWorkflowName]); + useEffect(() => { + const checkInterval = setInterval(async () => fetchLastRunWorkflowStatus(), 1500); + return () => clearInterval(checkInterval); + }, []); + return ( {props.children} diff --git a/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx b/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx index ed93e4f7..ea98d6fb 100644 --- a/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx +++ b/frontend/src/modules/Nodes/components/NodeElement/NodeElement.tsx @@ -6,7 +6,7 @@ import { Checkbox, CircularProgress } from "@mui/material"; import { NodeStatusErrorWithDetails, useNodesContext } from "../../context/NodesContext"; import { classNames } from "../../../../utils/classnames"; import { NodesApi } from "../../api/NodesAPI"; -import { InputParameter, Parameters, SingleParameter } from "../../../common/Parameters"; +import { InputParameter, Parameters, SingleParameter } from "../../../common/Parameters/Parameters"; import { useSelectionContext } from "../../../common/context/SelectionContext"; export interface NodeDTO { diff --git a/frontend/src/modules/Nodes/context/NodesContext.tsx b/frontend/src/modules/Nodes/context/NodesContext.tsx index d9387896..52e851ed 100644 --- a/frontend/src/modules/Nodes/context/NodesContext.tsx +++ b/frontend/src/modules/Nodes/context/NodesContext.tsx @@ -70,7 +70,7 @@ export interface NodeStatusErrorWithDetails { detail: { msg: string; type: string }[]; } -export interface NodeStatusResponseType { +export interface StatusResponseType { idx: number; status: string; error?: NodeStatusError; @@ -107,7 +107,7 @@ export function NodesContextProvider(props: NodesContextProviderProps): React.Re const fetchNodeResults = async () => { const lastRunResponse = await NodesApi.fetchLastRunInfo(); if (lastRunResponse && lastRunResponse.isOk) { - const lastRunResponseResult = lastRunResponse.result as NodeStatusResponseType; + const lastRunResponseResult = lastRunResponse.result as StatusResponseType; if (lastRunResponseResult && lastRunResponseResult.status !== "error") { const idx = lastRunResponseResult.idx.toString(); if (lastRunResponseResult.idx) { diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss similarity index 100% rename from frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementParameters/MeasurementElementParameters.module.scss rename to frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss diff --git a/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx new file mode 100644 index 00000000..cdb9baa7 --- /dev/null +++ b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import styles from "../GlobalElementParameters/GlobalElementParameters.module.scss"; +import { ArrowIcon } from "../../../ui-lib/Icons/ArrowIcon"; +import { GlobalParameterStructure } from "../../GraphLibrary/components/GraphStatus/context/GraphStatusContext"; + +export const GlobalElementParameters: React.FC<{ + title: string; + parameters: GlobalParameterStructure; +}> = ({ title, parameters }) => { + const [expanded, setExpanded] = React.useState(true); + + return ( +
+
+
{ + setExpanded(!expanded); + }} + > + +
+
{title}
+
+ {expanded && ( +
+ {Object.entries(parameters ?? {}).map(([key, value]) => ( +
+ {key}: {value} +
+ ))} +
+ )} +
+ ); +}; diff --git a/frontend/src/modules/common/ParameterList.tsx b/frontend/src/modules/common/Parameters/ParameterList.tsx similarity index 88% rename from frontend/src/modules/common/ParameterList.tsx rename to frontend/src/modules/common/Parameters/ParameterList.tsx index 27744247..61e4c84c 100644 --- a/frontend/src/modules/common/ParameterList.tsx +++ b/frontend/src/modules/common/Parameters/ParameterList.tsx @@ -1,10 +1,10 @@ import React from "react"; -import { NodeDTO, NodeMap } from "../Nodes/components/NodeElement/NodeElement"; +import { NodeDTO, NodeMap } from "../../Nodes/components/NodeElement/NodeElement"; import { InputParameter, Parameters, SingleParameter } from "./Parameters"; import { Checkbox } from "@mui/material"; -import InputField from "../../DEPRECATED_components/common/Input/InputField"; -import { useGraphContext } from "../GraphLibrary/context/GraphContext"; -import { GraphWorkflow } from "../GraphLibrary/components/GraphList"; +import InputField from "../../../DEPRECATED_components/common/Input/InputField"; +import { useGraphContext } from "../../GraphLibrary/context/GraphContext"; +import { GraphWorkflow } from "../../GraphLibrary/components/GraphList"; interface IProps { showParameters: boolean; diff --git a/frontend/src/modules/common/Parameters.module.scss b/frontend/src/modules/common/Parameters/Parameters.module.scss similarity index 100% rename from frontend/src/modules/common/Parameters.module.scss rename to frontend/src/modules/common/Parameters/Parameters.module.scss diff --git a/frontend/src/modules/common/Parameters.tsx b/frontend/src/modules/common/Parameters/Parameters.tsx similarity index 85% rename from frontend/src/modules/common/Parameters.tsx rename to frontend/src/modules/common/Parameters/Parameters.tsx index 32d95bb7..708f815d 100644 --- a/frontend/src/modules/common/Parameters.tsx +++ b/frontend/src/modules/common/Parameters/Parameters.tsx @@ -1,10 +1,10 @@ import React, { useEffect } from "react"; -import { classNames } from "../../utils/classnames"; +import { classNames } from "../../../utils/classnames"; import styles from "./Parameters.module.scss"; -import { NodeDTO } from "../Nodes/components/NodeElement/NodeElement"; -import { ArrowIcon } from "../../ui-lib/Icons/ArrowIcon"; -import { GraphWorkflow } from "../GraphLibrary/components/GraphList"; -import { useGraphContext } from "../GraphLibrary/context/GraphContext"; +import { NodeDTO } from "../../Nodes/components/NodeElement/NodeElement"; +import { ArrowIcon } from "../../../ui-lib/Icons/ArrowIcon"; +import { GraphWorkflow } from "../../GraphLibrary/components/GraphList"; +import { useGraphContext } from "../../GraphLibrary/context/GraphContext"; interface IProps { parametersExpanded?: boolean; diff --git a/frontend/src/utils/api/apiRoutes.ts b/frontend/src/utils/api/apiRoutes.ts index e486c6bc..c953ddd2 100644 --- a/frontend/src/utils/api/apiRoutes.ts +++ b/frontend/src/utils/api/apiRoutes.ts @@ -1,18 +1,18 @@ export const ALL_SNAPSHOTS = ({ branchName = "main", pageNumber = 1, pageLimit = 100, reverseOrder = true, globalReverse = false }) => - "api/branch/" + - branchName + - "/snapshots_history?page=" + - pageNumber + - "&per_page=" + - pageLimit + - "&reverse=" + - reverseOrder + - "&global_reverse=" + - globalReverse; + "api/branch/" + + branchName + + "/snapshots_history?page=" + + pageNumber + + "&per_page=" + + pageLimit + + "&reverse=" + + reverseOrder + + "&global_reverse=" + + globalReverse; export const ONE_SNAPSHOT = (snapshotId: string) => `api/snapshot/${snapshotId}/`; export const SNAPSHOT_RESULT = (snapshotId: string) => `api/data_file/${snapshotId}/content`; export const SNAPSHOT_DIFF = (currentSnapshotId: string, newSnapshotId: string) => - `api/snapshot/${currentSnapshotId}/compare?id_to_compare=${newSnapshotId}`; + `api/snapshot/${currentSnapshotId}/compare?id_to_compare=${newSnapshotId}`; export const UPDATE_SNAPSHOT = (id: string) => `api/snapshot/${id}/update_entry`; export const ALL_PROJECTS = () => "api/projects/list"; export const ACTIVE_PROJECT = () => "api/projects/active"; @@ -23,7 +23,8 @@ export const GET_NODE = () => "execution/get_node"; export const ALL_GRAPHS = () => "execution/get_graphs"; export const GET_GRAPH = () => "execution/get_graph"; export const GET_WORKFLOW_GRAPH = () => "execution/get_graph/cytoscape"; -export const GET_EXECUTION_HISTORY = () => "execution/last_run/workflow/execution_history?reverse=true"; export const SUBMIT_NODE_RUN = () => "execution/submit/node"; export const SUBMIT_WORKFLOW_RUN = () => "execution/submit/workflow"; +export const GET_EXECUTION_HISTORY = () => "execution/last_run/workflow/execution_history?reverse=true"; export const GET_LAST_RUN = () => "execution/last_run/"; +export const GET_LAST_RUN_WORKFLOW_STATUS = () => "execution/last_run/workflow/status"; From 5783203b0a0f2429db529d5c4bc7e7c3cd038a34 Mon Sep 17 00:00:00 2001 From: Serwan Asaad Date: Wed, 11 Sep 2024 19:25:05 +0200 Subject: [PATCH 09/11] Feat: Make figures clickable --- frontend/src/modules/Data/index.tsx | 444 ++++++++++++++-------------- 1 file changed, 230 insertions(+), 214 deletions(-) diff --git a/frontend/src/modules/Data/index.tsx b/frontend/src/modules/Data/index.tsx index 3f00d036..3bf6ea65 100644 --- a/frontend/src/modules/Data/index.tsx +++ b/frontend/src/modules/Data/index.tsx @@ -12,238 +12,254 @@ import InputField from "../../DEPRECATED_components/common/Input/InputField"; import jp from "jsonpath"; const formatDateTime = (dateTime: string): string => { - const date = new Date(dateTime); - return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; + const date = new Date(dateTime); + return `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`; }; const TimelineGraph = ({ - allSnapshots, - selectedSnapshotIndex, - setSelectedSnapshotIndex, - setSelectedSnapshotId, - setFlag, - fetchOneGitgraphSnapshot, + allSnapshots, + selectedSnapshotIndex, + setSelectedSnapshotIndex, + setSelectedSnapshotId, + setFlag, + fetchOneGitgraphSnapshot, }: { - allSnapshots: SnapshotDTO[]; + allSnapshots: SnapshotDTO[]; - selectedSnapshotIndex: number | undefined; - setSelectedSnapshotIndex: Dispatch>; - setSelectedSnapshotId: Dispatch>; + selectedSnapshotIndex: number | undefined; + setSelectedSnapshotIndex: Dispatch>; + setSelectedSnapshotId: Dispatch>; - setFlag: Dispatch>; - fetchOneGitgraphSnapshot: (snapshots: SnapshotDTO[], selectedIndex: number) => void; + setFlag: Dispatch>; + fetchOneGitgraphSnapshot: (snapshots: SnapshotDTO[], selectedIndex: number) => void; }) => { - const withoutAuthor = templateExtend(TemplateName.Metro, { - commit: { - message: { - displayAuthor: false, - }, - spacing: 50, - }, - }); - - return ( - allSnapshots?.length > 0 && - selectedSnapshotIndex !== undefined && ( - - {(gitgraph) => { - const mainBranch = gitgraph.branch({ - name: "main", - style: { - color: "gray", - label: { - strokeColor: "gray", - }, - spacing: 0.5, - }, - commitDefaultOptions: { - style: { - color: "gray", - message: { - color: "#d9d5d4", - }, - }, + const withoutAuthor = templateExtend(TemplateName.Metro, { + commit: { + message: { + displayAuthor: false, }, - }); - - allSnapshots.map((snapshot: SnapshotDTO, index) => { - const snapshotId = snapshot?.id.toString(); - mainBranch.commit({ - hash: `#${snapshotId}`, - author: "", - body: formatDateTime(snapshot.created_at), - subject: snapshot.metadata?.name, - style: { - dot: { - color: selectedSnapshotIndex === index ? "#d9d5d4" : "gray", - }, - }, - onClick: () => { - setFlag(true); - setSelectedSnapshotIndex(index); - setSelectedSnapshotId(snapshot?.id); - fetchOneGitgraphSnapshot(allSnapshots, index); - }, - }); - }); - }} - - ) - ); + spacing: 50, + }, + }); + + return ( + allSnapshots?.length > 0 && + selectedSnapshotIndex !== undefined && ( + + {(gitgraph) => { + const mainBranch = gitgraph.branch({ + name: "main", + style: { + color: "gray", + label: { + strokeColor: "gray", + }, + spacing: 0.5, + }, + commitDefaultOptions: { + style: { + color: "gray", + message: { + color: "#d9d5d4", + }, + }, + }, + }); + + allSnapshots.map((snapshot: SnapshotDTO, index) => { + const snapshotId = snapshot?.id.toString(); + mainBranch.commit({ + hash: `#${snapshotId}`, + author: "", + body: formatDateTime(snapshot.created_at), + subject: snapshot.metadata?.name, + style: { + dot: { + color: selectedSnapshotIndex === index ? "#d9d5d4" : "gray", + }, + }, + onClick: () => { + setFlag(true); + setSelectedSnapshotIndex(index); + setSelectedSnapshotId(snapshot?.id); + fetchOneGitgraphSnapshot(allSnapshots, index); + }, + }); + }); + }} + + ) + ); }; export const JSONEditor = ({ title, jsonDataProp, height }: { title: string; jsonDataProp: object; height: string }) => { - const [searchTerm, setSearchTerm] = useState(""); - const [jsonData, setJsonData] = useState(jsonDataProp); - - useEffect(() => { - setJsonData(jsonDataProp); - }, [jsonDataProp]); - - const filterData = (data: object, term: string) => { - if (!term) return data; - - try { - // Convert search term to JSONPath query - const jsonPathQuery = term.replace("#", "$").replace(/\*/g, "*").replace(/\//g, "."); - - // Perform the JSONPath query - const result = jp.nodes(data, jsonPathQuery); - - // Reconstruct the filtered data structure - return result.reduce( - ( - acc: Record, - { - path, - value, - }: { - path: jp.PathComponent[]; - value: unknown; - } - ) => { - let current = acc; - for (let i = 1; i < path.length - 1; i++) { - const key = path[i] as string; - if (!current[key]) current[key] = {}; - current = current[key] as Record; - } - const lastKey = path[path.length - 1] as string; - current[lastKey] = value; - return acc; + const [searchTerm, setSearchTerm] = useState(""); + const [jsonData, setJsonData] = useState(jsonDataProp); + + useEffect(() => { + setJsonData(jsonDataProp); + }, [jsonDataProp]); + + const filterData = (data: object, term: string) => { + if (!term) return data; + + try { + // Convert search term to JSONPath query + const jsonPathQuery = term.replace("#", "$").replace(/\*/g, "*").replace(/\//g, "."); + + // Perform the JSONPath query + const result = jp.nodes(data, jsonPathQuery); + + // Reconstruct the filtered data structure + return result.reduce( + ( + acc: Record, + { + path, + value, + }: { + path: jp.PathComponent[]; + value: unknown; + } + ) => { + let current = acc; + for (let i = 1; i < path.length - 1; i++) { + const key = path[i] as string; + if (!current[key]) current[key] = {}; + current = current[key] as Record; + } + const lastKey = path[path.length - 1] as string; + current[lastKey] = value; + return acc; + }, + {} + ); + } catch (error) { + console.error("Invalid JSONPath query:", error); + return data; + } + }; + + const handleSearch = (_val: string, e: ChangeEvent) => { + setSearchTerm(e.target.value); + const filteredData = filterData(jsonDataProp, e.target.value); + setJsonData(filteredData); + }; + + const imageDataType = defineDataType({ + is: (value) => typeof value === "string" && value.startsWith("data:image"), + Component: ({ value }) => { + const handleImageClick = () => { + const win = window.open(); + win.document.write(``); + }; + + return ( +
+
+
+ {/* Use onClick to handle the image opening in a new window */} + + Base64 figure + +
+
+ ); }, - {} - ); - } catch (error) { - console.error("Invalid JSONPath query:", error); - return data; - } - }; - - const handleSearch = (_val: string, e: ChangeEvent) => { - setSearchTerm(e.target.value); - const filteredData = filterData(jsonDataProp, e.target.value); - setJsonData(filteredData); - }; - - const imageDataType = defineDataType({ - is: (value) => typeof value === "string" && value.startsWith("data:image"), - Component: ({ value }) => ( -
-
- {value -
- ), - }); - const handleOnSelect = async (path: Path) => { - let searchPath = "#"; - path.forEach((a) => { - searchPath += "/" + a; }); - setSearchTerm(searchPath); - const filteredData = filterData(jsonDataProp, searchPath); - await navigator.clipboard.writeText(searchPath); - setJsonData(filteredData); - }; - return ( -
-

{title}

- - handleSearch(event.target.value, event)}> - handleOnSelect(path)} - theme={"dark"} - value={jsonData} - valueTypes={[imageDataType]} - displayDataTypes={false} - defaultInspectDepth={3} - style={{ overflowY: "auto", height: "100%", paddingBottom: "15px" }} - /> -
- ); + const handleOnSelect = async (path: Path) => { + let searchPath = "#"; + path.forEach((a) => { + searchPath += "/" + a; + }); + setSearchTerm(searchPath); + const filteredData = filterData(jsonDataProp, searchPath); + await navigator.clipboard.writeText(searchPath); + setJsonData(filteredData); + }; + return ( +
+

{title}

+ + handleSearch(event.target.value, event)}> + handleOnSelect(path)} + theme={"dark"} + value={jsonData} + valueTypes={[imageDataType]} + displayDataTypes={false} + defaultInspectDepth={3} + style={{ overflowY: "auto", height: "100%", paddingBottom: "15px" }} + /> +
+ ); }; const DataGUAlibrate = () => { - const [ref] = useModuleStyle(); - const { - totalPages, - setPageNumber, - allSnapshots, - selectedSnapshotIndex, - setSelectedSnapshotIndex, - setSelectedSnapshotId, - jsonData, - diffData, - result, - setFlag, - fetchOneGitgraphSnapshot, - } = useSnapshotsContext(); - return ( -
-
-
-
- - -
-
- {result && } -
- {jsonData && !diffData && } - {jsonData && diffData && } - {jsonData && diffData && } -
+ const [ref] = useModuleStyle(); + const { + totalPages, + setPageNumber, + allSnapshots, + selectedSnapshotIndex, + setSelectedSnapshotIndex, + setSelectedSnapshotId, + jsonData, + diffData, + result, + setFlag, + fetchOneGitgraphSnapshot, + } = useSnapshotsContext(); + return ( +
+
+
+
+ + +
+
+ {result && } +
+ {jsonData && !diffData && } + {jsonData && diffData && } + {jsonData && diffData && } +
+
+
-
-
- ); + ); }; export default () => ( - - - + + + ); From 4337d881ebf959a2e47f60aa102a3754b842e58b Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Thu, 12 Sep 2024 11:12:04 +0200 Subject: [PATCH 10/11] Don't show Targets Name property on Node library page --- .../src/modules/common/Parameters/Parameters.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/src/modules/common/Parameters/Parameters.tsx b/frontend/src/modules/common/Parameters/Parameters.tsx index 708f815d..d5c2b081 100644 --- a/frontend/src/modules/common/Parameters/Parameters.tsx +++ b/frontend/src/modules/common/Parameters/Parameters.tsx @@ -60,12 +60,16 @@ export const Parameters: React.FC = ({
)} {expanded && - Object.entries(currentItem?.parameters ?? {}).map(([key, parameter]) => ( -
-
{parameter.title}:
-
{getInputElement(key, parameter, currentItem)}
-
- ))} + Object.entries(currentItem?.parameters ?? {}).map(([key, parameter]) => { + if (parameter.title.toLowerCase() !== "targets name") { + return ( +
+
{parameter.title}:
+
{getInputElement(key, parameter, currentItem)}
+
+ ); + } + })} ); }; From 4048074bb80dfbcd2a311fbf984939ed6cfff71d Mon Sep 17 00:00:00 2001 From: Aleksandar Manasijevic Date: Fri, 13 Sep 2024 12:03:08 +0200 Subject: [PATCH 11/11] Finishing some small issues on Graph Status page --- .../GraphLibrary/api/GraphLibraryApi.tsx | 9 ++++++++- .../GraphStatus/GraphStatus.module.scss | 1 + .../MeasurementElementGraph.module.scss | 5 +++-- .../MeasurementElementGraph.tsx | 19 +++++++++++++------ .../GraphLibrary/context/GraphContext.tsx | 14 +++++++++++++- .../modules/Nodes/context/NodesContext.tsx | 5 +++++ .../GlobalElementParameters.module.scss | 5 +++++ .../GlobalElementParameters.tsx | 6 +++--- 8 files changed, 51 insertions(+), 13 deletions(-) diff --git a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx index 56b8e338..000682e5 100644 --- a/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx +++ b/frontend/src/modules/GraphLibrary/api/GraphLibraryApi.tsx @@ -47,7 +47,14 @@ export class GraphLibraryApi extends Api { }); } - static fetchLastWorkflowStatus(): Promise> { + static fetchLastWorkflowStatus(): Promise< + Res<{ + active: boolean; + nodes_completed: number; + run_duration: number; + run_results: { parameters: { nodes: { [key: string]: string }[] } }; + }> + > { return this._fetch(this.api(GET_LAST_RUN_WORKFLOW_STATUS()), API_METHODS.GET, { headers: BASIC_HEADERS, }); diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss index 4146b4a9..7d8a7f70 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/GraphStatus.module.scss @@ -17,6 +17,7 @@ .upperContainer { color: rgb(217 213 212); + min-width: 33%; } .resultsContainer { diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss index 7ee11723..5057a5cb 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.module.scss @@ -28,6 +28,7 @@ .lowerContainer { height: 100%; + gap: 10px; } .lowerUpperContainer { @@ -39,11 +40,11 @@ } .lowerUpperLeftContainer { - width: 50%; + min-width: 50%; } .lowerUpperRightContainer { - width: 50%; + max-width: 50%; } .lowerLowerContainer { diff --git a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx index 790f4d9b..90aa6134 100644 --- a/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx +++ b/frontend/src/modules/GraphLibrary/components/GraphStatus/components/MeasurementElementGraph/MeasurementElementGraph.tsx @@ -3,7 +3,7 @@ import styles from "./MeasurementElementGraph.module.scss"; import CytoscapeGraph from "../../../CytoscapeGraph/CytoscapeGraph"; import cytoscape from "cytoscape"; import { useGraphContext } from "../../../../context/GraphContext"; -import { GlobalElementParameters } from "../../../../../common/GlobalElementParameters/GlobalElementParameters"; +import { CircularProgress } from "@mui/material"; interface IProps { workflowGraphElements: cytoscape.ElementDefinition[]; @@ -15,6 +15,13 @@ interface IProps { export const MeasurementElementGraph: React.FC = ({ workflowGraphElements }) => { const title = "Calibration Graph Progress"; const { lastRunInfo } = useGraphContext(); + // const graphProgressMessage = lastRunInfo?.nodesCompleted + // ? `${lastRunInfo?.nodesCompleted}/${lastRunInfo?.nodesTotal} node${lastRunInfo?.nodesCompleted > 1 ? "s" : ""} completed` + // : ""; + const graphProgressMessage = lastRunInfo?.nodesCompleted + ? `${lastRunInfo?.nodesCompleted} node${lastRunInfo?.nodesCompleted > 1 ? "s" : ""} completed` + : undefined; + const runDurationMessage = lastRunInfo?.runDuration ? `${lastRunInfo?.runDuration}s` : undefined; return (
{title}
@@ -22,13 +29,13 @@ export const MeasurementElementGraph: React.FC = ({ workflowGraphElement
-
Status: {lastRunInfo?.active ? "running" : "finished"}
-
Graph progress: {lastRunInfo?.nodesCompleted} nodes completed
-
Run duration: {lastRunInfo?.runDuration}
+
Status: {lastRunInfo?.active ? "running" : lastRunInfo?.status !== "error" ? "finished" : lastRunInfo.status}
+
Graph progress: {graphProgressMessage ?? }
+
Run duration: {runDurationMessage ?? }
- - + {/**/} + {/**/}
diff --git a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx index 9a59a3e2..ae1d9cd7 100644 --- a/frontend/src/modules/GraphLibrary/context/GraphContext.tsx +++ b/frontend/src/modules/GraphLibrary/context/GraphContext.tsx @@ -15,7 +15,10 @@ interface LastRunInfo { workflowName?: string; active?: boolean; nodesCompleted?: number; + nodesTotal?: number; runDuration?: number; + status?: string; + errorMessage?: string; } export interface GraphMap { @@ -72,8 +75,17 @@ export const GraphContextProvider = (props: GraphProviderProps): React.ReactElem if (lastRunResponse && lastRunResponse.isOk) { const lastRunResponseResult = lastRunResponse.result as StatusResponseType; if (lastRunResponseResult && lastRunResponseResult.status !== "error") { - setLastRunInfo({ workflowName: (lastRunResponse.result as { name: string }).name }); + setLastRunInfo({ + workflowName: (lastRunResponse.result as { name: string }).name, + nodesTotal: Object.keys((lastRunResponse.result as StatusResponseType)?.run_result?.parameters?.nodes ?? {}).length, + }); } else { + setLastRunInfo({ + workflowName: (lastRunResponse.result as { name: string }).name, + nodesTotal: Object.keys((lastRunResponse.result as StatusResponseType)?.run_result?.parameters?.nodes ?? {}).length, + status: "error", + errorMessage: JSON.stringify(lastRunResponse.error), + }); console.log("last run status was error"); } } else { diff --git a/frontend/src/modules/Nodes/context/NodesContext.tsx b/frontend/src/modules/Nodes/context/NodesContext.tsx index 52e851ed..59a4820e 100644 --- a/frontend/src/modules/Nodes/context/NodesContext.tsx +++ b/frontend/src/modules/Nodes/context/NodesContext.tsx @@ -76,6 +76,11 @@ export interface StatusResponseType { error?: NodeStatusError; name: string; state_updates?: StateUpdate; + run_result?: { + parameters?: { + nodes: { [key: string]: string }; + }; + }; } export function NodesContextProvider(props: NodesContextProviderProps): React.ReactElement { diff --git a/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss index 6307400b..3a2da8bf 100644 --- a/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss +++ b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.module.scss @@ -8,6 +8,7 @@ font-size: 16px; height: 25px; display: flex; + text-wrap: nowrap; } .sectionWrapper { @@ -15,6 +16,10 @@ padding-bottom: 5px; } +.textWrapper { + word-break: keep-all; +} + .arrowIconWrapper { margin-top: -3px; padding-right: 5px; diff --git a/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx index cdb9baa7..7dacdbc7 100644 --- a/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx +++ b/frontend/src/modules/common/GlobalElementParameters/GlobalElementParameters.tsx @@ -10,7 +10,7 @@ export const GlobalElementParameters: React.FC<{ const [expanded, setExpanded] = React.useState(true); return ( -
+ <>
{Object.entries(parameters ?? {}).map(([key, value]) => ( -
+
{key}: {value}
))}
)} -
+ ); };