diff --git a/aiidalab_ispg/app/steps.py b/aiidalab_ispg/app/steps.py index 8790032..f373d1c 100644 --- a/aiidalab_ispg/app/steps.py +++ b/aiidalab_ispg/app/steps.py @@ -1,8 +1,8 @@ -"""Common Steps for AiiDAlab workflows. +"""Common/Base Steps for AiiDAlab workflows. Code inspired by the QeApp. Authors: - * Daniel Hollas + * Daniel Hollas """ import re @@ -135,7 +135,7 @@ class ViewWorkChainStatusStep(ipw.VBox, WizardAppWidgetStep): process_uuid = traitlets.Unicode(allow_none=True) - def __init__(self, progress_bar=None, children=None, **kwargs): + def __init__(self, progress_bar, children=None, **kwargs): if children is None: children = [] self.process_tree = ISPGProcessNodesTreeWidget() @@ -168,13 +168,26 @@ def __init__(self, progress_bar=None, children=None, **kwargs): ) ipw.dlink((self, "process_uuid"), (self.process_monitor, "value")) - if progress_bar is not None: - workflow_state = ipw.VBox([progress_bar, self.tree_toggle]) - else: - workflow_state = ipw.VBox([self.tree_toggle]) - workflow_state.layout.width = "60%" + self.kill_button = ipw.Button( + description="Kill workflow", + tooltip="Stop the running workflow", + button_style="danger", + icon="times-circle", + disabled=True, + ) + self.kill_button.on_click(self._on_click_kill_button) + + workflow_btns = ipw.HBox([self.tree_toggle, self.kill_button]) + self.tree_toggle.layout.width = "70%" + super().__init__( - children=[workflow_state, self.process_tree, self.node_view, *children], + children=[ + progress_bar, + workflow_btns, + self.process_tree, + self.node_view, + *children, + ], **kwargs, ) @@ -225,6 +238,7 @@ def _observe_process(self, change): self.tree_toggle.disabled = False self._update_step_state() self._update_workflow_state() + self._update_kill_button() def _observe_tree_toggle(self, change): if change["new"] == change["old"]: @@ -242,6 +256,34 @@ def _observe_tree_toggle(self, change): self.process_tree.value = None self.tree_toggle.icon = "folder" + def _update_kill_button(self): + """Update the layout of the kill button. + + Show the button only when the process is running + """ + if self.process_uuid is not None and self.state is self.State.ACTIVE: + self.kill_button.layout.display = "block" + self.kill_button.disabled = False + else: + self.kill_button.layout.display = "none" + self.kill_button.disabled = True + + def _on_click_kill_button(self, _=None): + """Callback for the kill button. + + First kill the process, then update the kill button layout. + """ + from aiida.engine.processes.control import kill_processes + + self.kill_button.disabled = True + + workchain = [load_node(self.process_uuid)] + # TODO: Wait for a bit here + kill_processes(workchain, wait=False) + + # update the kill button layout + self._update_kill_button() + class ViewSpectrumStep(ipw.VBox, WizardAppWidgetStep): """Step for displaying UV/vis spectrum"""