From 2fbc576b185dacda8dc542b62f1b4feaf1f5006b Mon Sep 17 00:00:00 2001 From: krande Date: Thu, 10 Oct 2024 14:15:20 +0200 Subject: [PATCH] frontend: Add nodrag class on buttons and add icons wsock: add error tracebacks in debug mode config: minor refactor of fem_analysis -> fea --- src/ada/api/spatial/assembly.py | 2 +- src/ada/comms/cli_async_ws_server.py | 5 +- src/ada/comms/fb_deserializer.py | 1 + src/ada/comms/fb_model_gen.py | 1 + src/ada/comms/fb_serializer.py | 2 + .../comms/msg_handling/default_on_message.py | 4 ++ src/ada/comms/wsock/Value.py | 17 ++++- src/ada/comms/wsock_server.py | 2 + src/ada/config.py | 2 +- src/ada/fem/formats/mesh_io/writer.py | 2 +- src/ada/fem/formats/utils.py | 19 +++--- .../procedural_modelling/load_procedures.py | 28 ++++++--- src/flatbuffers/schemas/commands.fbs | 3 +- .../node_editor/NodeEditorComponent.tsx | 26 +++++++- .../nodes/file_node/customFileObjectNode.tsx | 2 +- .../nodes/procedure_node/ParameterItem.tsx | 63 +++++++++++++------ .../nodes/procedure_node/ProcedureHeader.tsx | 16 ++++- .../nodes/procedure_node/ProcedureNode.tsx | 2 +- src/frontend/src/flatbuffers/wsock/value.ts | 24 +++++-- .../src/utils/node_editor/run_procedure.ts | 3 +- tests/core/visit/test_viewpoints.py | 2 +- 21 files changed, 167 insertions(+), 59 deletions(-) diff --git a/src/ada/api/spatial/assembly.py b/src/ada/api/spatial/assembly.py index bf33baa3f..c660a07b0 100644 --- a/src/ada/api/spatial/assembly.py +++ b/src/ada/api/spatial/assembly.py @@ -192,7 +192,7 @@ def to_fem( if isinstance(fem_format, str): fem_format = FEATypes.from_str(fem_format) - scratch_dir = Config().fem_analysis_scratch_dir if scratch_dir is None else pathlib.Path(scratch_dir) + scratch_dir = Config().fea_scratch_dir if scratch_dir is None else pathlib.Path(scratch_dir) write_to_fem( self, name, fem_format, overwrite, fem_converter, scratch_dir, metadata, make_zip_file, model_data_only diff --git a/src/ada/comms/cli_async_ws_server.py b/src/ada/comms/cli_async_ws_server.py index 87834a6e6..7f312dd37 100644 --- a/src/ada/comms/cli_async_ws_server.py +++ b/src/ada/comms/cli_async_ws_server.py @@ -10,7 +10,10 @@ async def start_async_server(host="localhost", port=8765, run_in_thread=False, log_level="DEBUG"): logger.setLevel(log_level) - server = WebSocketAsyncServer(host, port) + is_debug = False + if log_level == "DEBUG": + is_debug = True + server = WebSocketAsyncServer(host, port, debug=is_debug) if run_in_thread: await server.run_in_background() else: diff --git a/src/ada/comms/fb_deserializer.py b/src/ada/comms/fb_deserializer.py index e47f8e6be..b1724743d 100644 --- a/src/ada/comms/fb_deserializer.py +++ b/src/ada/comms/fb_deserializer.py @@ -167,6 +167,7 @@ def deserialize_value(fb_obj) -> ValueDC | None: array_value_type=ParameterTypeDC(fb_obj.ArrayValueType()), array_length=fb_obj.ArrayLength(), array_type=ArrayTypeDC(fb_obj.ArrayType()), + array_any_length=fb_obj.ArrayAnyLength(), ) diff --git a/src/ada/comms/fb_model_gen.py b/src/ada/comms/fb_model_gen.py index d3baba9bf..ec8d46317 100644 --- a/src/ada/comms/fb_model_gen.py +++ b/src/ada/comms/fb_model_gen.py @@ -154,6 +154,7 @@ class ValueDC: array_value_type: Optional[ParameterTypeDC] = None array_length: int = None array_type: Optional[ArrayTypeDC] = None + array_any_length: bool = None @dataclass diff --git a/src/ada/comms/fb_serializer.py b/src/ada/comms/fb_serializer.py index da55f6376..69e2efb95 100644 --- a/src/ada/comms/fb_serializer.py +++ b/src/ada/comms/fb_serializer.py @@ -303,6 +303,8 @@ def serialize_value(builder: flatbuffers.Builder, obj: Optional[ValueDC]) -> Opt Value.AddArrayLength(builder, obj.array_length) if obj.array_type is not None: Value.AddArrayType(builder, obj.array_type.value) + if obj.array_any_length is not None: + Value.AddArrayAnyLength(builder, obj.array_any_length) return Value.End(builder) diff --git a/src/ada/comms/msg_handling/default_on_message.py b/src/ada/comms/msg_handling/default_on_message.py index aa0ccbeb6..a4392aaa8 100644 --- a/src/ada/comms/msg_handling/default_on_message.py +++ b/src/ada/comms/msg_handling/default_on_message.py @@ -1,5 +1,6 @@ from __future__ import annotations +import traceback from typing import TYPE_CHECKING from ada.comms.fb_deserializer import deserialize_root_message @@ -43,5 +44,8 @@ def default_on_message(server: WebSocketAsyncServer, client: ConnectedClient, me on_error_reply(server, client, error_message=f"Unknown command type: {message.command_type}") except Exception as e: + trace_str = traceback.format_exc() logger.error(f"Error handling message: {e}") + if server.debug: + logger.error(trace_str) on_error_reply(server, client, error_message=str(e)) diff --git a/src/ada/comms/wsock/Value.py b/src/ada/comms/wsock/Value.py index 35aa6731a..f0a734abb 100644 --- a/src/ada/comms/wsock/Value.py +++ b/src/ada/comms/wsock/Value.py @@ -102,9 +102,16 @@ def ArrayType(self): return self._tab.Get(flatbuffers.number_types.Int8Flags, o + self._tab.Pos) return 0 + # Value + def ArrayAnyLength(self): + o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20)) + if o != 0: + return bool(self._tab.Get(flatbuffers.number_types.BoolFlags, o + self._tab.Pos)) + return False + def ValueStart(builder): - builder.StartObject(8) + builder.StartObject(9) def Start(builder): @@ -183,6 +190,14 @@ def AddArrayType(builder, arrayType): ValueAddArrayType(builder, arrayType) +def ValueAddArrayAnyLength(builder, arrayAnyLength): + builder.PrependBoolSlot(8, arrayAnyLength, 0) + + +def AddArrayAnyLength(builder, arrayAnyLength): + ValueAddArrayAnyLength(builder, arrayAnyLength) + + def ValueEnd(builder): return builder.EndObject() diff --git a/src/ada/comms/wsock_server.py b/src/ada/comms/wsock_server.py index 360f5112e..f5b4163be 100644 --- a/src/ada/comms/wsock_server.py +++ b/src/ada/comms/wsock_server.py @@ -78,6 +78,7 @@ def __init__( on_unsent_message: Optional[ Callable[[WebSocketAsyncServer, bytes, ConnectedClient, MessageDC, int], None] ] = retry_message_sending, + debug=False, ): self.host = host self.port = port @@ -91,6 +92,7 @@ def __init__( self.instance_id = random.randint(0, 2**31 - 1) # Generates a random int32 value self.msg_queue = asyncio.Queue() self.procedure_store = ProcedureStore() + self.debug = debug async def handle_client(self, websocket: websockets.WebSocketServerProtocol, path: str): client = await process_client(websocket, path) diff --git a/src/ada/config.py b/src/ada/config.py index dd8ce9c46..32ad06520 100644 --- a/src/ada/config.py +++ b/src/ada/config.py @@ -115,7 +115,7 @@ class Config: ], ), ConfigSection( - "fem_analysis", + "fea", [ ConfigEntry("execute_dir", str, None, False), ConfigEntry( diff --git a/src/ada/fem/formats/mesh_io/writer.py b/src/ada/fem/formats/mesh_io/writer.py index 16d2bc71d..685b3209e 100644 --- a/src/ada/fem/formats/mesh_io/writer.py +++ b/src/ada/fem/formats/mesh_io/writer.py @@ -14,7 +14,7 @@ def meshio_to_fem(assembly: Assembly, name: str, scratch_dir=None, metadata=None, model_data_only=False) -> None: """Convert Assembly information to FEM using Meshio""" if scratch_dir is None: - scratch_dir = Config().fem_analysis_scratch_dir + scratch_dir = Config().fea_scratch_dir mesh_format = metadata["fem_format"] diff --git a/src/ada/fem/formats/utils.py b/src/ada/fem/formats/utils.py index 915c84693..b734cfdc8 100644 --- a/src/ada/fem/formats/utils.py +++ b/src/ada/fem/formats/utils.py @@ -124,10 +124,10 @@ def analysis_dir(self): @property def execute_dir(self): - if Config().fem_analysis_execute_dir is None: + if Config().fea_execute_dir is None: return self.analysis_dir else: - return Config().fem_analysis_execute_dir / self.analysis_name + return Config().fea_execute_dir / self.analysis_name @property def analysis_name(self): @@ -220,9 +220,10 @@ def get_exe_path(fea_type: FEATypes): if exe_linux is None and bin_exe_linux.exists(): exe_linux = bin_exe_linux exe_win = shutil.which(f"{exe_name}.exe") + fea_exe_paths = Config().fea_fem_exe_paths - if Config().fem_analysis_fem_exe_paths.get(exe_name, None) is not None: - exe_path = Config().fem_analysis_fem_exe_paths[exe_name] + if Config().fea_fem_exe_paths.get(exe_name, None) is not None: + exe_path = Config().fea_fem_exe_paths[exe_name] elif exe_linux: exe_path = exe_linux elif exe_win: @@ -320,7 +321,7 @@ def _lock_check(analysis_dir): def folder_prep(scratch_dir, analysis_name, overwrite): if scratch_dir is None: - scratch_dir = pathlib.Path(Config().fem_analysis_scratch_dir) + scratch_dir = pathlib.Path(Config().fea_scratch_dir) else: scratch_dir = pathlib.Path(scratch_dir) @@ -359,9 +360,9 @@ def run_windows(exe: LocalExecute, run_cmd, stop_cmd=None, exit_after=True, bat_ with open(exe.execute_dir / stop_bat, "w") as d: d.write(f"cd /d {exe.analysis_dir}\n{stop_cmd}") - if Config().fem_analysis_execute_dir is not None: - shutil.copy(exe.execute_dir / start_bat, Config().fem_analysis_execute_dir / start_bat) - shutil.copy(exe.execute_dir / stop_bat, Config().fem_analysis_execute_dir / stop_bat) + if Config().fea_execute_dir is not None: + shutil.copy(exe.execute_dir / start_bat, Config().fea_execute_dir / start_bat) + shutil.copy(exe.execute_dir / stop_bat, Config().fea_execute_dir / stop_bat) # If the script should be running from batch files, then this can be used if run_in_shell: @@ -567,7 +568,7 @@ def default_fem_res_path( from ada.fem.formats.general import FEATypes if scratch_dir is None and analysis_dir is None: - scratch_dir = Config().fem_analysis_scratch_dir + scratch_dir = Config().fea_scratch_dir base_path = scratch_dir / name / name if analysis_dir is None else analysis_dir / name fem_format_map = { diff --git a/src/ada/procedural_modelling/load_procedures.py b/src/ada/procedural_modelling/load_procedures.py index 97733eb65..881ed9c80 100644 --- a/src/ada/procedural_modelling/load_procedures.py +++ b/src/ada/procedural_modelling/load_procedures.py @@ -106,22 +106,30 @@ def arg_to_param(arg: ast.arg, default: ast.expr, decorator_config: dict) -> Par array_type = ArrayTypeDC.SET else: raise NotImplementedError(f"Parameter type {arg_type} not implemented") - if array_value_type == ParameterTypeDC.FLOAT: - default_values = [ValueDC(float_value=x) for x in default_arg_value] - elif array_value_type == ParameterTypeDC.INTEGER: - default_values = [ValueDC(integer_value=x) for x in default_arg_value] - elif array_value_type == ParameterTypeDC.STRING: - default_values = [ValueDC(string_value=x) for x in default_arg_value] - elif array_value_type == ParameterTypeDC.BOOLEAN: - default_values = [ValueDC(boolean_value=x) for x in default_arg_value] - else: - raise NotImplementedError(f"Parameter type {arg_type} not implemented") + + array_is_any_length = False + if len(value_types) > 1 and value_types[1] == "...": + array_is_any_length = True + + default_values = None + if default_arg_value is not None: + if array_value_type == ParameterTypeDC.FLOAT: + default_values = [ValueDC(float_value=x) for x in default_arg_value] + elif array_value_type == ParameterTypeDC.INTEGER: + default_values = [ValueDC(integer_value=x) for x in default_arg_value] + elif array_value_type == ParameterTypeDC.STRING: + default_values = [ValueDC(string_value=x) for x in default_arg_value] + elif array_value_type == ParameterTypeDC.BOOLEAN: + default_values = [ValueDC(boolean_value=x) for x in default_arg_value] + else: + raise NotImplementedError(f"Parameter type {arg_type} not implemented") default_value = ValueDC( array_value=default_values, array_length=len(value_types), array_type=array_type, array_value_type=array_value_type, + array_any_length=array_is_any_length, ) else: raise NotImplementedError(f"Parameter type {arg_type} not implemented") diff --git a/src/flatbuffers/schemas/commands.fbs b/src/flatbuffers/schemas/commands.fbs index 8c69a80b2..d3e50bf7b 100644 --- a/src/flatbuffers/schemas/commands.fbs +++ b/src/flatbuffers/schemas/commands.fbs @@ -143,8 +143,9 @@ table Value { boolean_value: bool; // Value when type is BOOLEAN array_value: [Value]; // Array of values array_value_type: ParameterType; // Array of numbers (e.g., [1.0, 2.0, 3.0]) - array_length: int; // Length of the array + array_length: int; // Length of the array, array_type: ArrayType; // Type of the array + array_any_length: bool; // Boolean to indicate if the array can have any length } // Define a Parameter table that uses a union type for value diff --git a/src/frontend/src/components/node_editor/NodeEditorComponent.tsx b/src/frontend/src/components/node_editor/NodeEditorComponent.tsx index 4dbe75810..486e8b015 100644 --- a/src/frontend/src/components/node_editor/NodeEditorComponent.tsx +++ b/src/frontend/src/components/node_editor/NodeEditorComponent.tsx @@ -12,6 +12,24 @@ const nodeTypes = { procedure: ProcedureNode, file_object: CustomFileObjectNode, }; +const update_icon = + + +const popout_icon = + pop-out-line + + + + const NodeEditorComponent: React.FC = () => { // Access Zustand state and actions using hooks @@ -40,13 +58,15 @@ const NodeEditorComponent: React.FC = () => { {/* Header Area */}
-
Node Editor
+
Node Editor
+
{/* Content Area */} diff --git a/src/frontend/src/components/node_editor/nodes/file_node/customFileObjectNode.tsx b/src/frontend/src/components/node_editor/nodes/file_node/customFileObjectNode.tsx index cd110e90b..b68317820 100644 --- a/src/frontend/src/components/node_editor/nodes/file_node/customFileObjectNode.tsx +++ b/src/frontend/src/components/node_editor/nodes/file_node/customFileObjectNode.tsx @@ -45,7 +45,7 @@ function CustomFileObjectNode(props: { id: string, data: Record