From 647573943c597e6c89f58a2193d583b00e6d5f32 Mon Sep 17 00:00:00 2001
From: SystemsPurge <naktiyoussef@proton.me>
Date: Mon, 18 Nov 2024 11:03:02 +0100
Subject: [PATCH] Restored files edit dialog, rewrote into functional component

Signed-off-by: SystemsPurge <naktiyoussef@proton.me>
---
 src/pages/dashboards/dashboard.js             |  64 ++++--
 .../dashboards/dialogs/edit-files-dialog.js   | 192 ------------------
 .../dashboards/dialogs/edit-files-dialog.jsx  | 135 ++++++++++++
 src/pages/scenarios/scenario.js               |  94 +++++++--
 src/pages/scenarios/tables/configs-table.js   |   4 +-
 src/store/endpoints/file-endpoints.js         |   2 +-
 6 files changed, 269 insertions(+), 222 deletions(-)
 delete mode 100644 src/pages/dashboards/dialogs/edit-files-dialog.js
 create mode 100644 src/pages/dashboards/dialogs/edit-files-dialog.jsx

diff --git a/src/pages/dashboards/dashboard.js b/src/pages/dashboards/dashboard.js
index 5cffa1d..2839929 100644
--- a/src/pages/dashboards/dashboard.js
+++ b/src/pages/dashboards/dashboard.js
@@ -23,6 +23,7 @@ import classNames from 'classnames';
 import 'react-contexify/dist/ReactContexify.min.css';
 import EditWidget from './widget/edit-widget/edit-widget';
 import EditSignalMappingDialog from '../scenarios/dialogs/edit-signal-mapping'
+import EditFilesDialog from './dialogs/edit-files-dialog'
 import WidgetToolbox from './widget/widget-toolbox';
 import WidgetArea from './widget-area';
 import DashboardButtonGroup from './dashboard-button-group';
@@ -42,7 +43,9 @@ import {
   useLazyGetFilesQuery,
   useUpdateDashboardMutation,
   useGetICSQuery,
-  useLazyGetSignalsQuery
+  useLazyGetSignalsQuery,
+  useDeleteFileMutation,
+  useAddFileMutation
 } from '../../store/apiSlice';
 
 const startUpdaterWidgets = new Set(['Slider', 'Button', 'NumberInput']);
@@ -58,6 +61,8 @@ const Dashboard = ({ isFullscreen, toggleFullscreen }) => {
   const [triggerGetWidgets] = useLazyGetWidgetsQuery();
   const [triggerGetConfigs] = useLazyGetConfigsQuery();
   const [triggerGetFiles] = useLazyGetFilesQuery();
+  const [triggerDeleteFile] = useDeleteFileMutation();
+  const [triggerUploadFile] = useAddFileMutation();
   const [triggerGetSignals] = useLazyGetSignalsQuery();
   const [addWidget] = useAddWidgetMutation();
   const [updateWidget] = useUpdateWidgetMutation();
@@ -76,7 +81,6 @@ const Dashboard = ({ isFullscreen, toggleFullscreen }) => {
   const [editOutputSignalsModal, setEditOutputSignalsModal] = useState(false);
   const [editInputSignalsModal, setEditInputSignalsModal] = useState(false);
   const [filesEditModal, setFilesEditModal] = useState(false);
-  const [filesEditSaveState, setFilesEditSaveState] = useState([]);
   const [modalData, setModalData] = useState(null);
   const [modalIndex, setModalIndex] = useState(null);
   const [widgetChangeData, setWidgetChangeData] = useState([]);
@@ -247,6 +251,40 @@ const Dashboard = ({ isFullscreen, toggleFullscreen }) => {
     setModalIndex(index);
   };
 
+  const uploadFile = async (file) =>{
+    await triggerUploadFile({scenarioID:dashboard.scenarioID, file:file})
+    .then(async ()=>{
+      await triggerGetFiles(dashboard.scenarioID)
+        .then((fs)=>{
+            setFiles(fs.data.files)
+        })
+    })
+    .catch((e)=>{
+      console.log(`File upload failed: ${e}`)
+    })
+  }
+
+  const deleteFile = async (index) =>{
+    let file = files[index]
+    if(file !== undefined){
+      await triggerDeleteFile(file.id)
+      .then(async ()=>{
+        await triggerGetFiles(dashboard.scenarioID)
+        .then((fs)=>{
+            setFiles(fs.data.files)
+        })
+        .catch((e)=>{
+          console.log(`Error fetching files: ${e}`)
+        })
+      })
+      .catch((e)=>{
+        console.log(`Error deleting: ${e}`)
+      })
+     
+    }
+    
+  }
+
   const duplicateWidget = async (widget) => {
     let widgetCopy = { ...widget, id: undefined, x: widget.x + 50, y: widget.y + 50 };
     try {
@@ -262,13 +300,12 @@ const Dashboard = ({ isFullscreen, toggleFullscreen }) => {
   const startEditFiles = () => {
     let tempFiles = files.map(file => ({ id: file.id, name: file.name }));
     setFilesEditModal(true);
-    setFilesEditSaveState(tempFiles);
   };
 
   const closeEditFiles = () => {
     widgets.forEach(widget => {
       if (widget.type === "Image") {
-        //widget.customProperties.update = true;
+        widget.customProperties.update = true;
       }
     });
     setFilesEditModal(false);
@@ -531,16 +568,17 @@ const Dashboard = ({ isFullscreen, toggleFullscreen }) => {
           scenarioID={dashboard.scenarioID}
         />
 
-        {/* <EditFilesDialog
+        <EditFilesDialog
           key={"edit-files-dialog"}
-          sessionToken={this.state.sessionToken}
-          show={this.state.filesEditModal}
-          onClose={this.closeEditFiles.bind(this)}
-          signals={this.state.signals}
-          files={this.state.files}
-          scenarioID={this.state.dashboard.scenarioID}
-          locked={this.state.locked}
-        /> */}
+          sessionToken={sessionToken}
+          show={filesEditModal}
+          uploadFile={uploadFile}
+          deleteFile={deleteFile}
+          onClose={closeEditFiles}
+          files={files}
+          scenarioID={dashboard.scenarioID}
+          locked={locked}
+        /> 
 
         <EditSignalMappingDialog
           key={"edit-signal-mapping-input-dialog"}
diff --git a/src/pages/dashboards/dialogs/edit-files-dialog.js b/src/pages/dashboards/dialogs/edit-files-dialog.js
deleted file mode 100644
index 3eacda4..0000000
--- a/src/pages/dashboards/dialogs/edit-files-dialog.js
+++ /dev/null
@@ -1,192 +0,0 @@
-/**
- * This file is part of VILLASweb.
- *
- * VILLASweb is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * VILLASweb is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
-
-import React from 'react';
-import {Form, Button, Col, ProgressBar, Row} from 'react-bootstrap';
-import Dialog from '../../../common/dialogs/dialog';
-import { Table, ButtonColumn, DataColumn } from "../../../common/table";
-import EditFileContent from  "./edit-file-content";
-
-class EditFilesDialog extends React.Component {
-  valid = true;
-
-  constructor(props) {
-    super(props);
-
-    this.state = {
-      uploadFile: null,
-      uploadProgress: 0,
-      editModal: false,
-      modalFile: {}
-    };
-  }
-
-  onClose() {
-    this.props.onClose();
-  }
-
-  selectUploadFile(event) {
-    this.setState({ uploadFile: event.target.files[0] });
-  };
-
-  startFileUpload(){
-    // upload file
-    const formData = new FormData();
-    formData.append("file", this.state.uploadFile);
-
-    AppDispatcher.dispatch({
-      type: 'files/start-upload',
-      data: formData,
-      token: this.props.sessionToken,
-      progressCallback: this.updateUploadProgress,
-      finishedCallback: this.clearProgress,
-      scenarioID: this.props.scenarioID,
-    });
-
-    this.setState({ uploadFile: null });
-  };
-
-  updateUploadProgress = (event) => {
-    if (event.hasOwnProperty("percent")){
-      this.setState({ uploadProgress: parseInt(event.percent.toFixed(), 10) });
-    } else {
-      this.setState({ uploadProgress: 0 });
-    }
-  };
-
-  clearProgress = (newFileID) => {
-    this.setState({ uploadProgress: 0 });
-  };
-
-  closeEditModal() {
-    this.setState({editModal: false});
-  }
-
-  deleteFile(index){
-    let file = this.props.files[index]
-    AppDispatcher.dispatch({
-      type: 'files/start-remove',
-      data: file,
-      token: this.props.sessionToken
-    });
-  }
-
-  render() {
-    let fileOptions = [];
-    if (this.props.files.length > 0){
-      fileOptions.push(
-        <option key = {0} default>Select image file</option>
-        )
-      fileOptions.push(this.props.files.map((file, index) => (
-        <option key={index+1} value={file.id}>{file.name}</option>
-      )))
-    } else {
-      fileOptions = <option disabled value style={{ display: 'none' }}>No files found, please upload one first.</option>
-    }
-
-    const progressBarStyle = {
-      marginLeft: '100px',
-      marginTop: '-40px'
-    };
-
-    let title = this.props.locked ? "View files of scenario" : "Edit Files of Scenario";
-
-    return (
-      <Dialog
-        show={this.props.show}
-        title={title}
-        buttonTitle="Close"
-        onClose={() => this.onClose()}
-        blendOutCancel = {true}
-        valid={true}
-      >
-        <Table breakWord={true} data={this.props.files}>
-          <DataColumn
-            title='ID'
-            dataKey='id'
-            width={50}
-          />
-          <DataColumn
-            title='Name'
-            dataKey='name'
-          />
-          <DataColumn
-            title='Size (bytes)'
-            dataKey='size'
-          />
-          <DataColumn
-            title='Type'
-            dataKey='type'
-          />
-          <ButtonColumn
-            align='right'
-            deleteButton
-            onDelete={(index) => this.deleteFile(index)}
-            editButton
-            onEdit={index => this.setState({ editModal: true, modalFile: this.props.files[index] })}
-            locked={this.props.locked}
-          />
-        </Table>
-
-        <div style={{ float: 'center' }}>
-          <h5>Add file</h5>
-          <Row>
-            <Col xs lg="4">
-              <Form.Control
-                type='file'
-                onChange={(event) => this.selectUploadFile(event)}
-                disabled={this.props.locked}
-                />
-            </Col>
-            <Col xs lg="2">
-          <span className='solid-button'>
-            <Button
-              variant='secondary'
-              disabled={this.state.uploadFile === null || this.props.locked}
-              onClick={() => this.startFileUpload()}>
-              Upload
-          </Button>
-          </span>
-            </Col>
-          </Row>
-        </div>
-
-        <br />
-
-        <Form.Group as={Col} >
-          <ProgressBar
-            striped={true}
-            animated={true}
-            now={this.state.uploadProgress}
-            label={this.state.uploadProgress + '%'}
-          />
-        </Form.Group>
-
-        <div style={{ clear: 'both' }} />
-
-        <EditFileContent
-          show={this.state.editModal}
-          onClose={(data) => this.closeEditModal(data)}
-          sessionToken={this.props.sessionToken}
-          file={this.state.modalFile}
-        />
-      </Dialog>
-    );
-  }
-}
-
-export default EditFilesDialog;
\ No newline at end of file
diff --git a/src/pages/dashboards/dialogs/edit-files-dialog.jsx b/src/pages/dashboards/dialogs/edit-files-dialog.jsx
new file mode 100644
index 0000000..f6c8f7a
--- /dev/null
+++ b/src/pages/dashboards/dialogs/edit-files-dialog.jsx
@@ -0,0 +1,135 @@
+/**
+ * This file is part of VILLASweb.
+ *
+ * VILLASweb is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * VILLASweb is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
+ ******************************************************************************/
+
+import React, { useState } from 'react';
+import {Form, Button, Col, ProgressBar, Row} from 'react-bootstrap';
+import Dialog from '../../../common/dialogs/dialog';
+import { Table, ButtonColumn, DataColumn } from "../../../common/table";
+import EditFileContent from  "./edit-file-content";
+
+const EditFilesDialog = (props)=> {
+  const [uploadFile,setUploadFile] = useState(null)
+  const [uploadProgress,setUploadProgress] = useState(0)
+  const [editModal,setEditModal] = useState(false)
+  const [modalFile,setModalFile] = useState({})
+
+  const onClose = ()=>{
+    props.onClose();
+  }
+
+  const selectUploadFile = (e)=>{
+    setUploadFile(e.target.files[0])
+  };
+
+  const closeEditModal=()=> {
+    setEditModal(false)
+  }
+
+    let fileOptions = [];
+    if (props.files.length > 0){
+      fileOptions.push(
+        <option key = {0} default>Select image file</option>
+        )
+      fileOptions.push(props.files.map((file, index) => (
+        <option key={index+1} value={file.id}>{file.name}</option>
+      )))
+    } else {
+      fileOptions = <option disabled value style={{ display: 'none' }}>No files found, please upload one first.</option>
+    }
+
+
+    let title = props.locked ? "View files of scenario" : "Edit Files of Scenario";
+
+  return (
+    <Dialog
+      show={props.show}
+      title={title}
+      buttonTitle="Close"
+      onClose={() => onClose()}
+      blendOutCancel = {true}
+      valid={true}
+    >
+      <Table breakWord={true} data={props.files}>
+        <DataColumn
+          title='ID'
+          dataKey='id'
+          width={50}
+        />
+        <DataColumn
+          title='Name'
+          dataKey='name'
+        />
+        <DataColumn
+          title='Size (bytes)'
+          dataKey='size'
+        />
+        <DataColumn
+          title='Type'
+          dataKey='type'
+        />
+        <ButtonColumn
+          align='right'
+          deleteButton
+          onDelete={props.deleteFile}
+          editButton
+          onEdit={(index) => {
+              setEditModal(true)
+              setModalFile(props.files[index])
+          }
+          }
+          locked={props.locked}
+        />
+      </Table>
+
+      <div style={{ float: 'center' }}>
+        <h5>Add file</h5>
+        <Row>
+          <Col xs lg="4">
+            <Form.Control
+              type='file'
+              onChange={(event) => selectUploadFile(event)}
+              disabled={props.locked}
+              />
+          </Col>
+          <Col xs lg="2">
+        <span className='solid-button'>
+          <Button
+            variant='secondary'
+            disabled={uploadFile === null || props.locked}
+            onClick={()=>{props.uploadFile(uploadFile)}}>
+            Upload
+        </Button>
+        </span>
+          </Col>
+        </Row>
+      </div>
+
+      <br />
+
+      <div style={{ clear: 'both' }} />
+
+      <EditFileContent
+        show={editModal}
+        onClose={(data) => closeEditModal(data)}
+        sessionToken={props.sessionToken}
+        file={modalFile}
+      />
+    </Dialog>
+  );
+}
+
+export default EditFilesDialog;
\ No newline at end of file
diff --git a/src/pages/scenarios/scenario.js b/src/pages/scenarios/scenario.js
index ed63521..9317f18 100644
--- a/src/pages/scenarios/scenario.js
+++ b/src/pages/scenarios/scenario.js
@@ -23,18 +23,34 @@ import IconToggleButton from "../../common/buttons/icon-toggle-button";
 import ConfigsTable from "./tables/configs-table";
 import DashboardsTable from "./tables/dashboards-table";
 import ResultsTable from "./tables/results-table";
+import EditFilesDialog from '../dashboards/dialogs/edit-files-dialog'
 import UsersTable from "./tables/users-table";
-import {
+import { useEffect, useState } from "react";
+import { 
+  useGetDashboardQuery, 
+  useLazyGetWidgetsQuery, 
+  useLazyGetConfigsQuery, 
+  useAddWidgetMutation, 
+  useUpdateWidgetMutation, 
+  useDeleteWidgetMutation,
   useUpdateScenarioMutation,
+  useLazyGetFilesQuery,
+  useUpdateDashboardMutation,
   useGetICSQuery,
-} from "../../store/apiSlice";
+  useLazyGetSignalsQuery,
+  useDeleteFileMutation,
+  useAddFileMutation
+} from '../../store/apiSlice';
 
 const Scenario = (props) => {
     const params = useParams();
     const id = params.scenario;
-
+      const [triggerGetFiles] = useLazyGetFilesQuery();
+    const [triggerDeleteFile] = useDeleteFileMutation();
+    const [triggerUploadFile] = useAddFileMutation();
     const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth);
-
+    
+    const [filesEditModal, setFilesEditModal] = useState(false);
     const { data: fetchedScenarios, isLoading: isScenarioLoading, refetch: refetchScenario } = useGetScenarioByIdQuery(id);
     const scenario = fetchedScenarios?.scenario;
 
@@ -42,6 +58,8 @@ const Scenario = (props) => {
     const ics = fetchedICs?.ics;
 
     const [updateScenario, {isLoadingUpdate}] = useUpdateScenarioMutation();
+    const [files, setFiles] = useState([]);
+    const [locked, setLocked] = useState(false);
 
     const buttonStyle = {
         marginLeft: '10px',
@@ -52,6 +70,53 @@ const Scenario = (props) => {
         width: '30px'
     }
 
+    useEffect(async ()=>{
+      
+      await triggerGetFiles(id)
+        .then((fs)=>{
+            setFiles(fs.data.files)
+        })
+      
+    },[])
+
+    const uploadFile = async (file) =>{
+      await triggerUploadFile({scenarioID:id, file:file})
+      .then(async ()=>{
+        await triggerGetFiles(id)
+          .then((fs)=>{
+              setFiles(fs.data.files)
+          })
+      })
+      .catch((e)=>{
+        console.log(`File upload failed: ${e}`)
+      })
+    }
+  
+    const deleteFile = async (index) =>{
+      let file = files[index]
+      if(file !== undefined){
+        await triggerDeleteFile(file.id)
+        .then(async ()=>{
+          await triggerGetFiles(id)
+          .then((fs)=>{
+              setFiles(fs.data.files)
+          })
+          .catch((e)=>{
+            console.log(`Error fetching files: ${e}`)
+          })
+        })
+        .catch((e)=>{
+          console.log(`Error deleting: ${e}`)
+        })
+       
+      }
+      
+    }
+  
+    const closeEditFiles = () => {
+      setFilesEditModal(false);
+    };
+
     const onScenarioLock = async (index) => {
       try{
         const data = {...scenario};
@@ -74,7 +139,7 @@ const Scenario = (props) => {
           <IconButton
             childKey="0"
             tooltip={tooltip}
-            onClick={() => console.log("click")}
+            onClick={() => {setFilesEditModal(true)}}
             icon="file"
             buttonStyle={buttonStyle}
             iconStyle={iconStyle}
@@ -99,20 +164,23 @@ const Scenario = (props) => {
               </span>
           </h1>
   
-        {/* <EditFilesDialog
+          <EditFilesDialog
+          key={"edit-files-dialog"}
           sessionToken={sessionToken}
-          show={false}
-          onClose={null}
-          signals={null}
-          files={[]}
-          scenarioID={scenario.id}
-          locked={scenario.isLocked}
-        /> */}
+          show={filesEditModal}
+          uploadFile={uploadFile}
+          deleteFile={deleteFile}
+          onClose={closeEditFiles}
+          files={files}
+          scenarioID={id}
+          locked={locked}
+        /> 
   
         { areICsLoading?
           <div>isLoading...</div>
           :
             <ConfigsTable
+              files={files}
               ics={ics}
               scenario={scenario}
             />
diff --git a/src/pages/scenarios/tables/configs-table.js b/src/pages/scenarios/tables/configs-table.js
index 7e9c63f..62574ec 100644
--- a/src/pages/scenarios/tables/configs-table.js
+++ b/src/pages/scenarios/tables/configs-table.js
@@ -39,7 +39,7 @@ import {
 } from "../../../store/apiSlice";
 import ConfigActionBoard from "./config-action-board";
 
-const ConfigsTable = ({scenario, ics}) => {
+const ConfigsTable = ({scenario, ics,files}) => {
     const {data, refetch: refetchConfigs } = useGetConfigsQuery(scenario.id);
     const [addComponentConfig] = useAddComponentConfigMutation();
     const [updateComponentConfig] = useUpdateComponentConfigMutation();
@@ -49,8 +49,6 @@ const ConfigsTable = ({scenario, ics}) => {
 
     const configs = data ? data.configs : [];
     const [signals, setSignals] = useState({});
-    const {data: filesData } = useGetFilesQuery(scenario.id);
-    const files = filesData ? filesData.files : [];
 
     const [isNewModalOpened, setIsNewModalOpened] = useState(false);
     const [isEditModalOpened, setIsEditModalOpened] = useState(false);
diff --git a/src/store/endpoints/file-endpoints.js b/src/store/endpoints/file-endpoints.js
index 765c03f..118a68c 100644
--- a/src/store/endpoints/file-endpoints.js
+++ b/src/store/endpoints/file-endpoints.js
@@ -25,7 +25,7 @@ export const fileEndpoints = (builder) => ({
     addFile: builder.mutation({
       query: ({ scenarioID, file }) => {
         const formData = new FormData();
-        formData.append('inputFile', file);
+        formData.append('file', file);
         return {
           url: `files?scenarioID=${scenarioID}`,
           method: 'POST',