-
- {!runningUpdate && !parameterUpdated && (
-
{
- if (
- runningNodeInfo &&
- runningNodeInfo.idx &&
- stateUpdateObject &&
- ("val" in stateUpdateObject || "new" in stateUpdateObject)
- ) {
- setRunningUpdate(true);
- const response = await SnapshotsApi.updateState(
- runningNodeInfo?.idx,
- key,
- (stateUpdateObject.val ? stateUpdateObject.val : stateUpdateObject.new!).toString()
- );
- setRunningUpdate(false);
- if (response.isOk) {
- setParameterUpdated(response.result!);
- } else {
- setParameterUpdated(response.result!); //TODO Check this
- }
- }
- }}
- >
-
-
- )}
-
- {runningUpdate && !parameterUpdated && }
- {!runningUpdate && parameterUpdated && }
-
-
-
-
{stateUpdateObject?.key ? stateUpdateObject?.key.toString() : key.toString()}
-
- {stateUpdateObject && (
+ return (
+
- {stateUpdateObject.old}
-
- {renderSuggestedValue(stateUpdateObject.val ?? stateUpdateObject.new ?? "")}
+ {!runningUpdate && !parameterUpdated && (
+
{
+ if (
+ runningNodeInfo &&
+ runningNodeInfo.idx &&
+ stateUpdateObject &&
+ ("val" in stateUpdateObject || "new" in stateUpdateObject)
+ ) {
+ setRunningUpdate(true);
+ const stateUpdateValue = customValue ? customValue : stateUpdateObject.val ?? stateUpdateObject.new!;
+ const response = await SnapshotsApi.updateState(runningNodeInfo?.idx, key, stateUpdateValue.toString());
+ if (response.isOk) {
+ setParameterUpdated(response.result!);
+ } else {
+ setParameterUpdated(response.result!); //TODO Check this
+ }
+ setRunningUpdate(false);
+ }
+ }}
+ >
+
+
+ )}
+
+ {runningUpdate && !parameterUpdated && }
+ {!runningUpdate && parameterUpdated && }
+
+
+
+
{stateUpdateObject?.key ? stateUpdateObject?.key.toString() : key.toString()}
+
+ {stateUpdateObject && (
+
+ {stateUpdateObject.old}
+
+ {renderSuggestedValue(stateUpdateObject.val ?? stateUpdateObject.new ?? "")}
+
{
+ setEditMode(true);
+ setCustomValue(stateUpdateObject.val ?? stateUpdateObject.new);
+ }}
+ >
+ {!editMode && }
+
+ {editMode && (
+
{
+ setCustomValue(val);
+ }}
+ />
+ )}
+
+ )}
+
- )}
-
-
- );
+ );
};
const GetStateUpdates: React.FC<{
- runningNodeInfo: RunningNodeInfo | undefined;
+ runningNodeInfo: RunningNodeInfo | undefined;
}> = (props) => {
- const { runningNodeInfo } = props;
- return (
- <>
- {runningNodeInfo?.state_updates &&
State updates:
}
- {runningNodeInfo?.state_updates && (
-
- {Object.entries(runningNodeInfo?.state_updates ?? {}).map(([key, stateUpdateObject]) =>
- StateUpdateComponent({
- key,
- stateUpdateObject,
- runningNodeInfo,
- } as StateUpdateComponentProps)
- )}
-
- )}
- >
- );
+ const { runningNodeInfo } = props;
+ return (
+ <>
+ {runningNodeInfo?.state_updates &&
State updates:
}
+ {runningNodeInfo?.state_updates && (
+
+ {Object.entries(runningNodeInfo?.state_updates ?? {}).map(([key, stateUpdateObject]) =>
+ StateUpdateComponent({
+ key,
+ stateUpdateObject,
+ runningNodeInfo,
+ } as StateUpdateComponentProps)
+ )}
+
+ )}
+ >
+ );
};
const NodeStatusErrorWrapper: React.FC<{
- runningNodeInfo: RunningNodeInfo | undefined;
+ runningNodeInfo: RunningNodeInfo | undefined;
}> = (props) => {
- const { runningNodeInfo } = props;
- return (
- <>
- {runningNodeInfo?.error &&
Error traceback:
}
-
- {(runningNodeInfo?.error?.traceback ?? []).map((row, index) => (
-
- {row}
-
- ))}
-
- >
- );
+ const { runningNodeInfo } = props;
+ let errorMessage = runningNodeInfo?.error?.error_class;
+ if (errorMessage) {
+ errorMessage += ": ";
+ }
+ if (runningNodeInfo?.error?.message) {
+ errorMessage += runningNodeInfo?.error?.message;
+ }
+
+ return (
+ <>
+ {/*{runningNodeInfo?.error &&
Error traceback:
}*/}
+
+ {runningNodeInfo?.error?.error_class &&
Error occurred:
}
+
{errorMessage}
+ {runningNodeInfo?.error?.traceback?.length && runningNodeInfo?.error?.traceback?.length > 0 &&
Error traceback:
}
+ {(runningNodeInfo?.error?.traceback ?? []).map((row, index) => (
+
+ {row}
+
+ ))}
+
+ >
+ );
};
export const RunningJob: React.FC = () => {
- const { runningNode, runningNodeInfo } = useNodesContext();
+ const { runningNode, runningNodeInfo, isNodeRunning, setIsNodeRunning } = useNodesContext();
- const getRunningJobInfo = () => {
- return (
-
- {runningNodeInfo?.lastRunNodeName && (
-
Last run node: {runningNodeInfo?.lastRunNodeName}
- )}
- {runningNodeInfo?.timestampOfRun && (
-
Run start: {runningNodeInfo?.timestampOfRun}
- )}
- {runningNodeInfo?.runDuration && (
-
Run duration: {runningNodeInfo?.runDuration} seconds
- )}
- {runningNodeInfo?.status &&
Status: {runningNodeInfo?.status}
}
- {runningNodeInfo?.idx &&
idx: {runningNodeInfo?.idx}
}
-
- );
- };
+ const getRunningJobInfo = () => {
+ return (
+
+ {runningNodeInfo?.lastRunNodeName && (
+
Last run node: {runningNodeInfo?.lastRunNodeName}
+ )}
+ {runningNodeInfo?.timestampOfRun && (
+
Run start: {runningNodeInfo?.timestampOfRun}
+ )}
+ {runningNodeInfo?.runDuration && (
+
Run duration: {runningNodeInfo?.runDuration} seconds
+ )}
+ {runningNodeInfo?.status &&
Status: {runningNodeInfo?.status}
}
+ {runningNodeInfo?.idx &&
idx: {runningNodeInfo?.idx}
}
+
+ );
+ };
+
+ const getRunningJobParameters = () => {
+ return (
+ <>
+ {Object.entries(runningNode?.parameters ?? {}).length > 0 && (
+
+
+ {/*
setExpanded(!expanded)}>*/}
+ {/*
*/}
+ {/*
*/}
+ Parameters:
+
+
+ {
+ // expanded &&
+ Object.entries(runningNode?.parameters ?? {}).map(([key, parameter]) => (
+
+
{parameter.title}:
+
{parameter.default?.toString()}
+
+ ))
+ }
+
+
+ )}
+ >
+ );
+ };
+ const insertSpaces = (str: string, interval = 40) => {
+ let result = "";
+ for (let i = 0; i < str.length; i += interval) {
+ result += str.slice(i, i + interval) + " ";
+ }
+ return result.trim();
+ };
+
+ const handleStopClick = () => {
+ SnapshotsApi.stopNodeRunning().then((res) => {
+ if (res.isOk) {
+ setIsNodeRunning(!res.result);
+ }
+ });
+ };
- const getRunningJobParameters = () => {
return (
- <>
- {Object.entries(runningNode?.parameters ?? {}).length > 0 && (
-
-
- {/*
setExpanded(!expanded)}>*/}
- {/*
*/}
- {/*
*/}
- Parameters:
-
-
- {
- // expanded &&
- Object.entries(runningNode?.parameters ?? {}).map(([key, parameter]) => (
-
-
{parameter.title}:
-
{parameter.default?.toString()}
-
- ))
- }
+
+
+
+
+ Running job {runningNode?.name ? ":" : ""} {runningNode?.name ? insertSpaces(runningNode?.name) : ""}
+
+ {isNodeRunning && (
+
+
+ Stop
+
+
+ )}
-
- )}
- >
- );
- };
-
- return (
-
-
-
- Running job {runningNode?.name ? ":" : ""} {runningNode?.name ?? ""}
-
- {runningNodeInfo && (
-
- {getRunningJobInfo()}
- {getRunningJobParameters()}
+ {runningNodeInfo && (
+
+ {getRunningJobInfo()}
+ {getRunningJobParameters()}
+
+ )}
+
+
- )}
-
-
-
- );
+ );
};
diff --git a/frontend/src/modules/Nodes/context/NodesContext.tsx b/frontend/src/modules/Nodes/context/NodesContext.tsx
index 98da1440..166b0903 100644
--- a/frontend/src/modules/Nodes/context/NodesContext.tsx
+++ b/frontend/src/modules/Nodes/context/NodesContext.tsx
@@ -60,13 +60,17 @@ interface NodesContextProviderProps {
children: React.JSX.Element;
}
-interface NodeStatusError {
+export interface NodeStatusError {
error_class: string;
message: string;
- traceback: string[];
+ traceback?: string[];
}
-interface NodeStatusResponseType {
+export interface NodeStatusErrorWithDetails {
+ detail: { msg: string; type: string }[];
+}
+
+export interface NodeStatusResponseType {
idx: number;
status: string;
error?: NodeStatusError;
@@ -154,6 +158,12 @@ export function NodesContextProvider(props: NodesContextProviderProps): React.Re
useEffect(() => {
if (!isNodeRunning) {
fetchNodeResults();
+ if (runningNodeInfo?.status === "running") {
+ setRunningNodeInfo({
+ ...runningNodeInfo,
+ status: "finished",
+ });
+ }
}
}, [isNodeRunning]);
diff --git a/frontend/src/modules/Snapshots/api/SnapshotsApi.tsx b/frontend/src/modules/Snapshots/api/SnapshotsApi.tsx
index 6ec56c99..b1cd75aa 100644
--- a/frontend/src/modules/Snapshots/api/SnapshotsApi.tsx
+++ b/frontend/src/modules/Snapshots/api/SnapshotsApi.tsx
@@ -1,61 +1,70 @@
-import Api, {BASIC_HEADERS} from "../../../utils/api";
-import {Res} from "../../../common/interfaces/Api";
+import Api, { BASIC_HEADERS } from "../../../utils/api";
+import { Res } from "../../../common/interfaces/Api";
import {
ALL_SNAPSHOTS,
ONE_SNAPSHOT,
SNAPSHOT_DIFF,
SNAPSHOT_RESULT,
- UPDATE_SNAPSHOT
+ STOP_NODE_RUNNING,
+ UPDATE_SNAPSHOT,
} from "../../../utils/api/apiRoutes";
-import {API_METHODS} from "../../../common/enums/Api";
-import {SnapshotDTO} from "../SnapshotDTO";
+import { API_METHODS } from "../../../common/enums/Api";
+import { SnapshotDTO } from "../SnapshotDTO";
export interface SnapshotResult {
- items: SnapshotDTO[];
- per_page: number;
- page: number;
- total_items: number;
- total_pages: number;
+ items: SnapshotDTO[];
+ per_page: number;
+ page: number;
+ total_items: number;
+ total_pages: number;
}
export class SnapshotsApi extends Api {
- constructor() {
- super();
- }
-
- static api(path: string): string {
- return this.address + path;
- }
-
- static fetchAllSnapshots(pageNumber: number): Promise
> {
- return this._fetch(this.api(ALL_SNAPSHOTS({pageNumber})), API_METHODS.GET, {
- headers: BASIC_HEADERS,
- });
- }
-
- static fetchSnapshot(id: string): Promise> {
- return this._fetch(this.api(ONE_SNAPSHOT(id)), API_METHODS.GET, {
- headers: BASIC_HEADERS,
- });
- }
-
- static fetchSnapshotResult(id: string): Promise> {
- return this._fetch(this.api(SNAPSHOT_RESULT(id)), API_METHODS.GET, {
- headers: BASIC_HEADERS,
- });
- }
-
- static fetchSnapshotUpdate(currentId: string, newId: string): Promise> {
- return this._fetch(this.api(SNAPSHOT_DIFF(currentId, newId)), API_METHODS.GET, {
- headers: BASIC_HEADERS,
- });
- }
-
- static updateState(snapshotId: string, data_path: string, value: string): Promise> {
- return this._fetch(this.api(UPDATE_SNAPSHOT(snapshotId)), API_METHODS.POST, {
- headers: BASIC_HEADERS,
- body: JSON.stringify({data_path, value}),
- queryParams: {data_path, value},
- });
- }
+ constructor() {
+ super();
+ }
+
+ static api(path: string): string {
+ return this.address + path;
+ }
+
+ static fetchAllSnapshots(pageNumber: number): Promise> {
+ return this._fetch(this.api(ALL_SNAPSHOTS({ pageNumber })), API_METHODS.GET, {
+ headers: BASIC_HEADERS,
+ });
+ }
+
+ static fetchSnapshot(id: string): Promise> {
+ return this._fetch(this.api(ONE_SNAPSHOT(id)), API_METHODS.GET, {
+ headers: BASIC_HEADERS,
+ });
+ }
+
+ static fetchSnapshotResult(id: string): Promise> {
+ return this._fetch(this.api(SNAPSHOT_RESULT(id)), API_METHODS.GET, {
+ headers: BASIC_HEADERS,
+ });
+ }
+
+ static fetchSnapshotUpdate(currentId: string, newId: string): Promise> {
+ return this._fetch(this.api(SNAPSHOT_DIFF(currentId, newId)), API_METHODS.GET, {
+ headers: BASIC_HEADERS,
+ });
+ }
+
+ static updateState(snapshotId: string, data_path: string, value: string): Promise> {
+ return this._fetch(this.api(UPDATE_SNAPSHOT(snapshotId)), API_METHODS.POST, {
+ headers: BASIC_HEADERS,
+ body: JSON.stringify({ data_path, value }),
+ queryParams: { data_path, value },
+ });
+ }
+
+ static stopNodeRunning(): Promise> {
+ return this._fetch(this.api(STOP_NODE_RUNNING()), API_METHODS.POST, {
+ headers: BASIC_HEADERS,
+ // body: JSON.stringify({ data_path, value }),
+ // queryParams: { data_path, value },
+ });
+ }
}
diff --git a/frontend/src/ui-lib/Icons/EditIcon.tsx b/frontend/src/ui-lib/Icons/EditIcon.tsx
index 9157f6b1..02680d88 100644
--- a/frontend/src/ui-lib/Icons/EditIcon.tsx
+++ b/frontend/src/ui-lib/Icons/EditIcon.tsx
@@ -1,17 +1,28 @@
-import { ACTIVE_TEXT } from "../../utils/colors";
import { IconProps } from "../../common/interfaces/IconProps";
import React from "react";
-export const EditIcon: React.FunctionComponent = ({ width = 24, height = 24, color = ACTIVE_TEXT }) => (
-