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

Clean up app wrapper MVC #1009

Merged
merged 1 commit into from
Dec 20, 2024
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
2 changes: 1 addition & 1 deletion qe.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
"metadata": {},
"outputs": [],
"source": [
"controller.enable_toggles()"
"controller.enable_controls()"
]
}
],
Expand Down
101 changes: 57 additions & 44 deletions src/aiidalab_qe/app/wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import ipywidgets as ipw
import traitlets as tl
from IPython.display import display
from IPython.display import Javascript, display

from aiidalab_qe.common.guide_manager import guide_manager
from aiidalab_qe.common.widgets import LoadingWidget
Expand Down Expand Up @@ -48,10 +48,10 @@ def __init__(
self._view = view
self._set_event_handlers()

def enable_toggles(self) -> None:
"""Enable the toggle buttons."""
self._view.guide_toggle.disabled = False
self._view.about_toggle.disabled = False
def enable_controls(self) -> None:
"""Enable the control buttons at the top of the app."""
for control in self._view.controls.children:
control.disabled = False

@without_triggering("about_toggle")
def _on_guide_toggle(self, change: dict):
Expand Down Expand Up @@ -82,29 +82,35 @@ def _on_about_toggle(self, change: dict):
self._view.info_container.children = []
self._view.info_container.layout.display = "none"

def _on_guide_category_select(self, change: dict):
self._view.guide_selection.options = guide_manager.get_guides(change["new"])
self._update_active_guide()
def _on_calculation_history_click(self, _):
self._open_external_notebook("./calculation_history.ipynb")

def _on_guide_select(self, _):
self._update_active_guide()
def _on_guide_category_selection_change(self, change):
self._model.guide_options = guide_manager.get_guides(change["new"])

def _update_active_guide(self):
"""Sets the current active guide."""
def _on_guide_selection_change(self, _):
category = self._view.guide_category_selection.value
guide = self._view.guide_selection.value
active_guide = f"{category}/{guide}" if category != "none" else category
guide_manager.active_guide = active_guide
self._model.update_active_guide(category, guide)

def _set_guide_category_options(self, _):
"""Fetch the available guides."""
self._view.guide_category_selection.options = [
"none",
*guide_manager.get_guide_categories(),
]
def _open_external_notebook(self, url):
"""Open an external notebook in a new tab."""
display(Javascript(f"window.open('{url}', '_blank')"))

def _set_event_handlers(self) -> None:
"""Set up event handlers."""
self._model.observe(
self._on_guide_category_selection_change,
"selected_guide_category",
)
self._model.observe(
self._on_guide_selection_change,
[
"selected_guide_category",
"selected_guide",
],
)

self._view.guide_toggle.observe(
self._on_guide_toggle,
"value",
Expand All @@ -113,22 +119,38 @@ def _set_event_handlers(self) -> None:
self._on_about_toggle,
"value",
)
self._view.guide_category_selection.observe(
self._on_guide_category_select,
"value",
self._view.calculation_history_link.on_click(self._on_calculation_history_click)

ipw.dlink(
(self._model, "guide_category_options"),
(self._view.guide_category_selection, "options"),
)
self._view.guide_selection.observe(
self._on_guide_select,
"value",
ipw.link(
(self._model, "selected_guide_category"),
(self._view.guide_category_selection, "value"),
)
ipw.dlink(
(self._model, "guide_options"),
(self._view.guide_selection, "options"),
)
ipw.link(
(self._model, "selected_guide"),
(self._view.guide_selection, "value"),
)
self._view.on_displayed(self._set_guide_category_options)


class AppWrapperModel(tl.HasTraits):
"""An MVC model for `AppWrapper`."""

def __init__(self):
"""`AppWrapperModel` constructor."""
guide_category_options = tl.List(["none", *guide_manager.get_guide_categories()])
selected_guide_category = tl.Unicode("none")
guide_options = tl.List(tl.Unicode())
selected_guide = tl.Unicode(None, allow_none=True)

def update_active_guide(self, category, guide):
"""Sets the current active guide."""
active_guide = f"{category}/{guide}" if category != "none" else category
guide_manager.active_guide = active_guide


class AppWrapperView(ipw.VBox):
Expand Down Expand Up @@ -184,24 +206,23 @@ def __init__(self) -> None:
disabled=True,
)

self.calculation_history_button = ipw.Button(
self.calculation_history_link = ipw.Button(
layout=ipw.Layout(width="auto"),
button_style="",
icon="list",
description="Calculation history",
tooltip="View all calculations run with this app",
disabled=True,
)

self.calculation_history_button.on_click(self._open_calculation_history)

info_toggles = ipw.HBox(
self.controls = ipw.HBox(
children=[
self.guide_toggle,
self.about_toggle,
self.calculation_history_button,
self.calculation_history_link,
]
)
info_toggles.add_class("info-toggles")
self.controls.add_class("info-toggles")

env = Environment()
guide_template = files(templates).joinpath("guide.jinja").read_text()
Expand All @@ -211,9 +232,7 @@ def __init__(self) -> None:
self.about = ipw.HTML(env.from_string(about_template).render())

self.guide_category_selection = ipw.RadioButtons(
options=["none"],
description="Guides:",
value="none",
layout=ipw.Layout(width="max-content"),
)
self.guide_selection = ipw.RadioButtons(layout=ipw.Layout(margin="2px 20px"))
Expand All @@ -224,7 +243,7 @@ def __init__(self) -> None:
children=[
logo,
subtitle,
info_toggles,
self.controls,
self.info_container,
],
)
Expand All @@ -249,9 +268,3 @@ def __init__(self) -> None:
footer,
],
)

def _open_calculation_history(self, _):
from IPython.display import Javascript

url = "./calculation_history.ipynb"
display(Javascript(f"window.open('{url}', '_blank')"))
12 changes: 6 additions & 6 deletions tests/test_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,19 @@


class TestWrapper:
def test_enable_toggles(self):
"""Test enable_toggles method."""
def test_enable_controls(self):
"""Test enable_controls method."""
self._instansiate_mvc_components()
assert self.view.guide_toggle.disabled is True
assert self.view.about_toggle.disabled is True
self.controller.enable_toggles()
self.controller.enable_controls()
assert self.view.guide_toggle.disabled is False
assert self.view.about_toggle.disabled is False

def test_guide_toggle(self):
"""Test guide_toggle method."""
self._instansiate_mvc_components()
self.controller.enable_toggles()
self.controller.enable_controls()
self.controller._on_guide_toggle({"new": True})
self._assert_guide_is_on()
self.controller._on_guide_toggle({"new": False})
Expand All @@ -23,7 +23,7 @@ def test_guide_toggle(self):
def test_about_toggle(self):
"""Test about_toggle method."""
self._instansiate_mvc_components()
self.controller.enable_toggles()
self.controller.enable_controls()
self.controller._on_about_toggle({"new": True})
self._assert_about_is_on()
self.controller._on_about_toggle({"new": False})
Expand All @@ -32,7 +32,7 @@ def test_about_toggle(self):
def test_toggle_switch(self):
"""Test toggle_switch method."""
self._instansiate_mvc_components()
self.controller.enable_toggles()
self.controller.enable_controls()
self._assert_no_info()
self.controller._on_guide_toggle({"new": True})
self._assert_guide_is_on()
Expand Down
Loading