diff --git a/delete.ipynb b/delete.ipynb new file mode 100644 index 000000000..374c73a0f --- /dev/null +++ b/delete.ipynb @@ -0,0 +1,135 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# AiiDAlab QuantumESPRESSO App\n", + "\n", + "Caution! Deleting this job will also remove all associated nodes, including every calculation initiated by this job and their respective results. This action is irreversible.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import urllib.parse as urlparse\n", + "\n", + "import ipywidgets as widgets\n", + "from aiida import load_profile\n", + "from aiida.orm import load_node\n", + "from aiida.tools import delete_nodes\n", + "from IPython.display import Markdown, display\n", + "\n", + "# Load AiiDA profile\n", + "load_profile()\n", + "\n", + "# Parse the primary key from the Jupyter notebook URL\n", + "url = urlparse.urlsplit(jupyter_notebook_url) # noqa F821\n", + "query = urlparse.parse_qs(url.query)\n", + "pk = int(query['pk'][0])\n", + "\n", + "\n", + "def display_node_details(pk):\n", + " try:\n", + " node = load_node(pk)\n", + " print(f\"Node ID: {node.pk}\")\n", + " print(f\"Node Type: {node.process_label}\")\n", + " print(f\"Label: {node.label}\")\n", + " print(f\"Description: {node.description}\")\n", + " print(f\"Creation Time: {node.ctime}\")\n", + " except Exception as e:\n", + " print(f\"Error loading node: {str(e)}\")\n", + " return False\n", + " return True\n", + "\n", + "\n", + "def delete_node(pk, dry_run=True):\n", + " if dry_run:\n", + " _, was_deleted = delete_nodes([pk], dry_run=True)\n", + " if was_deleted:\n", + " print(f'Dry run: Node {pk} can be deleted.')\n", + " return\n", + " \n", + " _, was_deleted = delete_nodes([pk], dry_run=False)\n", + " if was_deleted:\n", + " print(f'Node {pk} deleted successfully.')\n", + "\n", + "\n", + "def confirm_deletion(b):\n", + " if delete_confirmation.value.lower() in ['y', 'yes']:\n", + " delete_node(pk, dry_run=False)\n", + " else:\n", + " print('Deletion aborted.')\n", + "\n", + "\n", + "def find_linked_qeapp_jobs(root_node_pk, process_label='QeAppWorkChain'):\n", + " \"\"\"Query all linked node with process_label = QeAppWorkChain.\"\"\"\n", + " from aiida.orm import Node, QueryBuilder\n", + " from aiida.orm.nodes.process.workflow.workchain import WorkChainNode\n", + " qb = QueryBuilder()\n", + " qb.append(WorkChainNode, filters={'id': root_node_pk}, tag='root')\n", + " qb.append(Node, with_incoming='root', tag='calcjob')\n", + " # There are seems a bug with `with_ancestors` in the QueryBuilder, so we have to use `with_incoming` instead.\n", + " # For the moment, it's safe to use `with_incoming` since we check it very time we delete a QEApp \n", + " qb.append(WorkChainNode, filters={'attributes.process_label': 'QeAppWorkChain'}, with_incoming='calcjob')\n", + " results = qb.all()\n", + " if len(results) == 0:\n", + " return None\n", + " return results\n", + "\n", + "\n", + "if display_node_details(pk):\n", + " linked_qeapp_jobs = find_linked_qeapp_jobs(pk)\n", + " if linked_qeapp_jobs:\n", + " warning_html = f\"\"\"\n", + "
\n", + " Critical: Unable to delete the requested node due to dependencies.\n", + " There are {len(linked_qeapp_jobs)} QEApp jobs linked to this node. Please delete them first:\n", + "