diff --git a/backend/app/internal/flowsheet_manager.py b/backend/app/internal/flowsheet_manager.py
index ea815daa..b3468771 100644
--- a/backend/app/internal/flowsheet_manager.py
+++ b/backend/app/internal/flowsheet_manager.py
@@ -2,6 +2,8 @@
import sys
import types
from xml.etree.ElementTree import QName
+import os
+import importlib
if sys.version_info < (3, 10):
from importlib_resources import files
@@ -74,6 +76,10 @@ def __init__(self, **kwargs):
self.app_settings = AppSettings(**kwargs)
self._objs, self._flowsheets = {}, {}
+ # Add custom flowsheets path to the system path
+ self.custom_flowsheets_path = Path.home() / ".watertap" / "custom_flowsheets"
+ sys.path.append(str(self.custom_flowsheets_path))
+
for package in self.app_settings.packages:
_log.debug(f"Collect flowsheet interfaces from package '{package}'")
for name, fsi in self._get_flowsheet_interfaces(package).items():
@@ -395,15 +401,71 @@ def _get_flowsheet_interfaces(
return interfaces
+ def add_custom_flowsheet(self, new_files, new_id):
+ """Add new custom flowsheet to the mini db."""
+
+ query = tinydb.Query()
+ try:
+ custom_flowsheets_dict = self._histdb.search(query.fragment({"custom_flowsheets_version": VERSION}))
+ if(len(custom_flowsheets_dict) == 0):
+ _log.error('unable to find custom flowsheets dictionary')
+ custom_flowsheets_dict = {}
+ else:
+ custom_flowsheets_dict = custom_flowsheets_dict[0]["custom_flowsheets_dict"]
+ except Exception as e:
+ _log.error(f'error trying to find custom flowsheets dictionary: {e}')
+ _log.error(f'setting it as empty dictionary')
+ custom_flowsheets_dict = {}
+ custom_flowsheets_dict[new_id] = new_files
+
+ self._histdb.upsert(
+ {"custom_flowsheets_version": VERSION, "custom_flowsheets_dict": custom_flowsheets_dict},
+ (query.custom_flowsheets_version == VERSION),
+ )
+
+ self.add_custom_flowsheets()
+
+ def remove_custom_flowsheet(self, id_):
+ """Remove a custom flowsheet from the mini db."""
+ query = tinydb.Query()
+ try:
+ custom_flowsheets_dict = self._histdb.search(query.fragment({"custom_flowsheets_version": VERSION}))
+ if(len(custom_flowsheets_dict) == 0):
+ _log.error('unable to find custom flowsheets dictionary')
+ custom_flowsheets_dict = {}
+ else:
+ custom_flowsheets_dict = custom_flowsheets_dict[0]["custom_flowsheets_dict"]
+ except Exception as e:
+ _log.error(f'error trying to find custom flowsheets dictionary: {e}')
+ _log.error(f'setting it as empty dictionary')
+ custom_flowsheets_dict = {}
+
+ # remove each file
+ flowsheet_files = custom_flowsheets_dict[id_]
+ for flowsheet_file in flowsheet_files:
+ flowsheet_file_path = self.custom_flowsheets_path / flowsheet_file
+ _log.info(f'flowsheet file path: {flowsheet_file_path}')
+ if os.path.isfile(flowsheet_file_path):
+ _log.info(f'removing file: {flowsheet_file_path}')
+ os.remove(flowsheet_file_path)
+
+
+ # delete from DB
+ del custom_flowsheets_dict[id_]
+ self._histdb.upsert(
+ {"custom_flowsheets_version": VERSION, "custom_flowsheets_dict": custom_flowsheets_dict},
+ (query.custom_flowsheets_version == VERSION),
+ )
+
+ # remove from flowsheets list
+ del self._flowsheets[id_]
+
+ self.add_custom_flowsheets()
+
def add_custom_flowsheets(self):
"""Search for user uploaded flowsheets. If found, add them as flowsheet interfaces."""
- from os import walk
- import importlib
- custom_flowsheets_path = Path.home() / ".watertap" / "custom_flowsheets"
- sys.path.append(str(custom_flowsheets_path))
-
files = []
- for (_, _, filenames) in walk(custom_flowsheets_path):
+ for (_, _, filenames) in os.walk(self.custom_flowsheets_path):
files.extend(filenames)
break
diff --git a/backend/app/routers/flowsheets.py b/backend/app/routers/flowsheets.py
index bc214649..601968aa 100644
--- a/backend/app/routers/flowsheets.py
+++ b/backend/app/routers/flowsheets.py
@@ -223,20 +223,33 @@ async def upload_flowsheet(files: List[UploadFile]) -> str:
custom_flowsheets_path = Path.home() / ".watertap" / "custom_flowsheets"
try:
# get file contents
-
+ new_files = []
+
print('trying to read files with aiofiles')
for file in files:
# for file in files:
print(file.filename)
+ new_files.append(file.filename)
+ if '_ui.py' in file.filename:
+ new_id = file.filename.replace('.py', '')
async with aiofiles.open(f'{str(custom_flowsheets_path)}/{file.filename}', 'wb') as out_file:
content = await file.read() # async read
await out_file.write(content)
- flowsheet_manager.add_custom_flowsheets()
+ flowsheet_manager.add_custom_flowsheet(new_files, new_id)
return {'return': 'success boy'}
except Exception as e:
_log.error(f"error on file upload: {str(e)}")
raise HTTPException(400, detail=f"File upload failed: {e}")
+
+@router.post("/{flowsheet_id}/remove_flowsheet")
+async def remove_flowsheet(flowsheet_id: str):
+ try:
+ flowsheet_manager.remove_custom_flowsheet(flowsheet_id)
+ return {'return': 'success boy'}
+ except Exception as e:
+ _log.error(f"error on flowsheet deletion: {str(e)}")
+ raise HTTPException(400, detail=f"failed: {e}")
@router.get("/{flowsheet_id}/load")
diff --git a/electron/ui/src/components/FlowsheetsListTable/FlowsheetsListTable.js b/electron/ui/src/components/FlowsheetsListTable/FlowsheetsListTable.js
index 3252c1d7..1cf9423b 100644
--- a/electron/ui/src/components/FlowsheetsListTable/FlowsheetsListTable.js
+++ b/electron/ui/src/components/FlowsheetsListTable/FlowsheetsListTable.js
@@ -1,8 +1,11 @@
import { useState } from 'react'
import { Table, TableBody, TableCell, TableContainer, TableHead, TableRow, IconButton, Icon, Button } from '@mui/material'
import { useNavigate } from "react-router-dom";
+import { deleteFlowsheet } from "../../services/flowsheetsList.service";
import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
+import ClearIcon from '@mui/icons-material/Clear';
+
export default function FlowsheetsListTable(props) {
@@ -56,6 +59,26 @@ export default function FlowsheetsListTable(props) {
}
+ const handleRemoveCustomFlowsheet = (e, id) => {
+ e.stopPropagation()
+ deleteFlowsheet(id)
+ .then(response => {
+ if (response.status === 200) {
+ response.json()
+ .then((data)=>{
+ console.log('delete successful: ',data)
+ window.location.reload()
+
+ }).catch((err)=>{
+ console.error("error on flowshete deletion: ",err)
+ })
+ }
+ else if (response.status === 400) {
+ console.error("error on flowshete deletion: ",response.statusText)
+ }
+ })
+ }
+
function compare( a, b ) {
if ( a[sortKey] < b[sortKey] ){
if(sortDirection === "ascending") return -1;
@@ -99,7 +122,13 @@ export default function FlowsheetsListTable(props) {
>
{row.description}
{formatLastRun(row.last_run)}
-
+
+ {row.custom &&
+ handleRemoveCustomFlowsheet(e, row.id_)}>
+
+
+ }
+
))}
diff --git a/electron/ui/src/components/NewFlowsheetDialog/NewFlowsheetDialog.js b/electron/ui/src/components/NewFlowsheetDialog/NewFlowsheetDialog.js
index 25cee921..ccbce66d 100644
--- a/electron/ui/src/components/NewFlowsheetDialog/NewFlowsheetDialog.js
+++ b/electron/ui/src/components/NewFlowsheetDialog/NewFlowsheetDialog.js
@@ -14,7 +14,7 @@ export default function NewFlowsheetDialog(props) {
const [ showWarning, setShowWarning ] = useState(false)
const [ warningMessage, setWarningMessage ] = useState("")
const [ files, setFiles ] = useState({"Model File": null, "Export File": null, "Diagram File": null, "Data Files": []})
- const fileTypes = {"Model File": ["py"], "Export File": ["py"], "Diagram File": ["png"], "Data Files": ["yaml", "yml", "json", "csv"], };
+ const fileTypes = {"Model File": ["py"], "Export File": ["py"], "Diagram File": ["png", "jpeg", "jpg"], "Data Files": ["yaml", "yml", "json", "csv", "txt", "zip"], };
const styles = {
modalStyle: {
position: 'absolute',
@@ -148,7 +148,7 @@ export default function NewFlowsheetDialog(props) {
try {
let newWarningMessage = "Please choose a valid file type from these options: "
for (let fileType of fileTypes[fileId]) {
- newWarningMessage+= fileType+", "
+ newWarningMessage+= fileType+" "
}
setWarningMessage(newWarningMessage)
setShowWarning(true)
diff --git a/electron/ui/src/services/flowsheetsList.service.js b/electron/ui/src/services/flowsheetsList.service.js
index 9ff285d8..7216f9d8 100644
--- a/electron/ui/src/services/flowsheetsList.service.js
+++ b/electron/ui/src/services/flowsheetsList.service.js
@@ -13,4 +13,11 @@ export const uploadFlowsheet = (data) => {
mode: 'cors',
body: data
});
+};
+
+export const deleteFlowsheet = (id) => {
+ return fetch('http://localhost:8001/flowsheets/'+id+'/remove_flowsheet', {
+ method: 'POST',
+ mode: 'cors'
+ });
};
\ No newline at end of file