Skip to content
Open
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
63 changes: 4 additions & 59 deletions src/techui_builder/generate_jsonmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

from techui_builder._logger import Logger
from techui_builder.models import Component, TechUi
from techui_builder.utils import _get_action_group, _get_macros, _get_nav_tabs

logger_ = logging.getLogger(__name__)

Expand Down Expand Up @@ -214,12 +215,12 @@ def _child_file_crawl(
# Use file, name, and macro elements
file_elem = open_display.file
name_elem = widget_elem.name.text
macro_dict = self._get_macros(open_display)
macro_dict = _get_macros(open_display)

case "embedded":
file_elem = widget_elem.file
name_elem = widget_elem.name.text
macro_dict = self._get_macros(widget_elem)
macro_dict = _get_macros(widget_elem)

case "navtabs":
tabs = _get_nav_tabs(widget_elem)
Expand All @@ -229,7 +230,7 @@ def _child_file_crawl(
for tab in tabs:
name_elem = tab.name.text
file_elem = tab.file
macro_dict = self._get_macros(tab)
macro_dict = _get_macros(tab)

# Extract file path from file_elem
# Keep raw string to preserve urls
Expand Down Expand Up @@ -346,17 +347,6 @@ def _get_component_label(
display_name = child_labels[name_elem]
return display_name

def _get_macros(self, element: ObjectifiedElement):
if hasattr(element, "macros"):
macros = element.macros.getchildren()
if macros is not None:
return {
str(macro.tag): macro.text
for macro in macros
if macro.text is not None
}
return {}

def _parse_display_name(self, name: str | None, file_path: Path) -> str | None:
"""Parse display name from <name> tag or file_path"""

Expand Down Expand Up @@ -459,51 +449,6 @@ def _check_default(key: str, value: Any):
return d


# File and desc are under the "actions",
# so the corresponding tag needs to be found
def _get_action_group(element: ObjectifiedElement) -> ObjectifiedElement | None:
try:
actions = element.actions
assert actions is not None
for action in actions.iterchildren("action"):
if action.get("type", default=None) == "open_display":
return action
return None
except AttributeError:
# TODO: Find better way of handling there being no "actions" group
# TODO: Do widgets always have a name attr, or _can_ it be empty??
name = element.name

parent_name = p.name if (p := element.getparent()) is not None else None

logger_.error(
f"Actions group not found in component [bold]{name}[/bold] on "
f"[bold]{parent_name}[/bold]"
)


def _get_nav_tabs(element: ObjectifiedElement) -> list[ObjectifiedElement] | None:
try:
element_tabs = element.tabs
assert element_tabs is not None

tabs = list(element_tabs.iterchildren("tab"))

return tabs

except AttributeError:
# TODO: Find better way of handling there being no "tabs" group
# TODO: Do widgets always have a name attr, or _can_ it be empty??
name = element.name

parent_name = p.name if (p := element.getparent()) is not None else None

logger_.error(
f"Tabs group not found in component [bold]{name}[/bold] on "
f"[bold]{parent_name}[/bold]"
)


@app.callback(invoke_without_command=True)
def generate_jsonmap(
bob_path: Annotated[
Expand Down
99 changes: 99 additions & 0 deletions src/techui_builder/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import logging
from pathlib import Path

from lxml import objectify
from lxml.objectify import ObjectifiedElement

logger_ = logging.getLogger(__name__)


def read_bob(path):
# Read the bob file
Expand Down Expand Up @@ -31,4 +36,98 @@ def get_widgets(root: ObjectifiedElement):
# Get all the widgets inside of the group objects
groups_widgets = get_widgets(child)
widgets.update(groups_widgets)
case "navtabs":
# There is a switch to toggle between screens
# e.g. for different hutches on the main index.bob
# so we need to extract those files and the widgets
# on them.
tabs = _get_nav_tabs(child)

if tabs is None:
continue

for tab in tabs:
# name_elem = tab.name.text
file_elem = tab.file
# macro_dict = _get_macros(tab)

# Extract file path from file_elem
# Keep raw string to preserve urls
file_text = file_elem.text.strip() if file_elem.text else ""
file_path = Path(file_text)

# If file is already a .bob file, skip it
if not file_path.suffix == ".bob":
continue

assert root.base, (
f"The file path for the screen is invalid: {root.base}"
)
root_file_dir = Path(root.base).parent

# try to find the navtab screen next to the parent screen
sub_screen_path = root_file_dir / file_path
assert sub_screen_path.exists(), (
f"The navtab screen '{file_path}' does not exist next to"
f" name {Path(root.base).name}"
)

_, sub_widgets = read_bob(sub_screen_path)
widgets.update(sub_widgets)

return widgets


def _get_macros(element: ObjectifiedElement):
if hasattr(element, "macros"):
macros = element.macros.getchildren()
if macros is not None:
return {
str(macro.tag): macro.text for macro in macros if macro.text is not None
}
return {}


# File and desc are under the "actions",
# so the corresponding tag needs to be found
def _get_action_group(element: ObjectifiedElement) -> ObjectifiedElement | None:
try:
actions = element.actions
assert actions is not None
for action in actions.iterchildren("action"):
if action.get("type", default=None) == "open_display":
return action
return None
except AttributeError:
# TODO: Find better way of handling there being no "actions" group
# TODO: Do widgets always have a name attr, or _can_ it be empty??
name = element.name

parent_name = p.name if (p := element.getparent()) is not None else None

logger_.error(
f"Actions group not found in component [bold]{name}[/bold] on "
f"[bold]{parent_name}[/bold]"
)


def _get_nav_tabs(element: ObjectifiedElement) -> list[ObjectifiedElement] | None:
try:
element_tabs = element.tabs
assert element_tabs is not None

tabs = list(element_tabs.iterchildren("tab"))

return tabs

except AttributeError:
# TODO: Find better way of handling there being no "tabs" group
# TODO: Do widgets always have a name attr, or _can_ it be empty??
name = element.name

parent_name = p.name if (p := element.getparent()) is not None else None

logger_.error(
f"Tabs group not found in component [bold]{name}[/bold] on "
f"[bold]{parent_name}[/bold]"
)