diff --git a/src/aiidalab_qe/app/main.py b/src/aiidalab_qe/app/main.py index 387267779..d0cb9e154 100644 --- a/src/aiidalab_qe/app/main.py +++ b/src/aiidalab_qe/app/main.py @@ -5,6 +5,7 @@ from pathlib import Path +import ipywidgets as ipw from IPython.display import display from aiidalab_qe.app.static import styles @@ -20,12 +21,17 @@ class QeApp: def __init__( - self, process=None, qe_auto_setup=True, bug_report_url=DEFAULT_BUG_REPORT_URL + self, + process=None, + qe_auto_setup=True, + bug_report_url=DEFAULT_BUG_REPORT_URL, + show_log=False, ): """Initialize the AiiDAlab QE application with the necessary setup.""" self.process = process self.qe_auto_setup = qe_auto_setup + self.log_widget = None self._load_styles() @@ -34,6 +40,30 @@ def __init__( self.view = AppWrapperView() display(self.view) + if show_log: + self.log_widget = ipw.Output( + layout=ipw.Layout( + border="solid 1px lightgray", + margin="2px", + padding="5px", + ), + ) + reset_button = ipw.Button( + description="Clear log", + button_style="primary", + icon="trash", + layout=ipw.Layout(width="fit-content"), + ) + reset_button.on_click(lambda _: self.log_widget.clear_output()) + display( + ipw.VBox( + children=[ + reset_button, + self.log_widget, + ], + ) + ) + # Set up bug report handling (if a URL is provided) if bug_report_url: install_create_github_issue_exception_handler( @@ -52,7 +82,10 @@ def _load_styles(self): def load(self): """Initialize the WizardApp and integrate the app into the main view.""" - self.app = WizardApp(qe_auto_setup=self.qe_auto_setup) + self.app = WizardApp( + qe_auto_setup=self.qe_auto_setup, + log_widget=self.log_widget, + ) self.view.main.children = [self.app] # load a previous calculation if it is provided if self.process: diff --git a/src/aiidalab_qe/app/result/__init__.py b/src/aiidalab_qe/app/result/__init__.py index 0940d78e7..1f474136e 100644 --- a/src/aiidalab_qe/app/result/__init__.py +++ b/src/aiidalab_qe/app/result/__init__.py @@ -23,6 +23,7 @@ class ViewQeAppWorkChainStatusAndResultsStep(QeDependentWizardStep[ResultsStepMo ) def __init__(self, model: ResultsStepModel, **kwargs): + self.log_widget = kwargs.pop("log_widget", None) super().__init__(model=model, **kwargs) self.observe( self._on_previous_step_state_change, @@ -130,6 +131,7 @@ def _post_render(self): self._update_status, self._update_state, ], + log_widget=self.log_widget, ) ipw.dlink( (self._model, "process_uuid"), diff --git a/src/aiidalab_qe/app/wizard_app.py b/src/aiidalab_qe/app/wizard_app.py index 06f29dcaf..93944ec18 100644 --- a/src/aiidalab_qe/app/wizard_app.py +++ b/src/aiidalab_qe/app/wizard_app.py @@ -23,13 +23,15 @@ class WizardApp(ipw.VBox): # The PK or UUID of the work chain node. process = tl.Union([tl.Unicode(), tl.Int()], allow_none=True) - def __init__(self, qe_auto_setup=True): + def __init__(self, qe_auto_setup=True, **kwargs): # Initialize the models self.structure_model = StructureStepModel() self.configure_model = ConfigurationStepModel() self.submit_model = SubmissionStepModel() self.results_model = ResultsStepModel() + log_widget = kwargs.pop("log_widget", None) + # Create the application steps self.structure_step = StructureSelectionStep( model=self.structure_model, @@ -46,6 +48,7 @@ def __init__(self, qe_auto_setup=True): ) self.results_step = ViewQeAppWorkChainStatusAndResultsStep( model=self.results_model, + log_widget=log_widget, ) # Wizard step observations @@ -102,7 +105,8 @@ def __init__(self, qe_auto_setup=True): self._process_loading_message, self._wizard_app_widget, InAppGuide(identifier="post-guide"), - ] + ], + **kwargs, ) self._wizard_app_widget.selected_index = None