From 045df2e8c9f855e88fb20b080f835b442bfeb4ae Mon Sep 17 00:00:00 2001 From: Aliaksandr Yakutovich Date: Mon, 2 Dec 2024 15:06:40 +0100 Subject: [PATCH] Start page: use `ipw.VBox` instead of `ipw.Output` to display apps (#185) Also, remove the decorator used as a workaround. --- home/start_page.py | 58 ++++++++++------------------------------------ 1 file changed, 12 insertions(+), 46 deletions(-) diff --git a/home/start_page.py b/home/start_page.py index f67d126..69942eb 100644 --- a/home/start_page.py +++ b/home/start_page.py @@ -1,7 +1,6 @@ """Module to generate AiiDAlab home page.""" import json -from functools import wraps from glob import glob from os import path @@ -9,7 +8,6 @@ import traitlets from aiidalab.app import AiidaLabApp from aiidalab.config import AIIDALAB_APPS -from IPython.display import display from home.utils import load_widget from home.widgets import AppStatusInfoWidget @@ -30,37 +28,12 @@ def create_app_widget_move_buttons(name): return app_widget_move_buttons -def _workaround_property_lock_issue(func): - """Work-around for issue with the ipw.Accordion widget. - - The widget does not report changes to the .selected_index trait when displayed - within a custom ipw.Output instance. However, the change is somewhat cryptic reported - by a change to the private '_property_lock' trait. We observe changes to that trait - and convert the change argument into a form that is more like the one expected by - downstream handlers. - """ - - @wraps(func) - def _inner(self, change): - if change["name"] == "_property_lock": - if "selected_index" in change["old"]: - fixed_change = change.copy() - fixed_change["name"] = "selected_index" - fixed_change["new"] = change["old"]["selected_index"] - del fixed_change["old"] - return func(self, fixed_change) - - return func(self, change) - - return _inner - - class AiidaLabHome: """Class that mananges the appearance of the AiiDAlab home page.""" def __init__(self): self.config_fn = ".launcher.json" - self.output = ipw.Output() + self.output = ipw.VBox() self._app_widgets = {} def _create_app_widget(self, name): @@ -98,17 +71,17 @@ def read_config(self): def render(self): """Rendering all apps.""" - self.output.clear_output() - apps = self.load_apps() - with self.output: - for name in apps: - # Create app widget if it has not been created yet. - if name not in self._app_widgets: - self._app_widgets[name] = self._create_app_widget(name) + displayed_apps = [] + apps = self.load_apps() - display(self._app_widgets[name]) + for name in apps: + # Create app widget if it has not been created yet. + if name not in self._app_widgets: + self._app_widgets[name] = self._create_app_widget(name) + displayed_apps.append(self._app_widgets[name]) + self.output.children = displayed_apps return self.output def load_apps(self): @@ -186,24 +159,17 @@ def __init__(self, app, allow_move=False, allow_manage=True): class CollapsableAppWidget(ipw.Accordion): """Widget that represents a collapsable app as part of the home page.""" - hidden = traitlets.Bool() + hidden = traitlets.Bool(None, allow_none=True) def __init__(self, app, **kwargs): self.app = app app_widget = AppWidget(app, **kwargs) super().__init__(children=[app_widget]) self.set_title(0, app.title) - # Need to observe all names here due to unidentified issue: - self.observe( - self._observe_accordion_selected_index - ) # , names=['selected_index']) - @_workaround_property_lock_issue + @traitlets.observe("selected_index") def _observe_accordion_selected_index(self, change): - if ( - change["name"] == "selected_index" - ): # Observing all names due to unidentified issue. - self.hidden = change["new"] is None + self.hidden = change["new"] is None @traitlets.observe("hidden") def _observe_hidden(self, change):