diff --git a/src/techui_builder/builder.py b/src/techui_builder/builder.py index fdfbdac..05f8c07 100644 --- a/src/techui_builder/builder.py +++ b/src/techui_builder/builder.py @@ -268,7 +268,7 @@ def _generate_json_map( # Create initial node at top of .bob file current_node = JsonMap( - str(screen_path.relative_to(self._write_directory)), + str(screen_path.resolve().relative_to(self._write_directory.resolve())), display_name=None, ) @@ -318,9 +318,7 @@ def _generate_json_map( macro_dict = self._get_macros(open_display) case "embedded": - file_elem = self._extract_action_button_file_from_embedded( - widget_elem.file, dest_path - ) + file_elem = widget_elem.file name_elem = widget_elem.name.text macro_dict = self._get_macros(widget_elem) @@ -359,14 +357,23 @@ def _generate_json_map( ) else: child_node = JsonMap( - str(file_path), display_name, exists=("IOC" in macro_dict) + str(file_path), + display_name, + exists=("IOC" in macro_dict or ("https:/" in str(file_path))), ) - child_node.macros = macro_dict - # TODO: make this work for only list[JsonMap] - assert isinstance(current_node.children, list) - # TODO: fix typing - current_node.children.append(child_node) + if widget_type == "embedded": + for embedded_child in child_node.children: + embedded_child.macros = {**embedded_child.macros, **macro_dict} + embedded_child.display_name = display_name + current_node.children.append(embedded_child) + + else: + child_node.macros = macro_dict + # TODO: make this work for only list[JsonMap] + assert isinstance(current_node.children, list) + # TODO: fix typing + current_node.children.append(child_node) except etree.ParseError as e: current_node.error = f"XML parse error: {e}" @@ -410,34 +417,6 @@ def _get_component_label( display_name = child_labels[name_elem] return display_name - def _extract_action_button_file_from_embedded( - self, file_elem: ObjectifiedElement, dest_path: Path - ) -> ObjectifiedElement: - file_path = Path(file_elem.text.strip() if file_elem.text else "") - file_path = dest_path.joinpath(file_path) - if not file_path.exists(): - rel_file_path = Path(str(file_elem.base)).relative_to( - dest_path.absolute(), walk_up=True - ) - file_path = dest_path.joinpath(rel_file_path) - tree = objectify.parse(file_path.absolute()) - root: ObjectifiedElement = tree.getroot() - - # Find all elements - widgets = [ - w - for w in root.findall(".//widget") - if w.get("type", default=None) == "action_button" - ] - - for widget_elem in widgets: - open_display = _get_action_group(widget_elem) - if open_display is None: - continue - file_elem = open_display.file - return file_elem - return file_elem - def _get_macros(self, element: ObjectifiedElement): if hasattr(element, "macros"): macros = element.macros.getchildren() diff --git a/src/techui_builder/generate.py b/src/techui_builder/generate.py index 7ea36f1..80c986d 100644 --- a/src/techui_builder/generate.py +++ b/src/techui_builder/generate.py @@ -193,12 +193,24 @@ def _allocate_widget( self, scrn_mapping: Mapping, component: Entity ) -> EmbeddedDisplay | ActionButton | None | list[EmbeddedDisplay | ActionButton]: name, suffix, suffix_label = self._initialise_name_suffix(component) + # Get relative path to screen - scrn_path = self.support_path.joinpath(f"bob/{scrn_mapping['file']}") - logger_.debug(f"Screen path: {scrn_path}") + file = scrn_mapping["file"] + if file.startswith("$(IOC)"): + scrn_path = data_scrn_path = file.replace( + "$(IOC)", f"{self.beamline_url}/{component.service_name}" + ) # Only works with related displays as + # embedded displays need to access the file to get dimensions + + assert scrn_mapping["type"] == "related", ( + "Only related displays can have remote screens" + ) + else: + scrn_path = self.support_path.joinpath(f"bob/{file}") + logger_.debug(f"Screen path: {scrn_path}") - # Path of screen relative to data/ so it knows where to open the file from - data_scrn_path = scrn_path.relative_to(self.synoptic_dir, walk_up=True) + # Path of screen relative to data/ so it knows where to open the file from + data_scrn_path = scrn_path.relative_to(self.synoptic_dir, walk_up=True) # For Gui Components with multiple components embedded, we add a suffix field # to the components, and adjust the name and suffix accordingly diff --git a/tests/test_builder.py b/tests/test_builder.py index 24375b0..10a8535 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -317,11 +317,15 @@ def test_generate_json_map( # TODO: write this test -def test_generate_json_map_embedded_screen( - builder_with_test_files, example_json_map, components -): +def test_generate_json_map_embedded_screen(builder_with_test_files, example_json_map): builder_with_test_files._get_component_label = Mock( - side_effect=["Display", "Detector", "Embedded Display"] + side_effect=[ + "Display", + "Detector", + "Embedded Display", + "Embedded Display", + "Embedded Display", + ] ) screen_path = Path("tests/test_files/test_bob_embedded.bob").absolute() @@ -330,14 +334,14 @@ def test_generate_json_map_embedded_screen( example_json_map.file = "test_bob_embedded.bob" example_json_map.children.append( JsonMap( - "$(IOC)/pmacAxis.pvi.bob", display_name="Embedded Display", exists=False + "$(IOC)/pmacAxis.pvi.bob", + display_name="Embedded Display", + exists=False, + macros={"M": "$(M)", "P": "$(P)"}, ) ) - test_json_map = builder_with_test_files._generate_json_map( - screen_path, dest_path, components - ) - + test_json_map = builder_with_test_files._generate_json_map(screen_path, dest_path) assert test_json_map == example_json_map diff --git a/tests/test_files/widget_url_screen.xml b/tests/test_files/widget_url_screen.xml new file mode 100644 index 0000000..c20d93d --- /dev/null +++ b/tests/test_files/widget_url_screen.xml @@ -0,0 +1,21 @@ + + + CAM + 0 + 0 + 100 + 40 + + CAM + + + Open Display + +

BL01T-DI-IOC-01

+ :CAM: +
+ test_url/bl01t-di-ioc-01/ADAravis_summary.bob + tab +
+
+
diff --git a/tests/test_generate.py b/tests/test_generate.py index 18f742a..7a4bc8f 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -265,6 +265,31 @@ def test_generator_allocate_widget(generator): assert str(widget) == xml_content +def test_generator_allocate_widget_with_remote_screens(generator): + generator._initilise_name_suffix = Mock(return_value=("CAM:", "CAM:", "R")) + + scrn_mapping = { + "file": "$(IOC)/ADAravis_summary.bob", + "prefix": "$(P)$(R)", + "type": "related", + } + component = Entity( + service_name="bl01t-di-ioc-01", + type="ADAravis.aravisCamera", + P="BL01T-DI-IOC-01", + desc=None, + M=None, + R=":CAM:", + ) + widget = generator._allocate_widget(scrn_mapping, component) + control_widget = Path("tests/test_files/widget_url_screen.xml") + + with open(control_widget) as f: + xml_content = f.read() + print(str(widget)) + assert str(widget) == xml_content + + def test_generator_allocate_widget_with_suffix(generator): generator._initialise_name_suffix = Mock(return_value=(":CAM:", ":CAM:", "R"))