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

Bt status for subtrees #210

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
9 changes: 8 additions & 1 deletion backend/filesystem/library_demo/config.json
Original file line number Diff line number Diff line change
@@ -1 +1,8 @@
{"name": "library_demo", "config": {"editorShowAccentColors": true, "theme": "dark", "btOrder": "bottom-to-top"}}
{
"name": "library_demo",
"config": {
"editorShowAccentColors": true,
"theme": "dark",
"btOrder": "top-to-bottom"
}
}
6 changes: 3 additions & 3 deletions backend/tree_api/json_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ def translate(content, tree_path, raw_order):
f.close()


def translate_tree_structure(content):
def translate_tree_structure(content, raw_order):
# Parse the JSON data
parsed_json = content

Expand All @@ -209,12 +209,12 @@ def translate_tree_structure(content):
# Get the tree structure
tree_structure = get_tree_structure(link_models, node_models)
# Get the order of bt: True = Ascendent; False = Descendent
# order = raw_order == "bottom-to-top"
order = raw_order == "bottom-to-top"

# Generate XML
start_node_id = get_start_node_id(node_models, link_models)
root = build_tree_structure(
node_models, link_models, tree_structure, start_node_id, False
node_models, link_models, tree_structure, start_node_id, order
)

return root
5 changes: 5 additions & 0 deletions backend/tree_api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
path("save_file/", views.save_file, name="save_file"),
path("translate_json/", views.translate_json, name="translate_json"),
path("get_tree_structure/", views.get_tree_structure, name="get_tree_structure"),
path(
"get_subtree_structure/",
views.get_subtree_structure,
name="get_subtree_structure",
),
path(
"get_universe_configuration/",
views.get_universe_configuration,
Expand Down
84 changes: 73 additions & 11 deletions backend/tree_api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def get_project_configuration(request):
def get_tree_structure(request):

project_name = request.GET.get("project_name")
bt_order = request.GET.get("bt_order")

# Generate the paths
base_path = os.path.join(settings.BASE_DIR, "filesystem")
Expand All @@ -208,7 +209,45 @@ def get_tree_structure(request):
graph_data = json.load(f)

# Get the tree structure
tree_structure = json_translator.translate_tree_structure(graph_data)
tree_structure = json_translator.translate_tree_structure(
graph_data, bt_order
)

return JsonResponse({"success": True, "tree_structure": tree_structure})
except Exception as e:
return JsonResponse(
{"success": False, "message": f"Error reading file: {str(e)}"},
status=500,
)
else:
return Response(
{"error": "The project does not have a graph definition"}, status=404
)


@api_view(["GET"])
def get_subtree_structure(request):

project_name = request.GET.get("project_name")
subtree_name = request.GET.get("subtree_name")
bt_order = request.GET.get("bt_order")

# Generate the paths
base_path = os.path.join(settings.BASE_DIR, "filesystem")
project_path = os.path.join(base_path, project_name)
subtree_path = os.path.join(project_path, "code/trees/subtrees/json")
graph_path = os.path.join(subtree_path, subtree_name + ".json")

# Check if the project exists
if os.path.exists(graph_path):
try:
with open(graph_path, "r") as f:
graph_data = json.load(f)

# Get the tree structure
tree_structure = json_translator.translate_tree_structure(
graph_data, bt_order
)

return JsonResponse({"success": True, "tree_structure": tree_structure})
except Exception as e:
Expand Down Expand Up @@ -345,7 +384,7 @@ def save_subtree(request):
f.write(subtree_json)

# TOFIX: order hardcoded
json_translator.translate(subtree_json, xml_path, "top-to-bottom")
# json_translator.translate(subtree_json, xml_path, "top-to-bottom")

return JsonResponse({"success": True}, status=status.HTTP_200_OK)

Expand Down Expand Up @@ -886,11 +925,18 @@ def generate_app(request):

# Copy all the subtrees to the temp folder
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".xml"):
shutil.copy(
os.path.join(subtree_path, subtree_file), result_trees_tmp_path
if subtree_file.endswith(".json"):
subtree_name = base = os.path.splitext(os.path.basename(subtree_file))[
0
]
xml_path = os.path.join(
project_path, "code", "trees", "subtrees", f"{subtree_name}.xml"
)

json_translator.translate(subtree_file, xml_path, bt_order)

shutil.copy(xml_path, result_trees_tmp_path)

# Generate a self-contained tree
tree_generator.generate(
result_trees_tmp_path, action_path, self_contained_tree_path
Expand Down Expand Up @@ -958,7 +1004,7 @@ def generate_dockerized_app(request):
action_path = os.path.join(project_path, "code/actions")

working_folder = "/tmp/wf"
subtree_path = os.path.join(project_path, "code/trees/subtrees")
subtree_path = os.path.join(project_path, "code/trees/subtrees/json")
result_trees_tmp_path = os.path.join("/tmp/trees/")
self_contained_tree_path = os.path.join(working_folder, "self_contained_tree.xml")
tree_gardener_src = os.path.join(settings.BASE_DIR, "tree_gardener")
Expand All @@ -980,11 +1026,27 @@ def generate_dockerized_app(request):
json_translator.translate(main_tree_graph, main_tree_tmp_path, bt_order)

# 3. Copy all the subtrees to the temp folder
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".xml"):
shutil.copy(
os.path.join(subtree_path, subtree_file), result_trees_tmp_path
)
try:
for subtree_file in os.listdir(subtree_path):
if subtree_file.endswith(".json"):
subtree_name = base = os.path.splitext(
os.path.basename(subtree_file)
)[0]
print(os.path.join(subtree_path, subtree_file))

xml_path = os.path.join(
project_path, "code", "trees", "subtrees", f"{subtree_name}.xml"
)

with open(os.path.join(subtree_path, subtree_file), "r+") as f:
# Reading from a file
subtree_json = f.read()

json_translator.translate(subtree_json, xml_path, bt_order)

shutil.copy(xml_path, result_trees_tmp_path)
except:
print("No subtrees")

# 4. Generate a self-contained tree
tree_generator.generate(
Expand Down
4 changes: 2 additions & 2 deletions backend/tree_gardener/tree_gardener/tree_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,15 +312,15 @@ def get_branches(element):
if child_instance is not None:
child = child_instance
retry_name = "Retry_" + str(nfailures)
instance = Class(name=retry_name, num_failures=int(nfailures), child=child)
instance = Class(name=class_name, num_failures=int(nfailures), child=child)
elif "Repeat" in class_name:
num_cycles = element.get("num_cycles")
for child_element in element:
child_instance = get_branches(child_element)
if child_instance is not None:
child = child_instance
repeat_name = "Repeat_" + str(num_cycles)
instance = Class(name=repeat_name, child=child, num_success=int(num_cycles))
instance = Class(name=class_name, child=child, num_success=int(num_cycles))
elif (
"Inverter" in class_name
or "Force" in class_name
Expand Down
17 changes: 10 additions & 7 deletions backend/tree_gardener/tree_gardener/tree_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,8 @@ def ascii_blackboard_to_json(blackboard):
json_str = '"blackboard":{'
do_append_coma = False

# FIX: [entry, value] = line.strip()[1:].split(":")
ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
blackboard = ansi_escape.sub("", blackboard)

for line in iter(blackboard.splitlines()):
if "Blackboard Data" in line:
Expand All @@ -115,18 +116,20 @@ def ascii_blackboard_to_json(blackboard):
continue
if do_append_coma:
json_str += ","
else:
do_append_coma = True
# Remove whitespaces with strip and remove / from entry
[entry, value] = line.strip()[1:].split(":")
json_str += f'"{entry.strip()}":"{value.strip()}"'
try:
[entry, value] = line.strip()[1:].split(":")
json_str += f'"{entry.strip()}":"{value.strip()}"'
do_append_coma = True
except:
pass
json_str += "}"
return json_str


def ascii_bt_to_json(tree, blackboard, file):
file.write("{")
# file.write(f"{ascii_tree_to_json(tree)},{ascii_blackboard_to_json(blackboard)}")
file.write(f"{ascii_tree_to_json(tree)}")
file.write(f"{ascii_tree_to_json(tree)},{ascii_blackboard_to_json(blackboard)}")
# file.write(f"{ascii_tree_to_json(tree)}")
file.write("}")
file.close()
8 changes: 6 additions & 2 deletions frontend/src/components/header_menu/HeaderMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MouseEventHandler, useEffect, useState } from "react";
import { MouseEventHandler, useContext, useEffect, useState } from "react";
import AppBar from "@mui/material/AppBar";
import Toolbar from "@mui/material/Toolbar";
import {
Expand All @@ -25,6 +25,7 @@ import { ReactComponent as ResetIcon } from "./img/reset.svg";
import ProjectModal from "./modals/ProjectModal";
import UniversesModal from "./modals/UniverseModal";
import SettingsModal from "../settings_popup/SettingsModal";
import { OptionsContext } from "../options/Options";

const HeaderMenu = ({
currentProjectname,
Expand All @@ -50,6 +51,9 @@ const HeaderMenu = ({
setGazeboEnabled: Function;
manager: CommsManager;
}) => {
// Settings
const settings = useContext(OptionsContext);

// Project state
const [existingProjects, setExistingProjects] = useState("");

Expand Down Expand Up @@ -202,7 +206,7 @@ const HeaderMenu = ({
const appBlob = await generateDockerizedApp(
modelJson,
currentProjectname,
"top-to-bottom",
settings.btOrder.value,
);

// Convert the blob to base64 using FileReader
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/helper/TreeEditorHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,3 +261,33 @@ export const configureEngine = (
.getActionEventBus()
.registerAction(new ZoomCanvasAction({ inverseZoom: true }));
};

export const findSubtree = (
baseTree: any,
subTree: string,
oldIndex: number = -1,
): number[] | undefined => {
var path: number[] = [];
var nodeChilds;
var name = baseTree.name;

if (name === subTree) {
return oldIndex >= 0 ? [] : undefined;
}

try {
nodeChilds = baseTree["childs"];
} catch (error) {
return undefined;
}

for (let index = 0; index < nodeChilds.length; index++) {
var result = findSubtree(nodeChilds[index], subTree, index);
if (result) {
path = [index].concat(result);
return path;
}
}

return undefined;
};
Loading
Loading