Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] added sequence handling #59

Merged
merged 4 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/parsers/csvparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
import numpy as np
from cesium_entity import CesiumEntity
from .parser import Parser
import sys
import importlib
import os

class CSVParser(Parser):
def __init__(self):
Expand Down
85 changes: 76 additions & 9 deletions api/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,17 @@
from flask_cors import CORS
from threading import Thread
from time import localtime, strftime
from os import makedirs, path, getcwd
from os import makedirs, path, getcwd, environ
from glob import glob
from communication import Comm
from datetime import datetime
from argparse import ArgumentParser
import pandas as pd
import store
import json
#import traceback
import subprocess
import zmq, zlib, pickle
import traceback

from parsers.ulgparser import ULGParser
from parsers.csvparser import CSVParser
Expand All @@ -29,10 +31,14 @@
logs_dir = logs_dir.replace("\\", "/")

configs_dir = path.expanduser("~/Documents/tiplot/config/")
sequences_dir = path.expanduser("~/Documents/tiplot/sequences/")

if not path.exists(logs_dir):
makedirs(logs_dir)

if not path.exists(sequences_dir):
makedirs(sequences_dir)

thread = Thread()
current_parser = None
current_file = None
Expand Down Expand Up @@ -174,16 +180,20 @@ def get_yt_values():
column = field['column']
isExtra = field['isExtra']
columns = list(set([column, "timestamp_tiplot"])) # remove duplicates
err = "no error"
ok = True
if isExtra:
datadict = store.Store.get().extra_datadict
else:
datadict = store.Store.get().datadict
try:
values = datadict[table][columns].fillna(0).to_dict('records')
except:
except Exception as e:
# columns not found
values = []
response = {"table": table, "column": column , "values": values}
err = str(e)
ok = False
response = {"table": table, "column": column , "values": values, "err": err, "ok": ok}
return response

@app.route('/values_xy', methods=['POST'])
Expand All @@ -194,12 +204,16 @@ def get_xy_values():
yCol = field['y']
columns = [xCol, yCol, "timestamp_tiplot"]
datadict = store.Store.get().datadict
err = "no error"
ok = True
try:
values = datadict[table][columns].fillna(0).to_dict('records')
except:
except Exception as e:
# columns not found
values = []
response = {"table": table, "x": xCol, "y": yCol, "values": values}
err = str(e)
ok = False
response = {"table": table, "x": xCol, "y": yCol, "values": values, "err": err, "ok": ok}
return response

@app.route('/correlation', methods=['POST'])
Expand Down Expand Up @@ -288,9 +302,8 @@ def add_log():

@app.route('/entities_props')
def get_entities_props():
props, err = store.Store.get().getEntitiesProps()
if err is not None: print(err)
res = {"data": props}
props, err, ok = store.Store.get().getEntitiesProps()
res = {"data": props, "err": err, "ok": ok}
return res

@app.route('/current_file')
Expand Down Expand Up @@ -339,11 +352,65 @@ def merge_extra():
# ok = False
return {"ok": ok}

@app.route('/run_sequence', methods=['POST'])
def run_sequence():
body = request.get_json()
sequence_name = body['sequence']
sequence_file = sequences_dir + sequence_name
print("Running " + sequence_file)
datadict = store.Store.get().datadict
try:
with open(sequence_file, "r") as f:
code = f.read()
global_namespace = {}
local_namespace = {}
exec(code, global_namespace, local_namespace)
handle_data = local_namespace['handle_data']
store.Store.get().datadict = handle_data(datadict)
ok = True
err = "no error"
except Exception as e:
err = traceback.format_exc()
ok = False
return {"ok": ok, "err": err}

@app.route('/sequences')
def get_sequences():
files = glob(sequences_dir + "/*")
# use the path module to get only the basename of each file
file_names = [path.basename(file) for file in files]
data = {'path': sequences_dir, 'files': file_names}
return data

@app.route('/create_sequence_file', methods=['POST'])
def create_sequence_file():
body = request.get_json()
sequence_name = body['name']+".py"
file_path = path.join(sequences_dir, sequence_name)
try:
with open(file_path, 'w') as file:
file.write("""def handle_data(datadict):
import numpy as np
import pandas as pd

new = datadict
return new""")
ok = True
err = "no error"
except Exception as e:
err = traceback.format_exc()
ok = False

return {"ok": ok, "err": err}



@socketio.on("disconnect")
def disconnected():
# print("-> client has disconnected " + request.sid)
pass


arg_parser = ArgumentParser(description="Tiplot")
arg_parser.add_argument('--port', type=int, default=5000, help='Port to run the server on')
arg_parser.add_argument('--model', type=str, default= getcwd() + "/../obj/main.gltf", help='Path to the model file')
Expand Down
9 changes: 5 additions & 4 deletions api/store.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def getKeys(self):

def getEntitiesProps(self):
data = []
err = None
err = "no error"
ok = True
for e in self.entities:
try:
if (e.position['table'] == e.attitude['table']):
Expand Down Expand Up @@ -83,10 +84,10 @@ def getEntitiesProps(self):
"wireframe": e.wireframe,
"tracked": e.tracked,
"pathColor": e.pathColor})
except KeyError as error:
except Exception as error:
err = str(error)
print("-> Error " + str(error))
return data, err
ok = False
return data, err, ok

def getEntities(self):
data = []
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tiplot",
"version": "1.1.5",
"version": "1.1.6rc",
"private": true,
"homepage": "./",
"proxy": "http://localhost:5000",
Expand Down Expand Up @@ -51,6 +51,7 @@
"react-scripts": "5.0.1",
"react-select": "^5.4.0",
"react-split-pane": "^0.1.92",
"react-toastify": "^9.1.2",
"socket.io": "^4.5.2",
"socket.io-client": "^4.5.2",
"three": "^0.148.0",
Expand Down
130 changes: 124 additions & 6 deletions src/components/ToolBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import "react-bootstrap-submenu/dist/index.css";
import logo from "../static/img/logo.png";
import { generateUUID } from "three/src/math/MathUtils";
import { PORT } from "../static/js/constants";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";

function ToolBar({
page,
Expand All @@ -29,20 +31,31 @@ function ToolBar({
}) {
const [layouts, setLayouts] = useState([]);
const [showSaveMsg, setShowSaveMsg] = useState(false);
const [showCreateMsg, setShowCreateMessage] = useState(false);

const [currentFile, setCurrentFile] = useState("");
const [appVersion, setAppVersion] = useState("0");
const [showInfoBox, setShowInfo] = useState(false);

const [additionalInfo, setAdditionalInfo] = useState([]);
const [hasExtra, setHasExtra] = useState(false);
const [hasMain, setHasMain] = useState(false);

const handleClose = () => setShowSaveMsg(false);
const [sequences, setSequences] = useState([]);

const handleClose = () => {
setShowSaveMsg(false);
setShowCreateMessage(false);
};

const saveCurrentLayoutNamed = () => setShowSaveMsg(true);
const createSequence = () => setShowCreateMessage(true);

useEffect(() => {
getCurrentFile();
getAdditionalInfo();
mapLayouts();
getSequences();
// eslint-disable-next-line
}, []);

Expand All @@ -63,11 +76,11 @@ function ToolBar({
else
setCurrentFile(
"Current File: " +
response.file[0] +
" \nFile Size: " +
formatFileSize(response.file[1]) +
" \nLast Modified: " +
response.file[2]
response.file[0] +
" \nFile Size: " +
formatFileSize(response.file[1]) +
" \nLast Modified: " +
response.file[2]
);

setAppVersion(response.appVersion);
Expand Down Expand Up @@ -235,8 +248,103 @@ function ToolBar({
);
};

const runSequence = async (sequenceName) => {
const response = await fetch(`http://localhost:${PORT}/run_sequence`, {
headers: {
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({ sequence: sequenceName }),
}).then((res) => res.json());
if (response.ok) toast.success(`\"${sequenceName}\" executed successfully`);
else toast.error(response.err);
};

const getSequences = async () => {
const seqs = await fetch(`http://localhost:${PORT}/sequences`).then((res) =>
res.json()
);
var rows = [];
seqs.files.forEach((seq_name) => {
rows.push(
<NavDropdown.Item
key={generateUUID()}
onClick={() => runSequence(seq_name)}
>
{seq_name}
</NavDropdown.Item>
);
});
if (rows.length === 0) {
rows.push(
<NavDropdown.Item key={generateUUID()} disabled>
No Saved Sequences
</NavDropdown.Item>
);
}
setSequences(rows);
};

const onCreate = async () => {
var name = document.getElementById("sequence-name").value;
const response = await fetch(
`http://localhost:${PORT}/create_sequence_file`,
{
headers: {
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({ name: name }),
}
).then((res) => res.json());

if (response.ok) toast.success(`\"${name}\" created successfully`);
else toast.error(response.err);

getSequences();
setShowCreateMessage(false);
};

return (
<>
<ToastContainer />
{/* Pop up for setting sequence name */}
<Modal
show={showCreateMsg}
onHide={handleClose}
animation={false}
centered
>
<Modal.Header closeButton>
<Modal.Title>Create new sequence</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="form-group">
<div className="d-flex">
<label htmlFor="layout-name" className="col-form-label">
Name:
</label>
<input type="text" className="form-control" id="sequence-name" />
<input
type="text"
className="form-control ml-2"
value=".py"
style={{ width: "10%" }}
disabled
/>
</div>
</div>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={onCreate}>
Create
</Button>
</Modal.Footer>
</Modal>

{/* Pop up for setting layout name */}
<Modal show={showSaveMsg} onHide={handleClose} animation={false} centered>
<Modal.Header closeButton>
Expand Down Expand Up @@ -350,6 +458,16 @@ function ToolBar({
Clear layouts
</NavDropdown.Item>
</DropdownSubmenu>
<DropdownSubmenu href="#" title="Sequences">
<DropdownSubmenu href="#" title="Saved Sequences">
{sequences}
</DropdownSubmenu>
<NavDropdown.Divider />
<NavDropdown.Item onClick={createSequence}>
Add new sequence
</NavDropdown.Item>
</DropdownSubmenu>

<NavDropdown.Divider />
<NavDropdown.Item
onClick={() => {
Expand Down
Loading