• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stfc / alc-aiidalab-widgets / 28381284739

29 Jun 2026 02:56PM UTC coverage: 81.818% (-3.5%) from 85.34%
28381284739

push

github

web-flow
Node Viewer Map (#16)

* Create a process node view widget that enables editing the node's label and description

* Create a dictionary map for node viewers

* Add the custom structure data view widget to the aiida node view map

* Create a basic SinglefileData node viewer

* Enable the deletion of a process node

* Add a temporary check message when trying to delete a process node

* Make node argument in structure viewer widget optional

* Update structure viewer tests to test for node initialisation

* Create test for MessageBox

* Add basic test for process node viewer widget

54 of 82 new or added lines in 5 files covered. (65.85%)

378 of 462 relevant lines covered (81.82%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

62.22
/src/alc_aiidalab_widgets/widgets/process_node_view.py
1
"""Visualisation widget for an AiiDA process node."""
2

3
from aiida.tools import delete_nodes
1✔
4
from aiidalab_widgets_base.viewers import (
1✔
5
    ProcessNodeViewerWidget as AiiDAlabProcessNodeViewerWidget,
6
)
7
from IPython.display import Javascript, display
1✔
8
from ipywidgets import HTML, Button, Text, Textarea, VBox
1✔
9

10
from alc_aiidalab_widgets.widgets.mesages import MessageBox
1✔
11

12

13
class ProcessNodeViewerWidget(VBox):
1✔
14
    """An extension of the AiiDAlab ProcessNodeViewerWidget."""
15

16
    def __init__(self, process, **kwargs):
1✔
17
        """CustomProcessNodeViewerWidget Constructor."""
18
        super().__init__(**kwargs)
1✔
19
        self.process = process
1✔
20
        self.label_widget = Text(
1✔
21
            value=process.label,
22
            disabled=False,
23
            description="Label: ",
24
            layout={"width": "70%"},
25
        )
26
        self.label_widget.observe(self._update_node_label, "value")
1✔
27
        self.description_widget = Textarea(
1✔
28
            value=process.description,
29
            disabled=False,
30
            description="Description:",
31
            layout={"width": "80%"},
32
        )
33
        self.description_widget.observe(self._update_node_description, "value")
1✔
34
        self.process_view = AiiDAlabProcessNodeViewerWidget(self.process)
1✔
35

36
        self.delete_btn = Button(
1✔
37
            description="Delete Node",
38
            button_style="warning",
39
            tooltip="Delete Process Node From Database",
40
            icon="trash",
41
            layout={"align_self": "flex-end"},
42
        )
43
        self.delete_btn.on_click(self._delete_node)
1✔
44

45
        self.children = [
1✔
46
            self.label_widget,
47
            self.description_widget,
48
            HTML("<hr>"),
49
            self.process_view,
50
            self.delete_btn,
51
        ]
52
        return
1✔
53

54
    def _update_node_label(self, change: dict) -> None:
1✔
55
        """Update the process node's label."""
56
        if change["new"] == change["old"]:
1✔
NEW
57
            return
×
58
        self.process.label = change["new"]
1✔
59
        return
1✔
60

61
    def _update_node_description(self, change: dict) -> None:
1✔
62
        """Update the process node's description."""
63
        if change["new"] == change["old"]:
1✔
NEW
64
            return
×
65
        self.process.description = change["new"]
1✔
66
        return
1✔
67

68
    def _delete_node(self, _) -> None:
1✔
69
        """Delete the current process node from the database."""
NEW
70
        children = list(self.children)
×
NEW
71
        message_box = MessageBox(
×
72
            (
73
                "Are you sure you want to delete this Node, "
74
                "all associated output nodes will also be deleted..."
75
            ),
76
            layout={"margin": "auto"},
77
        )
NEW
78
        children.append(message_box)
×
NEW
79
        self.children = children
×
NEW
80
        message_box.observe(self._accept_node_delete, "state")
×
NEW
81
        self.delete_btn.disabled = True
×
82
        # delete_nodes([self.process.pk], dry_run=False)
83
        # display(Javascript("window.location.reload();"))
NEW
84
        return
×
85

86
    def _accept_node_delete(self, change: dict) -> None:
1✔
NEW
87
        if change["new"]:
×
NEW
88
            delete_nodes([self.process.pk], dry_run=False)
×
NEW
89
            display(Javascript("window.location.reload();"))
×
90
        else:
NEW
91
            children = list(self.children)
×
NEW
92
            children = children[:-1]
×
NEW
93
            self.children = children
×
NEW
94
            self.delete_btn.disabled = False
×
NEW
95
        return
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc