diff --git a/src/pages/dashboards/widget/widgets/icstatus.jsx b/src/pages/dashboards/widget/widgets/icstatus.jsx
index 84ba116..94af01a 100644
--- a/src/pages/dashboards/widget/widgets/icstatus.jsx
+++ b/src/pages/dashboards/widget/widgets/icstatus.jsx
@@ -22,13 +22,11 @@ import { loadICbyId } from "../../../../store/icSlice";
import { sessionToken } from "../../../../localStorage";
import { useDispatch } from "react-redux";
+let timer = null
const WidgetICstatus = (props) => {
const dispatch = useDispatch()
const [ics,setIcs] = useState(props.ics)
-
- useEffect(() => {
- // Function to refresh data
- const refresh = async() => {
+ const refresh = async() => {
if (props.ics) {
let iccs = [];
for(let ic of props.ics){
@@ -38,10 +36,11 @@ const WidgetICstatus = (props) => {
setIcs(iccs)
}
};
+ useEffect(() => {
+ window.clearInterval(timer)
+ timer = window.setInterval(refresh,3000)
+ // Function to refresh data
refresh()
- // Start timer for periodic refresh
- const timer = window.setInterval(() => refresh(), 3000);
-
// Cleanup function equivalent to componentWillUnmount
return () => {
window.clearInterval(timer);
diff --git a/src/pages/dashboards/widget/widgets/player.jsx b/src/pages/dashboards/widget/widgets/player.jsx
index 14923a5..d0378a9 100644
--- a/src/pages/dashboards/widget/widgets/player.jsx
+++ b/src/pages/dashboards/widget/widgets/player.jsx
@@ -14,9 +14,9 @@
* You should have received a copy of the GNU General Public License
* along with VILLASweb. If not, see .
******************************************************************************/
-
+import JSZip from 'jszip';
import React, { useState, useEffect } from 'react';
-import { Container, Row, Col } from 'react-bootstrap';
+import { Container, Row, Col,Form } from 'react-bootstrap';
import {sendActionToIC,loadICbyId} from "../../../../store/icSlice";
import { sessionToken } from '../../../../localStorage';
import IconButton from '../../../../common/buttons/icon-button';
@@ -25,20 +25,21 @@ import ParametersEditor from '../../../../common/parameters-editor';
import ResultPythonDialog from '../../../scenarios/dialogs/result-python-dialog';
import { playerMachine } from '../widget-player/player-machine';
import { interpret } from 'xstate';
-import { useSendActionMutation, useLazyDownloadFileQuery, useGetResultsQuery, useGetFilesQuery } from '../../../../store/apiSlice';
+import { useAddResultMutation, useLazyDownloadFileQuery, useGetResultsQuery, useGetFilesQuery } from '../../../../store/apiSlice';
import notificationsDataManager from '../../../../common/data-managers/notifications-data-manager';
import NotificationsFactory from '../../../../common/data-managers/notifications-factory';
import { start } from 'xstate/lib/actions';
+import FileSaver from "file-saver";
import { useDispatch } from 'react-redux';
const WidgetPlayer = (
{widget, editing, configs, onStarted, ics, results, files, scenarioID}) => {
const dispatch = useDispatch()
+ const zip = new JSZip()
const [triggerDownloadFile] = useLazyDownloadFileQuery();
const {refetch: refetchResults} = useGetResultsQuery(scenarioID);
const {refetch: refetchFiles} = useGetFilesQuery(scenarioID);
-
-
+ const [addResult, {isError: isErrorAddingResult}] = useAddResultMutation();
const [playerState, setPlayerState] = useState(playerMachine.initialState);
const [configID, setConfigID] = useState(-1);
const [config, setConfig] = useState({});
@@ -109,7 +110,9 @@ const WidgetPlayer = (
case 'stopping': // if configured, show results
if (isUploadResultsChecked) {
refetchResults();
- refetchFiles();
+ refetchFiles().then(v=>{
+ setFilesToDownload(v.data.files)
+ });
}
newState = transitionState(playerState, 'FINISH')
setPlayerState(newState);
@@ -133,11 +136,24 @@ const WidgetPlayer = (
}
const clickStart = async () => {
- const startConfig = { ...config };
- startConfig.startParameters = startParameters;
-
try {
- dispatch(sendActionToIC({token:sessionToken,id:config.icID,actions:[{action:"start",when:Math.round((new Date()).getTime() / 1000),parameters:{...config.startParameters}}]}))
+ let pld = {action:"start",when:Math.round((new Date()).getTime() / 1000),parameters:{...config.startParameters}}
+ if(isUploadResultsChecked){
+ addResult({result: {
+ scenarioID: scenarioID
+ }})
+ .then(v=>{
+ pld.results = {
+ url: `https://slew.k8s.eonerc.rwth-aachen.de/api/v2/results/${v.data.result.id}/file`,
+ type: "url",
+ token: sessionToken
+ }
+ dispatch(sendActionToIC({token:sessionToken,id:config.icID,actions:[pld]}))
+ })
+ .catch(e=>{
+ notificationsDataManager.addNotification(NotificationsFactory.LOAD_ERROR(e.toString()));
+ })
+ }
//sendAction({ icid: startConfig.icID, action: "start", when: Math.round((new Date()).getTime() / 1000), parameters: {...startParameters } }).unwrap();
} catch(error) {
notificationsDataManager.addNotification(NotificationsFactory.LOAD_ERROR(error?.data?.message));
@@ -175,18 +191,28 @@ const WidgetPlayer = (
}
setFilesToDownload(toDownload);
-
}
const handleDownloadFile = async (fileID) => {
- try {
- const res = await triggerDownloadFile(fileID);
- const file = files.find(f => f.id === fileID);
- const blob = new Blob([res], { type: 'application/octet-stream' });
+ triggerDownloadFile(fileID)
+ .then(v=>{
+ console.log(filesToDownload)
+ const file = filesToDownload.find(f => f.id === fileID);
+ const blob = new Blob([v.data], { type: 'application/octet-stream' });
zip.file(file.name, blob);
- } catch (error) {
- notificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR(error?.data?.message));
- }
+ zip.generateAsync({ type: 'blob' })
+ .then((content) => {
+ FileSaver.saveAs(content, `result-${file.id}.zip`);
+ })
+ .catch((err) => {
+ notificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR('Failed to create ZIP archive'));
+ console.error('Failed to create ZIP archive', err);
+ });
+ })
+ .catch(e=>{
+ notificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR(e));
+ })
+
}
const openPythonDialog = () => {
@@ -255,10 +281,21 @@ const WidgetPlayer = (
+
+
+
+ setIsUploadResultsChecked(prevState => !prevState)}
+ />
+
+
+
{isUploadResultsChecked ?
-
Results
@@ -266,7 +303,7 @@ const WidgetPlayer = (
childKey={0}
onClick={() => openPythonDialog()}
icon={['fab', 'python']}
- disabled={(playerState && playerState.matches('finished')) ? false : true}
+ disabled={(playerState && playerState.matches('finished')&& isUploadResultsChecked) ? false : true}
iconStyle={iconStyle}
/>
@@ -277,7 +314,7 @@ const WidgetPlayer = (
childKey={1}
onClick={() => downloadResultFiles()}
icon='file-download'
- disabled={(playerState && playerState.matches('finished')) ? false : true}
+ disabled={(playerState && playerState.matches('finished') ) ? false : true}
iconStyle={iconStyle}
/>
diff --git a/src/pages/scenarios/dialogs/result-python-dialog.js b/src/pages/scenarios/dialogs/result-python-dialog.js
index 3042ffd..f86b53a 100644
--- a/src/pages/scenarios/dialogs/result-python-dialog.js
+++ b/src/pages/scenarios/dialogs/result-python-dialog.js
@@ -105,7 +105,7 @@ class ResultPythonDialog extends React.Component {
code_snippets.push(code_imports)
/* Result object */
- code_snippets.push(`r = Result(${result.id}, '${token}')`);
+ code_snippets.push(`r = Result(${result.id}, '${token}', endpoint='https://slew.k8s.eonerc.rwth-aachen.de')`);
/* Examples */
code_snippets.push(`# Get result metadata
diff --git a/src/pages/scenarios/tables/config-action-board.js b/src/pages/scenarios/tables/config-action-board.js
index d524fb7..38170a2 100644
--- a/src/pages/scenarios/tables/config-action-board.js
+++ b/src/pages/scenarios/tables/config-action-board.js
@@ -20,7 +20,6 @@ import DateTimePicker from 'react-datetime-picker';
import ActionBoardButtonGroup from '../../../common/buttons/action-board-button-group';
import classNames from 'classnames';
import { useState } from 'react';
-import { useSelector, useDispatch } from 'react-redux';
import { sessionToken } from '../../../localStorage';
import { useSendActionMutation, useAddResultMutation, useLazyGetSignalsQuery, useGetResultsQuery } from '../../../store/apiSlice';
import NotificationsFactory from "../../../common/data-managers/notifications-factory";
@@ -83,7 +82,6 @@ const ConfigActionBoard = ({selectedConfigs, scenarioID}) => {
const res = await addResult({result: newResult}).unwrap();
if(!isErrorAddingResult){
- console.log("result", res)
const url = window.location.origin;
action.results = {
url: `https://slew.k8s.eonerc.rwth-aachen.de/api/v2/results/${res.result.id}/file`,